Example #1
0
def saveWFs():
    from ROOT import TChain

    # 1 P3KJR 9472 5254 C1P3D2 610 2115.519087 0.831066 -0.000310 1
    # 1 P3KJR 9544 14210 C1P1D2 582 2083.442207 4.322209 -0.000296 2
    # 1 P3KJR 10614 8717 C1P1D2 582 2167.199298 1.929810 -0.000396 19
    # 1 P3KJR 13345 31547 C1P1D3 580 2013.263961 14.821248 -0.000213 46
    tt = TChain("skimTree")
    tt.Add("%s/latSkimDS%d*.root" % (dsi.latDir, 1))

    chan = 582
    ds = 1
    truncLo, truncHi = 0, 2
    if ds == 6 or ds == 2: truncLo = 4

    # wf 1 - passing DCR
    tCut1 = "trapENFCal > 2000 && trapENFCal < 2200 && channel==%d && avse>-1 && dcr99<0" % chan
    n = tt.Draw("Entry$:Iteration$", tCut1, "goff")
    evt, itr = tt.GetV1(), tt.GetV2()
    evtList = [[int(evt[i]), int(itr[i])] for i in range(n)]
    nEnt = len(set([evt[i] for i in range(n)]))
    passWF = []
    for i, (iE, iH) in enumerate(evtList):
        tt.GetEntry(iE)
        run = tt.run
        hitE = tt.trapENFCal.at(iH)
        dcr99 = tt.dcr99.at(iH)
        wf = tt.MGTWaveforms.at(iH)
        signal = wl.processWaveform(wf, truncLo, truncHi)
        wf1 = signal.GetWaveBLSub()
        ts1 = signal.GetTS()
        passWF.append((ts1, wf1, hitE, dcr99))
        print("%d / %d  Run %d  chan %d  trapENF %.1f" %
              (i + 1, len(evtList), run, chan, hitE))

    # wf 2 - failing DCR
    tCut2 = "trapENFCal > 1500 && channel==%d && dcr99>0.001" % chan
    n = tt.Draw("Entry$:Iteration$", tCut2, "goff")
    evt, itr = tt.GetV1(), tt.GetV2()
    evtList = [[int(evt[i]), int(itr[i])] for i in range(n)]
    nEnt = len(set([evt[i] for i in range(n)]))

    failWF = []
    for i, (iE, iH) in enumerate(evtList):
        tt.GetEntry(iE)
        run = tt.run
        hitE = tt.trapENFCal.at(iH)
        dcr99 = tt.dcr99.at(iH)
        wf = tt.MGTWaveforms.at(iH)
        signal = wl.processWaveform(wf, truncLo, truncHi)
        wf2 = signal.GetWaveBLSub()
        ts2 = signal.GetTS()
        failWF.append((ts2, wf2, hitE, dcr99))
        print("%d / %d  Run %d  chan %d  trapENF %.1f" %
              (i + 1, len(evtList), run, chan, hitE))

    np.savez("../data/dcr-example.npz", passWF, failWF)
Example #2
0
def PlotTemplateWaveforms(waveTree, calDict):
    """ Check the wf's grabbed from an M1 calibration run. """
    # plt.style.use('mjWaveforms')  # see ~/.matplotlib/stylelib
    # optional: redefine calDict with only one or two channels for debugging
    # calDict = {672:18}

    # Make a figure
    fig = plt.figure(figsize=(9, 7), facecolor='w')
    ax = plt.subplot(111)
    ax.set_xlabel("time (ns)")
    ax.set_ylabel("ADC")
    jet = plt.get_cmap('jet')
    cNorm = colors.Normalize(vmin=578, vmax=672)
    scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)

    # Plot multiple waveforms
    for chan in calDict:
        waveTree.GetEntry(calDict[chan])
        waveMGT = waveTree.event.GetWaveform(waveTree.itr)
        signal = wl.processWaveform(waveMGT)
        waveRaw = signal.GetWaveRaw()
        waveOff = signal.GetOffset() / 1e9  # seconds
        waveTS = signal.GetTS()
        colorVal = scalarMap.to_rgba(chan)
        label = ('%d' % chan)
        ax.plot(waveTS, waveRaw, color=colorVal, label=label)

    # make a legend and show the plot.
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles, labels, loc='upper right')
    plt.show()
Example #3
0
    def animate(iList):

        entry = gatTree.GetEntryNumber(iList)
        gatTree.LoadTree(entry)
        gatTree.GetEntry(entry)
        nChans = gatTree.channel.size()
        numPass = gatTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = gatTree.GetV1()
        chanList = list(set(int(chans[n]) for n in range(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in range(nChans)
                   if gatTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:
            wf = gatTree.MGTWaveforms.at(iH)
            iEvent = entry
            run = gatTree.run
            chan = gatTree.channel.at(iH)
            energy = gatTree.trapENFCal.at(iH)
            dcr = gatTree.dcr99.at(iH)
            # fs = gatTree.fitSlo.at(iH)
            # rn = gatTree.riseNoise.at(iH)
            signal = wl.processWaveform(wf)
            waveRaw = signal.GetWaveRaw()
            waveTS = signal.GetTS()

            baseline = np.sum(waveRaw[:50]) / 50

            # fill the figure
            p1.set_ydata(waveRaw)
            p1.set_xdata(waveTS)
            # plt.title("Run %d  Ch %d  Entry %d  trapENFCal %.1f  fitSlo %.2f  riseNoise %.2f" % (run,chan,iList,energy, fs, rn))
            plt.title("Run %d  Ch %d  Entry %d  trapENFCal %.1f  dcr99 %.8f" %
                      (run, chan, iList, energy, dcr))

            # dynamically scale the axes
            xmin, xmax = np.amin(waveTS), np.amax(waveTS)
            # a1.set_xlim([xmin,xmax])
            a1.set_xlim([9000, xmax])
            # if energy > 1000:
            # a1.set_ylim(0,1000)
            # else:
            ymin, ymax = np.amin(waveRaw), np.amax(waveRaw)
            # a1.set_ylim([ymin-abs(0.1*ymin),ymax+abs(0.1*ymax)])
            a1.set_ylim([ymax - abs(0.35 * ymax), ymax + abs(0.2 * ymax)])
            # a1.set_ylim([5000,6000])

            # print(progress)
            # print("%d / %d  Run %d  nCh %d  chan %d  trapE %.1f  samp %d" % (iList,nList,run,nChans,chan,energy,wf.GetLength()))
            if iList % 500 == 0 and iList != 0:
                print("%d / %d entries saved (%.2f %% done)." %
                      (iList, nList, 100 * (float(iList) / nList)))
            return p1,
Example #4
0
def getTrap():

    ds, run, chan = 1, 11085, 580  # C1P1D3
    # trigger eff vals from old study: mu = 1.448, sig = 0.305

    # 2016-9-15-P3LQG_Run60001538 C2P1D3 P42748B
    # ds, run, chan = 4, 60001538, 1110

    from ROOT import GATDataSet
    gds = GATDataSet(run)
    tt = gds.GetGatifiedChain()
    bt = gds.GetBuiltChain()
    tt.AddFriend(bt)

    tCut = "channel==%d" % chan
    n = tt.Draw("Entry$:Iteration$", tCut, "goff")
    evt, itr = tt.GetV1(), tt.GetV2()
    evtList = [[int(evt[i]), int(itr[i])] for i in range(n)]

    trapOutput = []

    pEvt = -1
    for i, (iE, iH) in enumerate(evtList):
        if iE != pEvt:
            tt.GetEntry(iE)
        pEvt = iE

        hitE = tt.trapENFCal.at(iH)
        wf = bt.event.GetWaveform(iH)
        sig = wl.processWaveform(wf)
        waveRaw = sig.GetWaveBLSub()
        waveTS = sig.GetTS()

        # mimic onboard energy trapezoid
        eTrap = wl.trapFilter(waveRaw, 400, 180, 0)
        nPad = len(waveRaw) - len(eTrap)
        eTrap = np.pad(eTrap, (nPad, 0), 'constant')
        eTrapTS = np.arange(0, len(eTrap) * 10., 10)

        # trap timestamps shouldn't change, don't recalculate them
        if i == 0:
            pTS = eTrapTS
        if not np.array_equal(eTrapTS, pTS):
            print("Warning, the timestamps changed.  Uggggg")
            return

        # print(i, iE, iH, hitE)
        trapOutput.append(eTrap)

    # np.savez("../data/trapOutput.npz",trapOutput,eTrapTS) # original ds4 run
    np.savez("../data/trapOutput-2.npz", trapOutput, eTrapTS)  # new ds1 run
Example #5
0
def main(argv):
    """ Interactive-fit or 'rapid'-fit waveforms that pass a given TCut.
        BUG: Doesn't always work with a TChain.  Add input files together
        with hadd and use a single TFile.
    """
    scanSpeed = 0.2
    iList = -1
    opt1 = ""
    intMode, batMode = False, False
    if (len(argv) >= 1): opt1 = argv[0]
    if "-i" in (opt1):
        intMode = True
        print "Interactive mode selected."
    if "-b" in (opt1):
        batMode = True
        print "Batch mode selected.  A new file will be created."

    # Load template waveform (created by gen-template.py)
    npzfile = np.load("./data/genTemplateWF.npz")
    temp, tempTS, tempE, tempST = npzfile['arr_0'] + 1, npzfile[
        'arr_1'], npzfile['arr_2'], npzfile['arr_3'] * 10

    # Set cuts
    # theCut = inputFile.Get("cutUsedHere").GetTitle()
    # DS3 "big DC" cut - PRELIMINARY
    theCut = "trapENFCal > 0.8 && gain==0 && mHClean==1 && isGood && !muVeto && !wfDCBits && !isLNFill1 && !isLNFill2 && trapETailMin < 0 && channel!=596 && channel!=676 && channel!=676 && channel!=612 && channel!=1104 && channel!=1200 && channel!=1334 && channel!=1336 && tOffset < 10 && waveS5/TMath::Power(trapENFCal,1/4) < 1200 && (waveS3-waveS2)/trapENFCal > 100 && (waveS3-waveS2)/trapENFCal < 300 && !(channel==692 && (run==16974 || run==16975 || run==16976 || run==16977 || run==16978 || run==16979)) && butterTime < 11000"
    # theCut += " && trapENFCal > 1.5 && trapENFCal < 2.1"
    # theCut += " && trapENFCal < 20 && trapENFCal > 2 && run > 17480"
    # theCut += " && kvorrT/trapENFCal > 2.2 && trapENFCal > 2 && trapENFCal < 10"

    # Set file I/O and create entry lists
    startT = time.clock()
    inFile = "~/project/wavelet-skim/waveletSkimDS3_1.root"
    # inFile = "~/project/wavelet-skim/hadd/waveletSkimDS3.root"
    outFile = "~/project/fit-skim/fitSkimDS3_1.root"
    inputFile = TFile(inFile)
    waveTree = inputFile.Get("skimTree")
    print "Found", waveTree.GetEntries(
    ), "input entries.  Using cut:\n", theCut, "\n"
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Found", nList, "entries passing cuts."
    stopT = time.clock()
    print "Data loading time (s): ", (stopT - startT)

    # In batch mode ONLY, create an output file+tree & append new branches
    outputFile = TFile()
    outTree = TTree()
    if batMode:
        outputFile = TFile(outFile, "RECREATE")
        print "Attempting tree copy to", outFile
        outTree = waveTree.CopyTree("")
        outTree.Write()
        print "Wrote", outTree.GetEntries(), "entries."
        cutUsed = TNamed("cutUsedHere", theCut)
        cutUsed.Write()
    fitStart = std.vector("double")()
    fitE = std.vector("double")()
    fitSlo = std.vector("double")()
    fitStartSD = std.vector("double")()
    fitESD = std.vector("double")()
    fitSloSD = std.vector("double")()
    fitChi2NDF = std.vector("double")()
    fitLnLike = std.vector("double")()
    tExp1 = std.vector("double")()
    tExp2 = std.vector("double")()
    tPol0 = std.vector("double")()
    tPol1 = std.vector("double")()
    tPol2 = std.vector("double")()
    tPol3 = std.vector("double")()
    baseAvg = std.vector("double")()
    baseNoise = std.vector("double")()
    bFitStart = outTree.Branch("fitStart", fitStart)
    bFitE = outTree.Branch("fitE", fitE)
    bFitSlo = outTree.Branch("fitSlo", fitSlo)
    bFitStart_sd = outTree.Branch("fitStartSD", fitStartSD)
    bFitE_sd = outTree.Branch("fitESD", fitESD)
    bFitSlo_sd = outTree.Branch("fitSloSD", fitSloSD)
    bFitChi2NDF = outTree.Branch("fitChi2NDF", fitChi2NDF)
    bFitLnLike = outTree.Branch("fitLnLike", fitLnLike)
    bTExp1 = outTree.Branch("tExp1", tExp1)
    bTExp2 = outTree.Branch("tExp2", tExp2)
    bTPol0 = outTree.Branch("tPol0", tPol0)
    bTPol1 = outTree.Branch("tPol1", tPol1)
    bTPol2 = outTree.Branch("tPol2", tPol2)
    bTPol3 = outTree.Branch("tPol3", tPol3)
    bBaseAvg = outTree.Branch("baseAvg", baseAvg)
    bBaseNoise = outTree.Branch("baseNoise", baseNoise)

    # Make a figure
    # with PdfPages('multipage_pdf.pdf') as pdf:
    fig = plt.figure(figsize=(11, 7), facecolor='w')
    p1 = plt.subplot2grid((6, 7), (0, 0), colspan=4, rowspan=2)  # original
    p2 = plt.subplot2grid((6, 7), (2, 0), colspan=4, rowspan=3)  # rising edge
    p3 = plt.subplot2grid((6, 7), (5, 0), colspan=4, rowspan=1)  # residual
    p4 = plt.subplot2grid((6, 7), (0, 4), colspan=3, rowspan=2)  # trace 1
    p5 = plt.subplot2grid((6, 7), (2, 4), colspan=3, rowspan=2,
                          sharex=p4)  # trace 2
    p6 = plt.subplot2grid((6, 7), (4, 4), colspan=3, rowspan=2,
                          sharex=p4)  # trace 3
    if not batMode: plt.show(block=False)

    # Setup multiprocessing
    manager = Manager()
    returnDict = manager.dict()

    # Loop over events
    while (True):
        saveMe = False
        iList += 1
        if intMode == True and iList != 0:
            value = raw_input()
            if value == 'q': break
            if value == 's': saveMe = True
            if value == 'p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value)  # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        numPass = waveTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))

        fitStart.assign(nChans, -9999)
        fitE.assign(nChans, -9999)
        fitSlo.assign(nChans, -9999)
        fitStartSD.assign(nChans, -9999)
        fitESD.assign(nChans, -9999)
        fitSloSD.assign(nChans, -9999)
        fitChi2NDF.assign(nChans, -9999)
        fitLnLike.assign(nChans, -9999)
        tExp1.assign(nChans, -9999)
        tExp2.assign(nChans, -9999)
        tPol0.assign(nChans, -9999)
        tPol1.assign(nChans, -9999)
        tPol2.assign(nChans, -9999)
        tPol3.assign(nChans, -9999)
        baseAvg.assign(nChans, -9999)
        baseNoise.assign(nChans, -9999)

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans)
                   if waveTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:

            # Load waveform for this hit
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            dataE = waveTree.trapENFCal.at(iH)
            dataST = waveTree.butterTime.at(iH)  # replace with blrwfFMR50?
            toe = waveTree.kvorrT.at(iH) / dataE
            print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f  t/e %.1f" % (
                iList, nList, run, nChans, chan, dataE, toe)
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH),
                                        opt='full')
            waveBLSub = signal.GetWaveBLSub()
            waveFilt = signal.GetWaveFilt()
            waveTS = signal.GetTS()
            dataBaseline, dataNoise = signal.GetBaseNoise()

            # Denoise the data waveform (take only lowest-frequency components)
            wp = pywt.WaveletPacket(data=waveBLSub,
                                    wavelet='haar',
                                    mode='symmetric',
                                    maxlevel=3)
            new_wp = pywt.WaveletPacket(data=None,
                                        wavelet='haar',
                                        mode='symmetric')
            new_wp['aaa'] = wp['aaa'].data
            waveDenoised = new_wp.reconstruct(update=False)

            # Window the fit around rising edge - start time calculator method
            loWin, hiWin = dataST - 1000, dataST + 4000  # ns
            if loWin < waveTS[0] or hiWin > waveTS[-1]:
                print "Window out of range!  dataST: %.1f  loWin %.1f  hiWin %.1f" % (
                    dataST, loWin, hiWin)
            idx = np.where((waveTS >= loWin) & (waveTS <= hiWin))
            data = waveBLSub[idx]
            # data = waveDenoised[idx]
            dataTS = waveTS[idx]

            # Pack into lists
            rawList = [waveBLSub, waveTS, dataE, dataST]
            dataList = [data, dataTS, dataE, dataST, loWin, hiWin]
            tempList = [temp, tempTS, tempE, tempST]

            # Optionally save something to a file
            if saveMe:
                print "Saved entry", iList, iH
                np.savez("./data/tailSlopeInputs.npz", rawList, tempList)

            # Recreate the guess and the guess's rising edge
            guessFull, guessFullTS = wm.MakeModel(dataList,
                                                  tempList,
                                                  [dataST, dataE, 1.],
                                                  opt="full")
            guess, guessTS = wm.MakeModel(dataList,
                                          tempList, [dataST, dataE, 1.],
                                          opt="!fancy")

            # Make an "almost complete" guess - no MCMC
            # st, en, slo = dataST-100, dataE, 5
            # InterpFn = interpolate.interp1d(tempTS, temp, kind="linear", copy="False", assume_sorted="True")
            # model, modelTS = wm.MakeModel(dataList, tempList, [st,en,slo], fn=InterpFn)

            # Fit with MCMC and get best-fit parameters
            numSteps, burnIn = 3000, 1800  # default: 10000, 5000.  fast: 3000, 1800  long test: 20000,10000
            wfModel = wm.TemplateModel(dataList, dataNoise, tempList)
            p = Process(target=RunMCMC,
                        args=(wfModel, numSteps, burnIn, returnDict))
            p.start()
            p.join()
            startTimeTr = returnDict["startTimeTr"]
            energyTr = returnDict["energyTr"]
            slownessTr = returnDict["slownessTr"]
            st = np.median(startTimeTr[burnIn:])
            en = np.median(energyTr[burnIn:])
            slo = np.median(slownessTr[burnIn:])
            InterpFn = interpolate.interp1d(tempTS,
                                            temp,
                                            kind="linear",
                                            copy="False",
                                            assume_sorted="True")
            model, modelTS = wm.MakeModel(dataList,
                                          tempList, [st, en, slo],
                                          fn=InterpFn)

            # Save some extra parameters for the ROOT output
            # Calculate residual, Chi2/NDF, likelihood, etc.
            st_std = np.std(startTimeTr[burnIn:])
            en_std = np.std(energyTr[burnIn:])
            slo_std = np.std(slownessTr[burnIn:])
            residual = model - data
            frac = (np.power(data - model, 2)) / np.abs(model)
            chi2NDF = np.sum(frac) / len(model)
            inv_sigma2 = 1.0 / (dataNoise**2)
            lnLike = -0.5 * (np.sum((data - model)**2 * inv_sigma2 -
                                    np.log(inv_sigma2)))

            # ** Do a separate & simple fit of the tail slope **
            # TODO: Add this to process-waveforms.py
            idxMax = np.where(
                guessFull == guessFull.max())  # returns an array/tuple
            idxMax = idxMax[0][0]  # "cast" to int
            tail, tailTS = waveDenoised[idxMax:], waveTS[idxMax:]
            popt, _ = curve_fit(wl.tailModelPol, tailTS, tail)  # poly fit
            pol0, pol1, pol2, pol3 = popt[0], popt[1], popt[2], popt[3]
            a, b = dataE, 72000
            popt2, _ = curve_fit(wl.tailModelExp, tailTS, tail,
                                 p0=[a, b])  # expo fit
            e1, e2 = popt2[0], popt2[1]

            # Assign values to output vectors and fill branches
            fitStart[iH], fitStartSD[iH] = st, st_std
            fitE[iH], fitESD[iH] = en, en_std
            fitSlo[iH], fitSloSD[iH] = slo, slo_std
            fitChi2NDF[iH] = chi2NDF
            fitLnLike[iH] = lnLike
            tExp1[iH], tExp2[iH] = e1, e2
            tPol0[iH], tPol1[iH], tPol2[iH], tPol3[iH] = pol0, pol1, pol2, pol3
            baseAvg[iH] = dataBaseline
            baseNoise[iH] = dataNoise
            if batMode:
                bFitStart.Fill()
                bFitE.Fill()
                bFitSlo.Fill()
                bFitStart_sd.Fill()
                bFitE_sd.Fill()
                bFitSlo_sd.Fill()
                bFitChi2NDF.Fill()
                bFitLnLike.Fill()
                bTExp1.Fill()
                bTExp2.Fill()
                bTPol0.Fill()
                bTPol1.Fill()
                bTPol2.Fill()
                bTPol3.Fill()
                bBaseAvg.Fill()
                bBaseNoise.Fill()
                if iList % 5000 == 0:
                    outTree.Write("", TObject.kOverwrite)
                    print "%d / %d entries saved (%.2f %% done)." % (
                        iList, nList, 100 * (float(iList) / nList))

            # If not in batch mode, fill the figure
            if batMode: continue
            p1.cla()
            p1.set_ylabel("ADC")
            p1.set_title(
                "Run %d  Channel %d  Entry %d\ntrapENFCal %.1f  T/E %.1f  ST %.1f"
                % (run, chan, iList, dataE, toe, dataST))
            p1.plot(waveTS, waveBLSub, color='blue')
            p1.plot(waveTS, waveDenoised, color='red', alpha=0.8)
            p1.plot(guessFullTS, guessFull, color='orange', linewidth=2)
            p1.axvline(x=dataST, color='green', linewidth=2)
            p1.axvline(x=loWin, color='black')
            p1.axvline(x=hiWin, color='black')
            p1.plot(tailTS,
                    wl.tailModelPol(tailTS, *popt),
                    color='cyan',
                    linewidth=1)  # tail poly fit
            p1.plot(tailTS,
                    wl.tailModelExp(tailTS, *popt2),
                    color='cyan',
                    linewidth=1)  # tail expo fit

            p2.cla()
            p2.plot(dataTS, data, color='blue', label='Data')
            p2.plot(guessTS, guess, color='orange', label='Guess')
            # special: plot the values of the trace after burn-in
            # to see how the model is covering the "money-zone"/rising edge after it's converged.
            # for i in range(burnIn,numSteps):
            # st_tr, en_tr, slo_tr = M.trace('startTime')[i], M.trace('energy')[i], M.trace('slowness')[i]
            # trace, traceTS = wm.MakeModel(dataList, tempList, [st_tr,en_tr,slo_tr], fn=InterpFn)
            # p2.plot(traceTS, trace, color='red',alpha=0.1,linewidth=2)
            p2.plot(modelTS,
                    model,
                    color='red',
                    linewidth=3,
                    alpha=0.7,
                    label='Best Fit')
            p2.legend(loc=4)

            p3.cla()
            p3.set_xlabel("Time [ns]", x=0.95, ha='right')
            p3.set_ylabel("Residual [ADC]")
            p3.plot(modelTS, residual, color='red')
            p3.axhline(y=0, color='blue', alpha=0.3)
            p3.axhline(y=dataNoise, color='blue', alpha=0.3)
            p3.axhline(y=-1.0 * dataNoise, color='blue', alpha=0.3)

            p4.cla()
            minST = tempST - tempTS[-1] + hiWin
            maxST = tempST - tempTS[0] + loWin
            p4.set_title(
                "startTime %.1f  Energy %.2f\nSlow %.1f  chi2/ndf %.1f  Min %d  Max %d"
                % (st, en, slo, chi2NDF, minST, maxST))
            p4.plot(startTimeTr[:])
            p4.set_ylabel('startTime')
            p4.axvline(x=burnIn, color='red', alpha=0.5)

            p5.cla()
            p5.plot(energyTr[:])
            p5.set_ylabel('energy')
            p5.axvline(x=burnIn, color='red', alpha=0.5)

            p6.cla()
            p6.plot(slownessTr[:])
            p6.set_ylabel('slowness')
            p6.axvline(x=burnIn, color='red', alpha=0.5)

            plt.tight_layout()
            plt.subplots_adjust(hspace=0.35)
            plt.pause(scanSpeed)
            # pdf.savefig()

    # End loop over events
    if batMode:
        outTree.Write("", TObject.kOverwrite)
        print "Wrote", outTree.GetBranch(
            "channel").GetEntries(), "entries in the copied tree,"
        print "and wrote", bFitStart.GetEntries(
        ), "entries in the new branches."
Example #6
0
def main(argv):
    # gROOT.ProcessLine("gErrorIgnoreLevel = 3001;") # suppress ROOT error messages
    startT = time.clock()
    print "Started:", time.strftime('%X %x %Z')
    intMode, batMode, rangeMode, fileMode, dsNum, subNum, runNum = False, False, False, False, -1, -1, -1
    for i, opt in enumerate(argv):
        if opt == "-i":
            intMode = True
            print "Interactive mode selected. Use \"p\" for previous and \"q\" to exit."
        if opt == "-r":
            rangeMode = True
            dsNum, subNum = int(argv[i + 1]), int(argv[i + 2])
            print "Scanning DS-%d range %d" % (dsNum, subNum)
        if opt == "-f":
            fileMode = True
            dsNum, runNum = int(argv[i + 1]), int(argv[i + 2])
        if opt == "-b":
            batMode = True
            import matplotlib
            if os.environ.get('DISPLAY', '') == '':
                print('No display found. Using non-interactive Agg backend')
                matplotlib.use('Agg')
            print "Batch mode selected.  A new file will be created."
    import matplotlib.pyplot as plt

    # Set file I/O and cuts
    inFile = "./data/waveSkimDS4_test.root"
    outFile = "./data/waveletSkimDS4_test.root"
    if (rangeMode):
        inFile = "~/project/v2-waveskim/waveSkimDS%d_%d.root" % (dsNum, subNum)
        outFile = "~/project/v2-processwfs/waveletSkimDS%d_%d.root" % (dsNum,
                                                                       subNum)
    if (fileMode):
        # inFile = "~/project/cal-wave-skim/waveSkimDS%d_run%d.root" % (dsNum,runNum)
        # outFile = "~/project/cal-wavelet-skim/waveletSkimDS%d_run%d.root" % (dsNum,runNum)
        inFile = "./waveSkimDS%d_run%d.root" % (dsNum, runNum)
        outFile = "./waveletSkimDS%d_run%d.root" % (dsNum, runNum)

    inputFile = TFile(inFile)
    waveTree = inputFile.Get("skimTree")
    print "Found", waveTree.GetEntries(), "input entries."

    theCut = inputFile.Get("theCut").GetTitle()
    # theCut = "trapENFCal > 0.8 && gain==0 && mHClean==1 && isGood && !muVeto && !isLNFill1 && !isLNFill2 && P!=0 && D!=0 && trapETailMin<0"
    # theCut += " && Entry$ < 2000"
    # theCut += " && trapENFCal > 20"
    print "Using cut:\n", theCut, "\n"

    print "Attempting entrylist draw ..."
    waveTree.Draw(">>elist", theCut, "GOFF entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Found", nList, "entries passing cuts."

    # In batch mode ONLY, create an output file+tree & append new branches
    outputFile = TFile()
    outTree = TTree()
    if (batMode == True):
        outputFile = TFile(outFile, "RECREATE")
        print "Attempting tree copy to", outFile
        outTree = waveTree.CopyTree("")
        outTree.Write()
        print "Wrote", outTree.GetEntries(), "entries."
        cutUsed = TNamed("cutUsedHere", theCut)
        cutUsed.Write()

    waveS0 = std.vector("double")()
    waveS1 = std.vector("double")()
    waveS2 = std.vector("double")()
    waveS3 = std.vector("double")()
    waveS4 = std.vector("double")()
    waveS5 = std.vector("double")()
    wpar4 = std.vector("double")()
    waveEnt = std.vector("double")()
    butterMax = std.vector("double")()
    butterTime = std.vector("double")()
    tOffset = std.vector("double")()
    lastZeroTime = std.vector("double")()
    pol0 = std.vector("double")()
    pol1 = std.vector("double")()
    pol2 = std.vector("double")()
    pol3 = std.vector("double")()
    exp0 = std.vector("double")()
    exp1 = std.vector("double")()
    rt10 = std.vector("double")()
    rt20 = std.vector("double")()
    rt50 = std.vector("double")()
    rt90 = std.vector("double")()

    bWaveS0 = outTree.Branch("waveS0", waveS0)
    bWaveS1 = outTree.Branch("waveS1", waveS1)
    bWaveS2 = outTree.Branch("waveS2", waveS2)
    bWaveS3 = outTree.Branch("waveS3", waveS3)
    bWaveS4 = outTree.Branch("waveS4", waveS4)
    bWaveS5 = outTree.Branch("waveS5", waveS5)
    bWPar4 = outTree.Branch("wpar4", wpar4)
    bWaveEnt = outTree.Branch("waveEnt", waveEnt)
    bButterMax = outTree.Branch("butterMax", butterMax)
    bButterTime = outTree.Branch("butterTime", butterTime)
    bTOffset = outTree.Branch("tOffset", tOffset)
    bLastZeroTime = outTree.Branch("lastZeroTime", lastZeroTime)
    bPol0 = outTree.Branch("pol0", pol0)
    bPol1 = outTree.Branch("pol1", pol1)
    bPol2 = outTree.Branch("pol2", pol2)
    bPol3 = outTree.Branch("pol3", pol3)
    bExp0 = outTree.Branch("exp0", exp0)
    bExp1 = outTree.Branch("exp1", exp1)
    bRt10 = outTree.Branch("rt10", rt10)
    bRt20 = outTree.Branch("rt20", rt20)
    bRt50 = outTree.Branch("rt50", rt50)
    bRt90 = outTree.Branch("rt90", rt90)

    # Make a figure
    fig = plt.figure(figsize=(7, 7), facecolor='w')
    p1 = plt.subplot(211)
    p2 = plt.subplot(212)
    if not batMode: plt.show(block=False)

    # Begin loop over events
    iList = -1
    while True:
        iList += 1
        if intMode == True and iList != 0:
            value = raw_input()
            if value == 'q': break  # quit
            if value == 'p': iList -= 2  # go to previous
            if (value.isdigit()):
                iList = int(value)  # go to entry number
        elif intMode == False and batMode == False:
            plt.pause(0.001)  # rapid-draw mode
        if iList >= nList: break  # bail out, goose!

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        waveS1.assign(nChans, -999)
        waveS0.assign(nChans, -999)
        waveS1.assign(nChans, -999)
        waveS2.assign(nChans, -999)
        waveS3.assign(nChans, -999)
        waveS4.assign(nChans, -999)
        waveS5.assign(nChans, -999)
        wpar4.assign(nChans, -999)
        waveEnt.assign(nChans, -999)
        butterMax.assign(nChans, -999)
        butterTime.assign(nChans, -999)
        tOffset.assign(nChans, -999)
        lastZeroTime.assign(nChans, -999)
        pol0.assign(nChans, -999)
        pol1.assign(nChans, -999)
        pol2.assign(nChans, -999)
        pol3.assign(nChans, -999)
        exp0.assign(nChans, -999)
        exp1.assign(nChans, -999)
        rt10.assign(nChans, -999)
        rt20.assign(nChans, -999)
        rt50.assign(nChans, -999)
        rt90.assign(nChans, -999)

        # Loop over hits passing cuts
        numPass = waveTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))
        hitList = (iH for iH in xrange(nChans)
                   if waveTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:
            run = waveTree.run
            iEvent = waveTree.iEvent
            chan = waveTree.channel.at(iH)
            energy = waveTree.trapENFCal.at(iH)
            wf = waveTree.MGTWaveforms.at(iH)
            startTime = waveTree.triggerTrapt0.at(iH)
            blrwfFMR50 = waveTree.blrwfFMR50.at(iH)

            if wf.GetID() != chan:
                print "Warning!!  Vector matching failed!  iList %d  run %d  iEvent %d" % (
                    iList, run, iEvent)
                break

            signal = wl.processWaveform(wf, opt='full')
            waveBLSub = signal.GetWaveBLSub()
            waveFilt = signal.GetWaveFilt()
            waveTS = signal.GetTS()
            waveletYOrig, waveletYTrans = signal.GetWavelet()

            # waveFTX, waveFTY, waveFTPow = signal.GetFourier()
            # waveTrap = signal.GetTrapezoid()
            # waveTrapF = signal.GetFiltTrapezoid()
            # waveTrapX = np.linspace(0, len(waveTrap), num=len(waveTrap))
            # _,waveletFilt = wl.waveletTransform(waveFilt,level=3)  # testing other levels on the filtered WF

            # Wavelet cut parameters
            waveS0[iH] = np.sum(waveletYTrans[0:1, 1:-1])
            waveS1[iH] = np.sum(waveletYTrans[0:1, 1:33])
            waveS2[iH] = np.sum(waveletYTrans[0:1, 33:65])
            waveS3[iH] = np.sum(waveletYTrans[0:1, 65:97])
            waveS4[iH] = np.sum(waveletYTrans[0:1, 97:-1])
            waveS5[iH] = np.sum(waveletYTrans[2:-1, 1:-1])
            wpar4[iH] = np.amax(waveletYTrans[0:1, 1:-1])

            # Waveform entropy parameters
            d1 = 2. * np.multiply(
                waveletYTrans[0:1, 1:65],
                np.log(waveletYTrans[0:1, 1:65] / waveS0[iH] / 2.0))
            d2 = np.multiply(waveletYTrans[0:1, 65:-1],
                             np.log(waveletYTrans[0:1, 65:-1] / waveS0[iH]))
            waveEnt[iH] = np.abs(np.sum(d1)) + np.abs(np.sum(d2))

            # Smoothed derivative params
            waveFiltDeriv = wl.wfDerivative(waveFilt)
            butterMax[iH] = np.amax(waveFiltDeriv)
            butterTime[iH] = np.argmax(
                waveFiltDeriv[100:]) * 10 + signal.GetOffset() + 1000
            tOffset[iH] = signal.GetOffset()
            # print "max %.3f  ts %.0f ns  offset %.0f ns" % (butterMax[iH], butterTime[iH], tOffset[iH])

            # Make a super denoised waveform
            wp = pywt.WaveletPacket(data=waveBLSub,
                                    wavelet='haar',
                                    mode='symmetric',
                                    maxlevel=3)
            new_wp = pywt.WaveletPacket(data=None,
                                        wavelet='haar',
                                        mode='symmetric')
            new_wp['aaa'] = wp['aaa'].data
            superDenoisedWF = new_wp.reconstruct(update=False)
            mgtSDWF = wl.MGTWFFromNpArray(superDenoisedWF)

            # Try to get start time by finding the super denoised last zero crossing
            lastZero = 0
            zeros = np.asarray(np.where(superDenoisedWF < 0.1))
            if (zeros.size > 0): lastZero = zeros[0, -1]
            lastZeroTime[iH] = waveTS[lastZero]

            # Time point calculator
            timePointCalc = MGWFTimePointCalculator()
            timePointCalc.AddPoint(.1)
            timePointCalc.AddPoint(.2)
            timePointCalc.AddPoint(.5)
            timePointCalc.AddPoint(.9)
            timePointCalc.FindTimePoints(mgtSDWF)
            rt10[iH] = timePointCalc.GetFromStartRiseTime(0) * 10
            rt20[iH] = timePointCalc.GetFromStartRiseTime(1) * 10
            rt50[iH] = timePointCalc.GetFromStartRiseTime(2) * 10
            rt90[iH] = timePointCalc.GetFromStartRiseTime(3) * 10
            # print "lastZero %.2f  startTime %.2f  10 %.2f  20 %.2f  50 %.2f  90 %.2f" % (lastZeroTime[iH], startTime,rt10, rt20, rt50, rt90)

            # Fit tail slope (2 methods).  Guard against fit fails
            idxMax = np.where(waveTS > rt90[iH])  # returns an array/tuple
            idxMax = idxMax[0][0]  # "cast" to int
            tail, tailTS = waveBLSub[idxMax:], waveTS[idxMax:]
            try:
                popt1, _ = curve_fit(wl.tailModelPol, tailTS, tail)
                pol0[iH], pol1[iH], pol2[iH], pol3[iH] = popt1[0], popt1[
                    1], popt1[2], popt1[3]
            except:
                pass
            try:
                popt2, _ = curve_fit(wl.tailModelExp,
                                     tailTS,
                                     tail,
                                     p0=[energy, 72000])
                exp0[iH], exp1[iH] = popt2[0], popt2[1]
            except:
                # print "curve_fit tailModelExp failed, run %i  event %i  channel %i" % (run, iList, chan)
                pass

            # Make a plot
            if not batMode:
                print "i %d  run %d  iEvent(i) %d  iH(j+1) %d/%d  chan %d  energy %.2f  bt %.2f" % (
                    iList, run, iEvent, iH + 1, nChans, chan, energy,
                    butterTime[iH])

                # Waveform plot
                p1.cla()
                p1.plot(waveTS, waveBLSub, color='blue')
                p1.plot(waveTS, superDenoisedWF, color='red')
                p1.plot(tailTS, wl.tailModelPol(tailTS, *popt1), color='cyan')
                p1.plot(tailTS,
                        wl.tailModelExp(tailTS, *popt2),
                        color='orange')
                p1.set_xlabel("Time (ns)")
                p1.set_ylabel("ADC")
                p1.set_title(
                    "Run %d  Ch %d  Energy %.2f  \n S5 %.2f  (S3-S2)/E %.2f  (S3-S4)/E %.2f"
                    % (run, chan, energy, waveS5[iH],
                       ((waveS3[iH] - waveS2[iH]) / energy),
                       ((waveS3[iH] - waveS4[iH]) / energy)))

                # Wavelet plot
                p2.cla()
                p2.imshow(waveletYTrans,
                          interpolation='nearest',
                          aspect="auto",
                          origin="lower",
                          extent=[0, 1, 0, len(waveletYTrans)],
                          cmap='jet')

                plt.tight_layout()
                plt.subplots_adjust(hspace=.2, top=0.92)
                plt.pause(0.00001)

        # End loop over hits
        if (batMode == True):
            bWaveS0.Fill()
            bWaveS1.Fill()
            bWaveS2.Fill()
            bWaveS3.Fill()
            bWaveS4.Fill()
            bWaveS5.Fill()
            bWPar4.Fill()
            bWaveEnt.Fill()
            bButterMax.Fill()
            bButterTime.Fill()
            bTOffset.Fill()
            bLastZeroTime.Fill()
            bPol0.Fill()
            bPol1.Fill()
            bPol2.Fill()
            bPol3.Fill()
            bExp0.Fill()
            bExp1.Fill()
            bRt10.Fill()
            bRt20.Fill()
            bRt50.Fill()
            bRt90.Fill()
            if iList % 5000 == 0:
                outTree.Write("", TObject.kOverwrite)
                print "%d / %d entries saved (%.2f %% done)." % (
                    iList, nList, 100 * (float(iList) / nList))

    # End loop over events
    if (batMode == True):
        outTree.Write("", TObject.kOverwrite)
        print "Wrote", outTree.GetBranch(
            "channel").GetEntries(), "entries in the copied tree,"
        print "and wrote", bWaveS0.GetEntries(), "entries in the new branches."

    stopT = time.clock()
    print "Process time (min): ", (stopT - startT) / 60
Example #7
0
def main(argv):
    scanSpeed = 0.0001
    opt1, opt2 = "", ""
    intMode, printWF = False, False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print "Interactive mode selected."
    if "-s" in (opt1, opt2):
        printWF = True
        print "Saving WF plots to current directory."

    # Set input file
    inputFile = TFile("~/project/match-skim/waveletSkimDS5_run23920.root")
    waveTree = inputFile.Get("skimTree")

    # Set cut
    theCut = inputFile.Get("cutUsedHere").GetTitle()
    theCut += " && waveS5/trapENFCal < 1200 && trapENFCal > 2 && trapENFCal < 5"
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Using cut:\n", theCut, "\n"
    print "Found", nList, "entries passing cuts."

    # Make a figure
    fig = plt.figure(figsize=(8, 7), facecolor='w')
    p1 = plt.subplot(211)
    p2 = plt.subplot(212)
    plt.show(block=False)

    # Make a huge floating template waveform
    samp, r, z, tempE, tempStart, smooth = 5000, 0, 15, 10, 2500, 100
    tempOrig, tempOrigTS = wl.MakeSiggenWaveform(samp, r, z, tempE, tempStart,
                                                 smooth)

    # Loop over events
    iList = -1
    while (True):
        iList += 1
        if intMode == True and iList != 0:
            value = raw_input()
            if value == 'q': break
            if value == 'p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value)  # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        nWaves = waveTree.MGTWaveforms.size()
        numPass = waveTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans)
                   if waveTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:

            # Load waveform data
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            dataE = waveTree.trapENFCal.at(iH)
            dataENM = waveTree.trapENM.at(iH)
            dataMaxTime = waveTree.trapENMSample.at(iH) * 10. - 4000
            # dataMaxTime = waveTree.blrwfFMR50.at(iH)
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH))
            data = signal.GetWaveBLSub()
            dataTS = signal.GetTS()
            print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f" % (
                iList, nList, run, nChans, chan, dataE)

            # Draw a trapezoid filter, append with 1000 samples of zeros
            # trap = np.zeros(1000)
            # trap = np.append(trap,wl.trapezoidalFilter(data))

            # 1. Signal-template convolution. Time domain, technically not quite a full matched filter?
            temp, tempTS = flipAndAlign(tempOrig, tempOrigTS, dataTS,
                                        dataMaxTime, dataENM, tempE)
            smf = gaussian_filter(temp * data, sigma=float(10))

            # 2. crazy stuff that doesn't work
            deriv = wl.wfDerivative(data)
            wp = pywt.WaveletPacket(data=deriv,
                                    wavelet='haar',
                                    mode='symmetric',
                                    maxlevel=3)
            new_wp = pywt.WaveletPacket(data=None,
                                        wavelet='haar',
                                        mode='symmetric')
            new_wp['aaa'] = wp['aaa'].data
            denoised = new_wp.reconstruct(update=False)

            # 3. LIGO-inspired matched filter

            # cmap = cm.get_cmap('Spectral') # then in plot: color=cmap(fraction)
            p1.cla()
            p1.set_ylabel("ADC")
            p1.plot(dataTS, data, color='blue')
            p1.plot(tempTS, temp, color='red')
            # p1.plot(tempTS,trap,color='green')
            p1.plot(tempTS, smf, color='red')

            p2.cla()
            p2.plot(dataTS, denoised, color='blue')

            plt.pause(scanSpeed)
Example #8
0
def main(argv):
    """ Interactive-fit or 'rapid'-fit waveforms that pass a given TCut.
        BUG: Doesn't always work with a TChain.  Add input files together
        with hadd and use a single TFile.
    """
    scanSpeed = 1.
    iList = -1
    opt1 = ""
    intMode = False
    if (len(argv) >= 1): opt1 = argv[0]
    if "-i" in (opt1): intMode = True

    # Set input data and cuts
    inputFile = TFile(
        "~/project/match-skim/waveletSkimDS5_run23920.root")  # calibration
    # inputFile = TFile("~/project/v2-processwfs/waveletSkimDS5_90.root") # noisy BG
    waveTree = inputFile.Get("skimTree")
    theCut = inputFile.Get("cutUsedHere").GetTitle()
    theCut += " && waveS5/trapENFCal < 1200 && trapENFCal > 1.5 && trapENFCal < 3"

    # Print cut and events passing cut
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Using cut:\n", theCut, "\n"
    print "Found", waveTree.GetEntries(), "input entries."
    print "Found", nList, "entries passing cuts."

    # Make a figure
    fig = plt.figure(figsize=(15, 10), facecolor='w')
    p1 = plt.subplot2grid((6, 7), (0, 0), colspan=4, rowspan=2)  # original
    p2 = plt.subplot2grid((6, 7), (2, 0), colspan=4, rowspan=3)  # rising edge
    p3 = plt.subplot2grid((6, 7), (5, 0), colspan=4, rowspan=1)  # residual
    p4 = plt.subplot2grid((6, 7), (0, 4), colspan=3, rowspan=2)  # trace 1
    p5 = plt.subplot2grid((6, 7), (2, 4), colspan=3, rowspan=2)  # trace 2
    p6 = plt.subplot2grid((6, 7), (4, 4), colspan=3, rowspan=2)  # trace 3
    plt.show(block=False)

    # Make template(s)
    # npzfile = np.load("./data/genTemplateWF.npz") # gen-template.py
    # temp, tempTS, tempE, tempST = npzfile['arr_0']+1, npzfile['arr_1'], npzfile['arr_2'], npzfile['arr_3']*10

    samp, r, z, tempE, tempST, smooth = 2016, 0, 15, 3938, 1000, 100  # gen-template.py
    # samp, r, z, tempE, tempST, smooth = 5000, 0, 15, 10, 2500, 100  # huge template
    # samp, r, z, tempE, tempST, smooth = 2016, 0, 15, 10, 1000, 100 # regular size template
    # samp, r, z, tempE, tempST, smooth = 2016, 30, 30, 10, 1000, 100 # regular size temp, slower rise
    # samp, r, z, tempE, tempST, smooth = 500, 0, 15, 10, 100, 100  # small template
    temp, tempTS = wl.MakeSiggenWaveform(samp, r, z, tempE, tempST, smooth)
    tempST = tempST * 10  # convert to ns

    # Loop over events
    while True:
        saveMe = False
        iList += 1
        if intMode == True and iList != 0:
            value = raw_input()
            if value == 'q': break
            if value == 's': saveMe = True
            if value == 'p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value)  # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        numPass = waveTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans)
                   if waveTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:

            # ------------------------------------------------------------------------

            # Load waveform for this hit
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            dataE = waveTree.trapENFCal.at(iH)
            dataST = waveTree.butterTime.at(iH)  # replace with blrwfFMR50?
            toe = waveTree.kvorrT.at(iH) / dataE
            print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f  t/e %.1f" % (
                iList, nList, run, nChans, chan, dataE, toe)
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH),
                                        opt='full')
            waveBLSub = signal.GetWaveBLSub()
            waveFilt = signal.GetWaveFilt()
            waveTS = signal.GetTS()
            baseAvg, dataNoise = signal.GetBaseNoise()

            # Denoise the data waveform (take only lowest-frequency components)
            wp = pywt.WaveletPacket(data=waveBLSub,
                                    wavelet='haar',
                                    mode='symmetric',
                                    maxlevel=3)
            new_wp = pywt.WaveletPacket(data=None,
                                        wavelet='haar',
                                        mode='symmetric')
            new_wp['aaa'] = wp['aaa'].data
            waveDenoised = new_wp.reconstruct(update=False)

            # Window the fit around rising edge - start time calculator method
            loWin, hiWin = dataST - 1000, dataST + 4000  # ns
            if loWin < waveTS[0] or hiWin > waveTS[-1]:
                print "Window out of range!  dataST: %.1f  loWin %.1f  hiWin %.1f" % (
                    dataST, loWin, hiWin)
            idx = np.where((waveTS >= loWin) & (waveTS <= hiWin))
            data = waveBLSub[idx]
            # data = waveDenoised[idx]
            dataTS = waveTS[idx]

            # Pack into lists
            rawList = [waveBLSub, waveTS, dataE, dataST]
            dataList = [data, dataTS, dataE, dataST, loWin, hiWin, dataNoise]
            tempList = [temp, tempTS, tempE, tempST]

            # Optionally save something to a file
            if saveMe:
                np.savez("./data/tailSlopeInputs.npz", rawList, tempList)

            # Recreate the guess and the guess's rising edge
            guessFull, guessFullTS = wm.MakeModel(dataList,
                                                  tempList,
                                                  [dataST, dataE, 1.],
                                                  opt="full")
            guess, guessTS = wm.MakeModel(dataList,
                                          tempList, [dataST, dataE, 1.],
                                          opt="!fancy")

            # Make an "almost complete" guess - no fitting
            # st, en, slo = dataST-100, dataE, 5
            InterpFn = interpolate.interp1d(tempTS,
                                            temp,
                                            kind="linear",
                                            copy="False",
                                            assume_sorted="True")
            # model, modelTS = wm.MakeModel(dataList, tempList, [st,en,slo], fn=InterpFn)

            # Fit with MCMC and get best-fit parameters
            # numSteps, burnIn = 10000, 5000 # default - 10000, 5000.  try 3000, 2000.  long test: 20000,10000
            # myModel = TemplateModel( dataList, dataNoise, tempList )
            # waveModel = pymc.Model( myModel )
            # M = pymc.MCMC( waveModel )
            # M.use_step_method(pymc.Metropolis, M.startTime, proposal_sd=100., proposal_distribution='Normal')
            # M.use_step_method(pymc.Metropolis, M.energy, proposal_sd=1., proposal_distribution='Normal')
            # M.use_step_method(pymc.Metropolis, M.slowness, proposal_sd=100., proposal_distribution='Normal')
            # M.sample(iter=numSteps, verbose=0) # do the fit
            # st = np.median(M.trace('startTime')[burnIn:])
            # en = np.median(M.trace('energy')[burnIn:])
            # slo = np.median(M.trace('slowness')[burnIn:])
            # InterpFn = interpolate.interp1d(tempTS, temp, kind="linear", copy="False", assume_sorted="True")
            # model, modelTS = wm.MakeModel(dataList, tempList, [st,en,slo], fn=InterpFn)

            # Fit with SciPy minimizer(s) and get best-fit parameters

            # how long does it take?
            start = time.time()

            MakeTracesGlobal(
            )  # creates 3 global arrays: startTrace, enTrace, sloTrace
            datas = [dataList, tempList, InterpFn]

            # floats = [1.]
            # result = op.basinhopping(findLnLike, floats, T=1000, stepsize=15, niter_success=2, minimizer_kwargs={"args":datas})
            # print "slowness:",result["x"],"dataE",dataE,"dataST",dataST
            # floats = [dataST, dataE, result["x"]]
            # MakeTracesGlobal() # resets traces

            floats = [dataST, dataE, 20.]
            result = op.minimize(findLnLike,
                                 floats,
                                 args=datas,
                                 method="Nelder-Mead")
            if not result["success"]: print result["message"]
            st, en, slo = result["x"]

            model, modelTS = wm.MakeModel(dataList,
                                          tempList, [st, en, slo],
                                          fn=InterpFn)

            stop = time.time()
            print "fitting took", stop - start

            # Calculate residual, Chi2/NDF, likelihood, etc.
            residual = model - data
            frac = (np.power(data - model, 2)) / np.abs(model)
            chi2NDF = np.sum(frac) / len(model)
            inv_sigma2 = 1.0 / (dataNoise**2)
            lnLike = -0.5 * (np.sum((data - model)**2 * inv_sigma2 -
                                    np.log(inv_sigma2)))

            # Fill the figure
            p1.cla()
            p1.set_ylabel("ADC")
            p1.set_title(
                "Run %d  Channel %d  Entry %d\ntrapENFCal %.1f  T/E %.1f  ST %.1f"
                % (run, chan, iList, dataE, toe, dataST))
            p1.plot(waveTS, waveBLSub, color='blue')
            p1.plot(waveTS, waveDenoised, color='red', alpha=0.8)
            p1.plot(guessFullTS, guessFull, color='orange', linewidth=2)
            p1.axvline(x=dataST, color='green', linewidth=2)
            p1.axvline(x=loWin, color='black')
            p1.axvline(x=hiWin, color='black')

            p2.cla()
            p2.plot(dataTS, data, color='blue', label='Data')
            p2.plot(guessTS, guess, color='orange', label='Guess')
            p2.plot(modelTS, model, color='red', linewidth=3, label='Best Fit')
            p2.legend(loc=4)

            p3.cla()
            p3.set_xlabel("Time [ns]", x=0.95, ha='right')
            p3.set_ylabel("Residual [ADC]")
            p3.plot(guessTS, residual, color='red')
            p3.axhline(y=0, color='blue', alpha=0.3)
            p3.axhline(y=dataNoise, color='blue', alpha=0.3)
            p3.axhline(y=-1.0 * dataNoise, color='blue', alpha=0.3)

            p4.cla()
            p4.set_title("startTime %.1f  Energy %.2f  Slow %.1f" %
                         (st, en, slo))

            p4.plot(stTrace[1:])
            p4.set_ylabel('startTime')

            p5.cla()
            p5.plot(enTrace[1:])
            p5.set_ylabel('energy')

            p6.cla()
            p6.plot(sloTrace[1:])
            p6.set_ylabel('slowness')

            plt.tight_layout()
            plt.subplots_adjust(hspace=0.35)
            plt.pause(scanSpeed)
Example #9
0
def main(argv):
    scanSpeed = 0.0001
    opt1, opt2 = "", ""
    intMode, printWF = False, False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print "Interactive mode selected."
    if "-s" in (opt1, opt2):
        printWF = True
        print "Saving WF plots to current directory."

    # Set input file and cut
    inputFile = TFile("~/project/match-skim/waveletSkimDS5_run23920.root")
    # inputFile = TFile("~/project/v2-processwfs/waveletSkimDS5_90.root")
    waveTree = inputFile.Get("skimTree")
    theCut = inputFile.Get("cutUsedHere").GetTitle()
    theCut += " && waveS5/trapENFCal < 1200 && trapENFCal < 5"
    # theCut += " && trapENFCal > 1.5 && trapENFCal < 2"
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Using cut:\n", theCut, "\n"
    print "Found", nList, "entries passing cuts."

    # Make a figure
    fig = plt.figure(figsize=(15, 10), facecolor='w')
    # p1 = plt.subplot(231)
    # p2 = plt.subplot(232)
    # p3 = plt.subplot(233)
    # p4 = plt.subplot(234)
    # p5 = plt.subplot(235)
    # p6 = plt.subplot(236)
    p1 = plt.subplot2grid((2, 3), (0, 0), colspan=2)
    p3 = plt.subplot2grid((2, 3), (0, 2))
    p4 = plt.subplot2grid((2, 3), (1, 0))
    p5 = plt.subplot2grid((2, 3), (1, 1))
    p6 = plt.subplot2grid((2, 3), (1, 2))

    plt.show(block=False)

    # Make templates
    samp, r, z, tempE, tempStart, smooth = 5000, 0, 15, 10, 2500, 100  # huge template
    tempHuge, tempHugeTS = wl.MakeSiggenWaveform(samp, r, z, tempE, tempStart,
                                                 smooth)

    samp, r, z, tempE, tempStart, smooth = 2016, 0, 15, 10, 1000, 100  # regular size template
    # samp, r, z, tempE, tempStart, smooth = 2016, 30, 30, 10, 1000, 100 # regular size temp, slower rise
    # samp, r, z, tempE, tempStart, smooth = 500, 0, 15, 10, 100, 100  # small template
    tempOrig, tempOrigTS = wl.MakeSiggenWaveform(samp, r, z, tempE, tempStart,
                                                 smooth)

    # Load stuff from DS1 forced acq. runs
    npzfile = np.load("./data/fft_forcedAcqDS1.npz")
    avgPsd, xPsd, avgPwrSpec, xPwrSpec, data_forceAcq, data_fft = npzfile[
        'arr_0'], npzfile['arr_1'], npzfile['arr_2'], npzfile[
            'arr_3'], npzfile['arr_4'], npzfile['arr_5']

    # Sampling frequency - 100MHz
    fs = 1e8

    # Loop over events
    iList = -1
    while (True):
        iList += 1
        if intMode == True and iList != 0:
            value = raw_input()
            if value == 'q': break
            if value == 'p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value)  # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        nWaves = waveTree.MGTWaveforms.size()
        numPass = waveTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans)
                   if waveTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:

            # ------------------------------------------------------------------------

            # Load data
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            dataE = waveTree.trapENFCal.at(iH)
            dataENM = waveTree.trapENM.at(iH)
            dataMaxTime = waveTree.trapENMSample.at(iH) * 10. - 4000
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH))
            data = signal.GetWaveBLSub()
            time = signal.GetTS()
            print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f  len %d" % (
                iList, nList, run, nChans, chan, dataE, len(data))

            # Load template
            template, temp_time = tempOrig, tempOrigTS
            template = template * (dataENM / tempE)
            # template = wl.wfDerivative(template)

            # Plot data and template
            p1.cla()
            p1.plot(time, data, color='blue')
            p1.set_xlabel('Time (s)')
            p1.set_ylabel('Voltage (arb)')
            p1.set_title("Run %i  Ch %i  E %.2f  ENM %.2f" %
                         (run, chan, dataE, dataENM))

            # p2.cla()
            p1.plot(temp_time, template, color='red')
            # p2.set_xlabel('Time (s)')
            # p2.set_ylabel('Voltage (arb)')
            # p2.set_title('Template')

            # Plot ASD of data and template
            # (amplitude spectral density (ASD), which is the square root of the PSD)
            p3.cla()
            power_data, freq_psd = plt.psd(data,
                                           Fs=fs,
                                           NFFT=2048,
                                           pad_to=2048,
                                           visible=False)
            p3.loglog(freq_psd, np.sqrt(power_data), color='blue')

            power_temp, freq = plt.psd(template,
                                       Fs=fs,
                                       NFFT=2048,
                                       pad_to=2048,
                                       visible=False)  # check this.
            p3.loglog(freq, np.sqrt(power_temp), color='red')

            p3.loglog(xPsd, np.sqrt(avgPsd),
                      color='green')  # DS1 forced acq. results

            p3.set_xlabel('Frequency (Hz)')
            p3.set_ylabel('ASD')
            p3.grid('on')

            # Apply a bandpass filter to the data and plot it
            # NOTE: This is tough.  There might be a feature
            #       due to rising edges, between 3e6 and 5e6 Hz.
            #       But that's only from data. Doing it w/ siggen templates yielded squat.
            # B,A = sig.butter(2, [3e6/(1e8/2),5e6/(1e8/2)], btype='bandpass')

            B, A = sig.butter(2, 1e6 / (1e8 / 2),
                              btype='lowpass')  # nice lowpass filter
            data_LowPass = sig.lfilter(B, A, data)

            B1, A1 = sig.butter(2, [1e5 / (1e8 / 2), 1e6 / (1e8 / 2)],
                                btype='bandpass')  # attempt at bandpass
            data_BanPass = sig.lfilter(B1, A1, data)

            p4.cla()
            p4.plot(time, data_LowPass, label='lowpass')
            p4.plot(time, data_BanPass, label='bandpass')
            p4.set_title('Band passed data')
            p4.set_xlabel('Time (s)')
            p4.legend(loc=4)

            # Plot time-domain cross-correlation
            # correlated_raw = np.correlate(data, template, 'same') # ligo used 'valid'.  'full' or 'same'
            # correlated_passed = np.correlate(data_pass, template, 'same')
            # p5.plot(np.arange(0, (correlated_raw.size*1.)/fs, 1.0/fs),correlated_raw)
            # p5.set_title('Time domain cross-correlation')
            # p5.set_xlabel('Offest between data and template (s)')
            # p5.plot(np.arange(0, (correlated_passed.size*1.)/fs, 1.0/fs), correlated_passed,color='red')
            # p5.set_xlabel('Offset between data and template (s)')

            # correlated = np.correlate(data,temp,'full')
            # correlated = np.correlate(data_pass,temp,'full')
            # x_corr = np.arange(0, (correlated.size*1.)/fs, 1.0/fs)

            # -- clint -- Do a simple convolution and smooth it
            temp, tempTS = flipAndAlign(tempHuge, tempHugeTS, time,
                                        dataMaxTime, dataENM, tempE)
            # smf = gaussian_filter(temp * data,sigma=float( 10 ))
            smf = gaussian_filter(temp * data_LowPass, sigma=float(5))

            p5.cla()
            p5.plot(time, data, color='blue', alpha=0.4)
            p5.plot(time, data_LowPass, color='green')
            p5.plot(tempTS, temp, color='red')
            p5.plot(tempTS, smf, color='red')
            # p5.plot(tempTS,correlated) # use the 'same' option
            # p5.plot(x_corr,correlated)

            # Matched (Optimal) Filter, freq. domain
            # Take the FFT of the data
            # data_fft = np.fft.fft(data)

            # Take the FFT of the low pass data
            data_fft = np.fft.fft(data_LowPass)

            # Pad template and take FFT
            zero_pad = np.zeros(data.size - template.size)
            template_padded = np.append(template, zero_pad)
            template_fft = np.fft.fft(template_padded)

            # Match FFT frequency bins to PSD frequency bins
            # power_noise, freq_psd_noise = plt.psd(data_forceAcq, Fs=fs, NFFT=2048, pad_to=2048, visible=False)
            # power_noise, freq_psd_noise = plt.psd(data[:256], Fs=fs, visible=False) # 512 or 256?
            power_noise, freq_psd_noise = avgPsd, xPsd  # from file

            # just for fun, calculate the integral of the 3 different noise spectra
            # forceAcqSingleBL = np.sum(power_noise)
            # data_bl_psd,_ = plt.psd(data[:512], Fs=fs, NFFT=512, visible=False)
            # dataBL = np.sum(data_bl_psd)
            # avgForceAcqSpec = np.sum(avgPsd)

            datafreq = np.fft.fftfreq(data.size) * fs
            power_vec = np.interp(datafreq, freq_psd_noise, power_noise)

            # Apply the optimal matched filter
            optimal = data_fft * template_fft.conjugate() / power_vec
            optimal_time = 2 * np.fft.ifft(optimal)

            # Normalize the matched filter output
            df = np.abs(datafreq[1] - datafreq[0])  # freq. bin size
            sigmasq = 2 * (template_fft * template_fft.conjugate() /
                           power_vec).sum() * df
            sigma = np.sqrt(np.abs(sigmasq))
            SNR = abs(optimal_time) / (sigma)

            opE = np.amax(SNR)
            opEE = opE / dataE

            # Plot the result
            p6.cla()
            p6.plot(time, SNR)
            p6.set_title('Optimal Matched Filter, opE %.1f  opE/E %.2f' %
                         (opE, opEE))
            p6.set_xlabel('Offset time (s)')
            p6.set_ylabel('SNR')

            plt.tight_layout()
            plt.pause(scanSpeed)
Example #10
0
def main(argv):

    ds = 5
    tt = TChain("skimTree")
    tt.Add("~/project/cal/lat/*.root")

    # i'm just pasting the output of view-v2 here.

    # thesis plot, fast vs slow
    # trapENF 16.0, iE 20958, iH 0 # fast
    # trapENF 16.0, iE 33039, iH 0 # slow
    evtList = [[20958, 0], [33039, 0]]
    cols = ['k', 'r', 'g', 'm']
    labels = ['Fast, 16.0 keV', 'Slow, 16.0 keV']
    alphas = [1, 0.7]

    for i, (iE, iH) in enumerate(evtList):
        tt.GetEntry(iE)

        run = tt.run
        chan = tt.channel.at(iH)
        hitE = tt.trapENFCal.at(iH)
        wf = tt.MGTWaveforms.at(iH)
        truncLo, truncHi = 0, 2
        if ds == 6 or ds == 2: truncLo = 4
        signal = wl.processWaveform(wf, truncLo, truncHi)
        waveBLSub = signal.GetWaveBLSub()
        waveTS = signal.GetTS()
        print("%d / %d  Run %d  chan %d  trapENF %.1f" %
              (i, len(evtList), run, chan, hitE))

        # plt.plot(waveTS, waveBLSub, "-", lw=1, c=cols[i], label="%.1f keV" % hitE)

        plt.plot(waveTS,
                 waveBLSub,
                 "-",
                 lw=2,
                 c=cols[i],
                 alpha=alphas[i],
                 label=labels[i])

        # # standard energy trapezoid
        # eTrap = wl.trapFilter(waveBLSub,400,250,-7200)
        #
        # nPad = len(waveBLSub)-len(eTrap)
        # eTrap = np.pad(eTrap, (nPad,0), 'constant')
        # eTrapTS = np.arange(0, len(eTrap)*10., 10)
        # ePickoff = eTrapTS[nPad + 400 + 200]
        # # plt.axvline(ePickoff, c='m')
        #
        # # trigger trap
        # tTrap = wl.trapFilter(waveBLSub,100,150,-7200)
        # tTrap = np.pad(tTrap, (nPad,0), 'constant')
        # tTrapTS = np.arange(0, len(tTrap)*10., 10)
        #
        # # low pass filter
        # B, A = butter(2,1e6/(1e8/2), btype='lowpass')
        # waveLP = lfilter(B, A, waveBLSub)
        #
        # plt.cla()
        # plt.plot(waveTS, waveBLSub, 'b', label='Raw WF, %.2f keV' % (hitE))
        # # plt.plot(waveTS, waveLP, 'r', alpha=0.7, label='Low-pass filter')

    plt.ylim(ymin=-10)

    plt.xlabel("Time (ns)", ha='right', x=1)
    plt.ylabel("Voltage (ADC)", ha='right', y=1)
    plt.legend(loc=4)

    # plt.pause(0.0001) # scan speed, does plt.show(block=False) automatically
    # plt.show()

    plt.savefig('../plots/fast-and-slow.pdf')
Example #11
0
def checkLAT():
    """ ./check-files.py [-c] -l """
    # make sure nLat matches nSplit files
    # repeat the checkWave checks
    print("Checking lats.  Cal?", checkCal)

    fileList = []

    # bkg
    if not checkCal:
        dsMap = bkg.dsMap()
        for ds in dsMap:
            for sub in range(dsMap[ds] + 1):

                sList = dsi.getSplitList(
                    "%s/splitSkimDS%d_%d*" % (dsi.splitDir, ds, sub), sub)
                latList = dsi.getSplitList(
                    "%s/latSkimDS%d_%d*" % (dsi.latDir, ds, sub), sub)
                if len(sList) != len(latList):
                    print(
                        "Error: ds %d sub %d.  Found %d split files but %d lat files."
                        % (ds, sub, len(sList), len(latList)))

                tmpList = [f for idx, f in sorted(latList.items())]
                fileList.extend(tmpList)
    # cal
    else:
        dsMap = cal.GetKeys()
        for key in dsMap:
            ds = int(key[2])
            if skipDS6Cal and ds == 6: continue
            for sub in range(cal.GetIdxs(key)):
                cRuns = cal.GetCalList(key, sub)
                for run in cRuns:

                    sList = dsi.getSplitList(
                        "%s/splitSkimDS%d_run%d*" % (dsi.calSplitDir, ds, run),
                        run)
                    latList = dsi.getSplitList(
                        "%s/latSkimDS%d_run%d*" % (dsi.calLatDir, ds, run),
                        run)
                    if len(sList) != len(latList):
                        print(
                            "Error: ds %d  sub %d  run %d.  Found %d split files but %d lat files."
                            % (ds, sub, run, len(sList), len(latList)))

                    tmpList = [f for idx, f in sorted(latList.items())]
                    fileList.extend(tmpList)
    if testMode:
        fileList = []
        ds = 1
        # dsMap = bkg.dsMap()
        # for sub in range(dsMap[ds]+1):
        #     latList = dsi.getSplitList("%s/latSkimDS%d_%d*" % (dsi.latDir, ds, sub), sub)
        #     tmpList = [f for idx, f in sorted(latList.items())]
        #     fileList.extend(tmpList)
        dsMap = cal.GetKeys()
        key = dsMap[1]
        for sub in range(cal.GetIdxs(key)):
            cRuns = cal.GetCalList(key, sub)
            for run in cRuns:
                latList = dsi.getSplitList(
                    "%s/latSkimDS%d_run%d*" % (dsi.calLatDir, ds, run), run)
                fileList.extend([f for idx, f in sorted(latList.items())])

    # loop over files, repeating the same checks in checkWave
    for idx, fname in enumerate(fileList[:fLimit]):
        f = TFile(fname)
        t = f.Get("skimTree")
        n = t.GetEntries()

        if n == 0:
            print("No entries in file", fname)
            continue

        brSingle, brVector = [], []
        for br in t.GetListOfBranches():
            if "vector" in br.GetClassName():
                brVector.append(br.GetName())
            else:
                brSingle.append(br.GetName())

        if n < 20:
            eList = np.arange(0, n, 1)
        else:
            eList = np.arange(0, 20, 1)
            eList = np.append(eList, np.arange(n - 20, n, 1))

        for i in eList:
            t.GetEntry(i)

            # make sure individual entries are accessible (no segfaults)
            for br in brSingle:
                val = getattr(t, br)
                # print(val)
            for br in brVector:
                try:
                    nCh = getattr(t, br).size()
                except AttributeError:
                    print("Error:", br)
                for j in range(nCh):
                    val = getattr(t, br)[j]
                    # print(br,nCh,val)

            # make sure we can process waveforms
            for j in range(nCh):
                wf = t.MGTWaveforms.at(j)
                ch = t.channel.at(j)

                # be absolutely sure you're matching the right waveform to this hit
                if wf.GetID() != ch:
                    print(
                        "ERROR -- Vector matching failed. entry %d, file: %s" %
                        (i, fname))

                # run the LAT routine to convert into numpy arrays
                truncLo, truncHi = 0, 2
                if ds == 6 or ds == 2: truncLo = 4
                signal = wl.processWaveform(wf, truncLo, truncHi)

        if verbose:
            print("%d/%d  %s  nEnt %d" % (idx, len(
                fileList[:fLimit]), fname.split("/")[-1], t.GetEntries()))

        f.Close()
Example #12
0
def main(argv):
    """ Bug: Doesn't always work with a TChain.
    Add input files together with hadd and use a single TFile.
    """
    scanSpeed = 0.2
    opt1, opt2 = "", ""
    intMode, printWF = False, False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print "Interactive mode selected."
    if "-s" in (opt1, opt2):
        printWF = True
        print "Saving WF plots to current directory."

    # Set input file
    # DS5 calibration run (lots of all pulses)
    # inputFile = TFile("~/project/match-skim/waveletSkimDS5_run23884.root")

    # Simulated noise pulses from Brian
    inputFile = TFile("./data/SimWF_Baseline.root")
    waveTree = inputFile.Get("skimTree")

    # ext. pulsing runs (P2D2, chan 674) https://majorana.npl.washington.edu/elog/Run+Elog/1093
    # gatFile = TFile("~/project/gat-blt-data/gatified/mjd_run7219.root")
    # bltFile = TFile("~/project/gat-blt-data/built/OR_run7219.root")

    # ext. trigger runs https://majorana.npl.washington.edu/elog/Run+Elog/1207
    # gatFile = TFile("~/project/gat-blt-data/gatified/mjd_run9913.root")
    # bltFile = TFile("~/project/gat-blt-data/built/OR_run9913.root")

    # waveTree = gatFile.Get("mjdTree")
    # bltTree = bltFile.Get("MGTree")
    # waveTree.AddFriend(bltTree)

    print "Found",waveTree.GetEntries(),"input entries."

    # Set cuts
    # theCut = inputFile.Get("cutUsedHere").GetTitle()
    # theCut = "trapENFCal > 0.8 && gain==0 && mH==1 && isGood && !muVeto && !wfDCBits && !isLNFill1 && !isLNFill2 && trapETailMin < 0 && channel!=596 && channel!=676 && channel!=676 && channel!=612 && channel!=1104 && channel!=1200 && channel!=1334 && channel!=1336"
    # theCut = "channel==674"
    theCut = ""
    print "Using cut:\n",theCut,"\n"
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Found",nList,"entries passing cuts."

    # Make a figure
    fig = plt.figure(figsize=(8,5), facecolor='w')
    # p1 = plt.subplot2grid((6,7), (0,0), colspan=4, rowspan=2) # original
    p1 = plt.subplot(111)
    plt.show(block=False)

    # Make a template waveform
    samp, r, z, ene, t0, smooth = 2016, 0, 15, 10, 1000, 100
    temp, tempTS = MakeSiggenWaveform(samp,r,z,ene,t0,smooth)

    # Loop over events
    iList = -1
    while(True):
        iList += 1
        if intMode==True and iList !=0:
            value = raw_input()
            if value=='q': break
            if value=='p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value) # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList);
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        # nChans = waveTree.channel.size()
        nChans = waveTree.MGTWaveforms.size()
        # numPass = waveTree.Draw("channel",theCut,"GOFF",1,iList)
        # chans = waveTree.GetV1()
        # chanList = list(set(int(chans[n]) for n in xrange(numPass)))
        # event = bltTree.event  # grab waveforms from built data (comment this out if we're using clint-skim)

        # Loop over hits passing cuts
        # hitList = (iH for iH in xrange(nChans) if waveTree.channel.at(iH) in chanList)  # a 'generator expression'
        # for iH in hitList:
        for iH in range(nChans):
            # run = waveTree.run
            # chan = waveTree.channel.at(iH)
            # dataE = waveTree.trapENFCal.at(iH)
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH)) # use when we have skim
            # signal = wl.processWaveform(event.GetWaveform(iH)) # use when we have gat+blt data
            waveBLSub = signal.GetWaveBLSub()
            waveFilt = signal.GetWaveFilt()
            waveTS = signal.GetTS() * 10.
            # print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f" % (iList,nList,run,nChans,chan,dataE)

            # Generate a siggen WF
            samp, r, z, ene, t0, smooth = 2016, 0, 15, 10, 1000, 100
            sigg, siggTS = MakeSiggenWaveform(samp,r,z,ene,t0,smooth)

            data = sigg + waveBLSub

            # Fill the figure
            p1.cla()
            p1.set_ylabel("ADC")
            # p1.set_title("Run %d  Channel %d  Entry %d  trapENFCal %.1f" % (run,chan,iList,dataE))
            p1.plot(waveTS,data,color='blue')
            p1.plot(tempTS,temp,color='red')

            plt.pause(scanSpeed)
Example #13
0
def main(argv):

    startT = time.clock()
    inDir, outDir = ".", "."
    inFile, inFileName, outFileName = TFile(), "", ""
    gatTree = TTree()
    dsNum, subNum, runNum, theCut, inFileName = -1, -1, -1, "", ""
    saveLAT, savePacket, saveWave = False, False, False

    if len(argv) == 0: return
    for i, opt in enumerate(argv):
        if opt == "-f":
            # dsNum, subNum, inDir, outDir = int(argv[i+1]), int(argv[i+2]), str(argv[i+3]), str(argv[i+4])
            inDir, inFileName, outDir = str(argv[i + 1]), str(
                argv[i + 2]), str(argv[i + 3])
            # inFileName = "waveSkimDS{}_{}.root".format(dsNum, subNum)
        if opt == "-r":
            inDir, inFileName, outDir = str(argv[i + 1]), str(
                argv[i + 2]), str(argv[i + 3])
            # dsNum, runNum, inDir, outDir = int(argv[i+1]), int(argv[i+2]), str(argv[i+3]), str(argv[i+4])
            # inFileName = "waveSkimDS{}_run{}.root".format(dsNum, runNum)

    # inFileName = inDir + inFile
    print("Scanning File: {}".format(inFileName))
    inFile = TFile("%s/%s" % (inDir, inFileName))
    gatTree = inFile.Get("skimTree")
    theCut = inFile.Get("theCut").GetTitle()

    # Make files smaller for tests
    # theCut += " && sumEHL > 236 && sumEHL < 240 && mHL==2 && trapENFCal < 5"
    # Select only pulsers
    # theCut += " && EventDC1Bits > 0"

    print "Using cut:\n", theCut
    gatTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    gatTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Found", gatTree.GetEntries(), "input entries."
    print "Found", nList, "entries passing cuts."
    # Gimmicky but works... this bypasses creating the branches...
    gatTree.GetEntry(0)

    # Mess of various branches
    channel = std.vector("int")()
    trapENFCal = std.vector("double")()
    trapENM = std.vector("double")()

    # Create map of branches to put into dataframe
    # This map is only for branches that we want to keep!
    keepMapBase = {
        'trapENFCal': gatTree.trapENFCal,
        'trapENM': gatTree.trapENM,
        "channel": gatTree.channel,
        "run": gatTree.run,
        "mHL": gatTree.mHL
    }

    # Combine dictionaries, if keepMapLAT is empty it won't add any branches
    keepMap = dict(keepMapBase)
    # keepMap.update(keepMapLAT)

    dataList = []
    print 'Writing to: ', '%s/proc%s.h5' % (outDir, inFileName.split('.')[0])

    iList, removeNBeg, removeNEnd = -1, 500, 500
    # Loop over events
    while True:
        iList += 1
        if iList >= nList: break
        # if iList >= 5000: break
        entry = gatTree.GetEntryNumber(iList)
        gatTree.LoadTree(entry)
        gatTree.GetEntry(entry)
        nChans = gatTree.channel.size()
        numPass = gatTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = gatTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))
        hitList = (iH for iH in xrange(nChans)
                   if gatTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:
            dataMap = {}
            wf = gatTree.MGTWaveforms.at(iH)
            signal = wl.processWaveform(wf, removeNBeg, removeNEnd)
            wave = np.array(signal.GetWaveRaw(), dtype=np.int16)
            for key, branch in keepMap.items():
                # Save branches that aren't vector<Template> (so far only run and mHL)
                if key == 'run' or key == 'mHL': dataMap[key] = int(branch)
                elif key == 'channel': dataMap[key] = int(branch.at(iH))
                else: dataMap[key] = float(branch.at(iH))
            dataMap['waveform'] = wave.tolist()
            dataList.append(dataMap)

        if iList % 5000 == 0 and iList != 0:
            print "%d / %d entries saved (%.2f %% done), time: %s" % (
                iList, nList, 100 *
                (float(iList) / nList), time.strftime('%X %x %Z'))

    df = pd.DataFrame.from_dict(dataList)
    print(df.head())
    print(df.info())
    print(np.unique(df.channel))
    print(np.unique(df.mHL))
    print(np.unique(df.run))
    # Suppress stupid warning
    warnings.filterwarnings(action="ignore",
                            module="pandas",
                            message="^\nyour performance")

    # Chunk write like a sucker
    chunksize = 50000
    start = 0
    end = chunksize - 1
    i = 0
    # for i in len(df):
    while end < df.shape[0]:
        # chunk = df.iloc[(i*chunksize):min((i+1)*chunksize,len(df))]
        chunk = df.iloc[start:end]
        try:
            chunk.to_hdf('{}/proc{}_{}.h5'.format(outDir,
                                                  inFileName.split('.')[0], i),
                         key='skimTree',
                         data_columns=[
                             'trapENFCal', 'trapENM', 'channel', 'mHL',
                             'waveform'
                         ],
                         format='fixed',
                         mode='w',
                         complevel=9)
        except (Exception) as e:
            print e
            print chunk
            print chunk.info()
        start += chunksize
        end += chunksize
        i += 1

    # df.to_hdf('%s/proc%s.h5' % (outDir,inFileName.split('.')[0]), key="skimTree", data_columns=['trapENFCal', 'trapENM','channel','mHL','waveform'], format='fixed', mode='w', complevel=9)

    stopT = time.clock()
    print("Stopped:", time.strftime('%X %x %Z'), "\nProcess time (min):",
          (stopT - startT) / 60)
    print(float(nList) / ((stopT - startT) / 60.), "entries per minute.")
Example #14
0
def main(argv):

    quickDraw = False
    for i, opt in enumerate(argv):
        if opt == "-q":
            print("Quick draw mode selected.")
            quickDraw = True

    # ds = "5A"
    # tt.Add("~/project/cal/lat/*.root")
    # tt.Add("~/project/cal/lat/latSkimDS1_run13774_0.root")

    # tCut = "trapENFCal > 238 && trapENFCal < 239" # 238 kev wf, thesis plot
    # tCut = "trapENFCal >= 1.0 && trapENFCal < 1.2 && channel!=598  && trapENFCal > threshKeV+3*threshSigma && fitSlo < 100" # 1 kev wf, thesis plot

    # tCut = "trapENFCal > 16 && trapENFCal < 16.1 && fitSlo < 100 && tOffset<10"
    # tCut = "trapENFCal > 16 && trapENFCal < 16.1 && fitSlo > 100"

    # don't open the final files as tchains, it made a big segfault??
    # tf = TFile("~/project/bkg/cut/final/final_DS%s.root" % ds)
    # tt = tf.Get("skimTree")

    # tCut = "trapENFCal >= 1 && trapENFCal < 4"

    # tCut = "trapENFCal < 1.5 && tOffset > 1000" # try to grab a retrigger waveform

    # ds = 5
    tt = TChain("skimTree")
    tt.Add("~/project/bkg/cut/final95/final95*.root")

    tCut = "tOffset > 4000"  # for sure retriggers
    # tCut = "tOffset > 200 && tOffset < 2000"

    n = tt.Draw("Entry$:Iteration$", tCut, "goff")
    evt, itr = tt.GetV1(), tt.GetV2()
    evtList = [[int(evt[i]), int(itr[i])] for i in range(n)]

    nEnt = len(set([evt[i] for i in range(n)]))
    print("Found %d total entries, %d passing cut: %s" %
          (tt.GetEntries(), nEnt, tCut))

    dsr = bkg.dsRanges()

    i, pEvt = -1, -1
    while (True):
        i += 1
        if not quickDraw and i != 0:
            val = input()
            if val == "q": break
            if val == "p": i -= 2
            if val.isdigit(): i = int(val)
            if val == "s":
                pltName = "../plots/wf-%d.pdf" % i
                print("Saving figure:", pltName)
                plt.savefig(pltName)
        if i >= len(evtList): break
        iE, iH = evtList[i]

        if iE != pEvt:
            tt.GetEntry(iE)
        pEvt = iE

        run = tt.run
        ds = bkg.GetDSNum(run)

        chan = tt.channel.at(iH)
        hitE = tt.trapENFCal.at(iH)
        tOff = tt.tOffset.at(iH)

        wf = tt.MGTWaveforms.at(iH)
        truncLo, truncHi = 0, 2

        if ds == 6 or ds == 2: truncLo = 4
        signal = wl.processWaveform(wf, truncLo, truncHi)

        # waveform
        waveBLSub = signal.GetWaveBLSub()
        waveTS = signal.GetTS()
        print("%d / %d  Run %d  chan %d  trapENF %.1f, iE %d, iH %d" %
              (i, len(evtList), run, chan, hitE, iE, iH))

        # standard energy trapezoid
        eTrap = wl.trapFilter(waveBLSub, 400, 250, -7200)

        nPad = len(waveBLSub) - len(eTrap)
        eTrap = np.pad(eTrap, (nPad, 0), 'constant')
        eTrapTS = np.arange(0, len(eTrap) * 10., 10)
        ePickoff = eTrapTS[nPad + 400 + 200]
        # plt.axvline(ePickoff, c='m')

        # trigger trap
        tTrap = wl.trapFilter(waveBLSub, 100, 150, -7200)
        tTrap = np.pad(tTrap, (nPad, 0), 'constant')
        tTrapTS = np.arange(0, len(tTrap) * 10., 10)

        # low pass filter
        B, A = butter(2, 1e6 / (1e8 / 2), btype='lowpass')
        waveLP = lfilter(B, A, waveBLSub)

        # wavelet denoised
        wp = pywt.WaveletPacket(waveBLSub, 'db2', 'symmetric', maxlevel=4)
        new_wp = pywt.WaveletPacket(data=None, wavelet='db2', mode='symmetric')
        new_wp['aaa'] = wp['aaa'].data
        waveDenoised = new_wp.reconstruct(update=False)
        # resize in a smart way
        diff = len(waveDenoised) - len(waveBLSub)
        if diff > 0: waveDenoised = waveDenoised[diff:]

        plt.cla()
        plt.plot(waveTS,
                 waveBLSub,
                 'b',
                 lw=2,
                 label='Raw WF, %.2f keV' % (hitE))
        # plt.plot(waveTS, waveBLSub, 'b', alpha=0.2, label='Raw WF, %.2f keV' % (hitE))
        # plt.plot(waveTS, waveLP, 'r', alpha=0.7, label='Low-pass filter')
        plt.plot(waveTS,
                 waveDenoised,
                 "r",
                 lw=2,
                 alpha=0.5,
                 label="Denoised WF")
        plt.plot(np.nan, np.nan, "-w", label="tOffset: %d" % tOff)

        plt.xlabel("Time (ns)", ha='right', x=1)
        plt.ylabel("Voltage (ADC)", ha='right', y=1)
        plt.legend(loc=4)
        plt.tight_layout()

        plt.pause(
            0.0001)  # scan speed, does plt.show(block=False) automatically
Example #15
0
def main(argv):
    scanSpeed = 1.0
    opt1, opt2 = "", ""
    intMode, printWF = False, False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print "Interactive mode selected."
    if "-s" in (opt1, opt2):
        printWF = True
        print "Saving WF plots to current directory."

    # Set input file
    inputFile = TFile(
        "./data/SimWF_Baseline.root")  # simulated noise pulses from Brian
    waveTree = inputFile.Get("skimTree")
    theCut = ""

    # Make a figure
    fig = plt.figure(figsize=(8, 5), facecolor='w')
    # fig, (ax_orig, ax_noise, ax_corr) = plt.subplots(3, 1, sharex=True)
    # p1 = plt.subplot2grid((6,7), (0,0), colspan=4, rowspan=2) # original
    p1 = plt.subplot(111)
    plt.show(block=False)

    # Make a template waveform
    samp, r, z, ene, t0, smooth = 5000, 0, 15, 10, 2500, 100  # huge floating waveform
    tempOrig, tempOrigTS = wl.MakeSiggenWaveform(samp, r, z, ene, t0, smooth)

    # Loop over events
    iEnt = -1
    while (True):
        iEnt += 1
        if intMode == True and iEnt != 0:
            value = raw_input()
            if value == 'q': break
            if value == 'p': iEnt -= 2  # previous
            if (value.isdigit()): iEnt = int(value)  # go to entry
        if iEnt >= waveTree.GetEntriesFast(): break
        waveTree.GetEntry(iEnt)

        # Make a fake "data" pulse
        signal = wl.processWaveform(
            waveTree.MGTWaveforms.at(0))  # brian only has 1 pulse per event
        noise = signal.GetWaveBLSub()
        dataTS = signal.GetTS() * 10.
        samp, r, z, ene, t0, smooth = 2016, 0, 15, 10, 1000, 100  # realistic waveform
        sigg, siggTS = wl.MakeSiggenWaveform(samp, r, z, ene, t0, smooth)
        data = sigg + noise

        # how long does this take?
        start = time.time()
        wp = pywt.WaveletPacket(data=data,
                                wavelet='haar',
                                mode='symmetric',
                                maxlevel=3)
        new_wp = pywt.WaveletPacket(data=None,
                                    wavelet='haar',
                                    mode='symmetric')
        new_wp['aaa'] = wp['aaa'].data
        newWave = new_wp.reconstruct(update=False)
        stop = time.time()
        print "denoising took", stop - start

        # what about this part?
        start = time.time()
        deriv = wl.wfDerivative(newWave)
        stop = time.time()
        print "derivative took", stop - start

        p1.cla()
        p1.set_ylabel("ADC")
        p1.plot(dataTS, data, color='blue')
        p1.plot(siggTS, sigg, color='red')
Example #16
0
def procSim(nMax=None):
    """
        Get sum and hit spectra w/ threshold cut, without ch. 598 (it's noisy.)
        Here we use "mHT" and "sumET" exclusively.
        Use !EventDC1Bits and trapENFCal > 0.7, all hits.  (Skim file was generated w/ 'dontSkipAnything')
        Save detailed info for events with hits < 2630 keV.
    """
    from ROOT import TFile, TTree, MGTWaveform

    # fig = plt.figure(figsize=(12,7), facecolor='w')
    # p0 = plt.subplot2grid((6,10), (0,0), colspan=10, rowspan=3) # waveform fit
    # p1 = plt.subplot2grid((6,10), (3,0), colspan=10, rowspan=1) # residual
    # p2 = plt.subplot2grid((6,10), (4,0), colspan=2, rowspan=2) # traces
    # p3 = plt.subplot2grid((6,10), (4,2), colspan=2, rowspan=2)
    # p4 = plt.subplot2grid((6,10), (4,4), colspan=2, rowspan=2)
    # p5 = plt.subplot2grid((6,10), (4,6), colspan=2, rowspan=2)
    # p6 = plt.subplot2grid((6,10), (4,8), colspan=2, rowspan=2)

    # Use the force acquisition baseline + SigGen waveforms
    inDir = os.environ['LATDIR'] + '/data'
    f1 = TFile('{}/waveSkimDS0_run4201.root'.format(inDir))
    skimTree = f1.Get('skimTree')

    dfSigGen = pd.read_hdf('{}/SigGen_WFs_P42574A.h5'.format(inDir))
    # sigList = [0, 20, 40, 60]
    sigList = [0]
    # Truncates to 2017 samples, cuz we in 2017
    truncLo, truncHi = 8, 6
    dataList = []

    print('Total Entries: ', skimTree.GetEntries())
    maxVal = 0
    if nMax:
        maxVal = min(nMax, skimTree.GetEntries())
    else:
        maxVal = skimTree.GetEntries()

    for idx in range(maxVal):
        if idx % 100 == 0:
            print("Processed Entry ", idx)
        skimTree.GetEntry(idx)
        if skimTree.mH > 1: continue  # Only care about mH1 for noise
        channel = skimTree.channel.at(0)
        if channel != 624: continue
        wf = MGTWaveform()
        wf = skimTree.MGTWaveforms.at(0)
        signal = wl.processWaveform(wf, truncLo, truncHi)
        data = signal.GetWaveRaw()
        data_blSub = signal.GetWaveBLSub()
        dataTS = signal.GetTS()
        dataBL, dataNoise = signal.GetBaseNoise()
        # Generate one fake WF at each amplitude/r/z combination (30 total)
        for index, row in dfSigGen.iterrows():
            # Skip the waveforms that are far
            # if row['r'] != 34.0: continue
            # if row['z'] != 50.0: continue
            for sigma in sigList:
                dataMap = {}
                if sigma == 0:
                    simWF = row['waveform']
                else:
                    simWF = gaussian_filter(row['waveform'], sigma)
                sig = addSigToBaseline(data, simWF)
                sigBL = addSigToBaseline(data_blSub, simWF)
                # Dummy variables
                # fitAmp, TSMax = row['amp'], 1200*10
                dataMap = procEvent(
                    sig, dataTS, sigBL, dataBL,
                    '{}_A{}R{}Z{}'.format(idx, row['amp'], row['r'], row['z']))
                dataMap['Amp'] = row['amp']
                dataMap['R'] = row['r']
                dataMap['Z'] = row['z']
                dataMap['Sigma'] = sigma
                # dataMap['waveform'] = sigBL.tolist()
                dataList.append(dataMap)

    df = pd.DataFrame.from_dict(dataList)
    print(df.head())
    df.to_hdf('{}/SimPSA_P42574A.h5'.format(inDir), 'skimTree')
Example #17
0
def main(argv):
    """Interactive-draw or rapid-draw waveforms that pass a given TCut.
       Bug: Doesn't always work with a TChain.  Add input files together
       with hadd and use a single TFile.
    """
    scanSpeed = 0.2
    opt1, opt2 = "", ""
    intMode, printWF, warpMode = False, False, False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print("Interactive mode selected.")
    if "-s" in (opt1, opt2):
        printWF = True
        print("Saving WF plots to current directory.")
    if "-w" in (opt1, opt2):
        warpMode = True
        import matplotlib
        matplotlib.use('TkAgg')
        print("Warp-speed drawing, don't trust figure axes.")
    import matplotlib.pyplot as plt
    plt.style.use('../pltReports.mplstyle')
    from matplotlib.colors import LogNorm, Normalize

    # Set input file and cuts
    dsNum = 5
    # waveTree = TChain("skimTree") # NOTE: Can't always recognize MGTWaveforms branch
    # waveTree.Add("~/project/lat/latSkimDS1*")
    inputFile = TFile(
        "/Users/wisecg/project/cal/lat/latSkimDS5_run20044_0.root")
    # inputFile = TFile("~/project/cal-waves/waveSkimDS2_run14857.root")
    # inputFile = TFile("~/project/cal-waves/waveSkimDS5_run23895.root")

    waveTree = inputFile.Get("skimTree")
    print("Found", waveTree.GetEntries(), "input entries.")

    theCut = inputFile.Get("theCut").GetTitle()
    # theCut += " && trapENFCal  1.1"
    # theCut = " trapENFCal > 0.5 && trapENFCal < 10"

    # Print cut and events passing cut
    print("Using cut:\n", theCut, "\n")
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print("Found", nList, "entries passing cuts.")

    # Make a figure (only setting data in the loop is faster)
    fig = plt.figure()
    a1 = plt.subplot(111)
    a1.set_xlabel("Time (ns)", ha='right', x=1)
    a1.set_ylabel("Voltage (ADC)", ha='right', y=1)
    p1, = a1.plot(np.ones(1),
                  np.ones(1),
                  color='blue',
                  alpha=0.8,
                  label='data')
    p2, = a1.plot(np.ones(1),
                  np.ones(1),
                  color='magenta',
                  linewidth=1.5,
                  label='denoised')
    p3, = a1.plot(np.ones(1),
                  np.ones(1),
                  color='red',
                  linewidth=3,
                  label='lowpass')
    # a1.legend(loc=4)
    plt.show(block=False)

    # Loop over events
    iList = -1
    while (True):
        iList += 1
        if intMode == True and iList != 0:
            value = input()
            if value == 'q': break
            if value == 'p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value)  # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        nWFs = waveTree.MGTWaveforms.size()

        if (nWFs == 0):
            print("Error - nWFs:", nWFs, "nChans", nChans)
            continue

        numPass = waveTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in range(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in range(nChans)
                   if waveTree.channel.at(iH) in chanList)
        for iH in hitList:
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            energy = waveTree.trapENFCal.at(iH)
            wf = waveTree.MGTWaveforms.at(iH)

            truncLo, truncHi = 0, 2
            if dsNum == 6 or dsNum == 2: truncLo = 4
            signal = wl.processWaveform(wf, truncLo, truncHi)

            waveBLSub = signal.GetWaveBLSub()
            # waveRaw = signal.GetWaveRaw()
            waveTS = signal.GetTS()
            print("%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f" %
                  (iList, nList, run, nChans, chan, energy))

            # standard energy trapezoid
            eTrap = wl.trapFilter(waveBLSub, 400, 250, -7200)

            nPad = len(waveBLSub) - len(eTrap)
            eTrap = np.pad(eTrap, (nPad, 0), 'constant')
            eTrapTS = np.arange(0, len(eTrap) * 10., 10)
            ePickoff = eTrapTS[nPad + 400 + 200]
            # plt.axvline(ePickoff, c='m')

            # trigger trap
            tTrap = wl.trapFilter(waveBLSub, 100, 150, -7200)
            tTrap = np.pad(tTrap, (nPad, 0), 'constant')
            tTrapTS = np.arange(0, len(tTrap) * 10., 10)

            # -- fill the figure --
            p1.set_ydata(waveBLSub)
            p1.set_xdata(waveTS)

            p2.set_ydata(tTrap)
            p2.set_ydata(tTrapTS)

            p3.set_ydata(eTrap)
            p3.set_xdata(eTrapTS)

            xmin, xmax = np.amin(waveTS), np.amax(waveTS)
            ymin, ymax = np.amin(waveBLSub), np.amax(waveBLSub)
            a1.set_xlim([xmin, xmax])
            a1.set_ylim([ymin - abs(0.1 * ymin), ymax + abs(0.1 * ymax)])
            # plt.title("Run %d  Channel %d  Entry %d  trapENFCal %.1f" % (run,chan,iList,energy))

            if warpMode:
                # superfast, requires TkAgg backend, doesn't update axes
                a1.draw_artist(a1.patch)
                a1.draw_artist(p1)
                fig.canvas.blit(a1.bbox)
                fig.canvas.flush_events()
            else:
                plt.pause(scanSpeed)

            if (printWF):
                plt.savefig("./plots/wave-%d-%d-%d.pdf" % (run, iList, chan))
Example #18
0
File: lat.py Project: gothman5/LAT
def main(argv):

    print("=======================================")
    print("LAT started:",time.strftime('%X %x %Z'))
    startT = time.clock()
    # gROOT.ProcessLine("gErrorIgnoreLevel = 3001;") # suppress ROOT error messages
    global batMode
    intMode, batMode, rangeMode, fileMode, gatMode, singleMode, pathMode, cutMode = False, False, False, False, False, False, False, False
    dontUseTCuts = False
    dsNum, subNum, runNum, plotNum = -1, -1, -1, 1
    pathToInput, pathToOutput, manualInput, manualOutput, customPar = ".", ".", "", "", ""

    if len(argv)==0: return
    for i,opt in enumerate(argv):
        if opt == "-r":
            rangeMode, dsNum, subNum = True, int(argv[i+1]), int(argv[i+2])
            print("Scanning DS-%d sub-range %d" % (dsNum, subNum))
        if opt == "-p":
            pathMode, manualInput, manualOutput = True, argv[i+1], argv[i+2]
            print("Manually set input/output files:\nInput: %s\nOutput: %s" % (manualInput, manualOutput))
        if opt == "-d":
            pathToInput, pathToOutput = argv[i+1], argv[i+2]
            print("Custom paths: Input %s,  Output %s" % (pathToInput,pathToOutput))
        if opt == "-f":
            fileMode, dsNum, runNum = True, int(argv[i+1]), int(argv[i+2])
            print("Scanning DS-%d, run %d" % (dsNum, runNum))
        if opt == "-g":
            gatMode, runNum = True, int(argv[i+1])
            print("GATDataSet mode.  Scanning run %d" % (runNum))
        if opt == "-s":
            singleMode, pathToInput = True, argv[i+1]
            print("Single file mode.  Scanning {}".format(pathToInput))
        if opt == "-i":
            intMode, plotNum = True, int(argv[i+1])
            print("Interactive mode selected. Use \"p\" for previous and \"q\" to exit.")
        if opt == "-x":
            dontUseTCuts = True
            print("DC TCuts deactivated.  Retaining all events ...")
        if opt == "-c":
            cutMode, customPar = True, str(argv[i+1])
            print("Using custom cut parameter: {}".format(customPar))
        if opt == "-b":
            batMode = True
            import matplotlib
            # if os.environ.get('DISPLAY','') == '':
                # print('No display found. Using non-interactive Agg backend')
            matplotlib.use('Agg')
            print("Batch mode selected.  A new file will be created.")
    import matplotlib.pyplot as plt
    from matplotlib import gridspec
    import matplotlib.ticker as mtick
    plt.style.use('pltTalks.mplstyle')
    from matplotlib.colors import LogNorm, Normalize

    # File I/O
    inFile, outFile, bltFile = TFile(), TFile(), TFile()
    gatTree, bltTree, out = TTree(), TTree(), TTree()
    theCut, inPath, outPath = "", "", ""

    # Set input and output files
    if rangeMode:
        inPath = "%s/waveSkimDS%d_%d.root" % (pathToInput, dsNum, subNum)
        outPath = "%s/latSkimDS%d_%d.root" % (pathToOutput, dsNum, subNum)
    if fileMode:
        inPath = "%s/waveSkimDS%d_run%d.root" % (pathToInput, dsNum, runNum)
        outPath = "%s/latSkimDS%d_run%d.root" % (pathToOutput, dsNum, runNum)
    if pathMode:
        inPath, outPath = manualInput, manualOutput
    if gatMode:
        ds = GATDataSet()
        gatPath = ds.GetPathToRun(runNum,GATDataSet.kGatified)
        bltPath = ds.GetPathToRun(runNum,GATDataSet.kBuilt)
        outPath = "%s/lat_run%d.root" % (pathToOutput, runNum)
    if pathMode and gatMode:
        outPath = manualOutput


    # Initialize trees
    if rangeMode or fileMode or pathMode:
        inFile = TFile(inPath)
        gatTree = inFile.Get("skimTree")
        print(gatTree.GetEntries(),"entries in input tree.")
    elif gatMode:
        inFile = TFile(gatPath)
        bltFile = TFile(bltPath)
        gatTree = inFile.Get("mjdTree")
        bltTree = bltFile.Get("MGTree")
        gatTree.AddFriend(bltTree)
    if singleMode:
        inFile = TFile(pathToInput)
        gatTree = inFile.Get("skimTree")

    # apply cut to tree
    if (rangeMode or fileMode or pathMode) and not dontUseTCuts:
        try:
            theCut = inFile.Get("theCut").GetTitle()
        except ReferenceError:
            theCut = ""
    if cutMode:
        # theCut += customPar
        # theCut = "(channel==672 || channel==674) && mH==2" # sync chan: 672, extp chan: 674
        # theCut += " && fitSlo < 10"
        # theCut = "trapENFCal > 1 && trapENFCal < 10 && riseNoise > 2"
        theCut = "trapENFCal > 20 && trapENFCal < 100 && riseNoise > 2"
        print("WARNING: Custom cut in use! : ",theCut)

    gatTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    gatTree.SetEntryList(elist)
    nList = elist.GetN()
    print("Using cut:\n",theCut)
    print("Found",gatTree.GetEntries(),"input entries.")
    print("Found",nList,"entries passing cuts.")

    # Output: In batch mode (-b) only, create an output file+tree & append new branches.
    if batMode and not intMode:
        outFile = TFile(outPath, "RECREATE")
        print("Attempting tree copy to",outPath)
        out = gatTree.CopyTree("")
        out.Write()
        print("Wrote",out.GetEntries(),"entries.")
        cutUsed = TNamed("theCut",theCut)
        cutUsed.Write()

    waveS1, waveS2 = std.vector("double")(), std.vector("double")()
    waveS3, waveS4, waveS5 = std.vector("double")(), std.vector("double")(), std.vector("double")()
    bcMax, bcMin = std.vector("double")(), std.vector("double")()
    bandMax, bandTime = std.vector("double")(), std.vector("double")()
    den10, den50, den90 = std.vector("double")(), std.vector("double")(), std.vector("double")()
    oppie = std.vector("double")()
    fitMu, fitAmp, fitSlo = std.vector("double")(), std.vector("double")(), std.vector("double")()
    fitTau, fitBL = std.vector("double")(), std.vector("double")()
    matchMax, matchWidth, matchTime = std.vector("double")(), std.vector("double")(), std.vector("double")()
    pol0, pol1, pol2, pol3 = std.vector("double")(), std.vector("double")(), std.vector("double")(), std.vector("double")()
    fails, fitChi2, fitLL = std.vector("int")(), std.vector("double")(), std.vector("double")()
    riseNoise = std.vector("double")()
    t0_SLE, t0_ALE, lat, latF = std.vector("double")(), std.vector("double")(), std.vector("double")(), std.vector("double")()
    latAF, latFC, latAFC = std.vector("double")(), std.vector("double")(), std.vector("double")()
    nMS = std.vector("int")()
    tE50, latE50, wfStd = std.vector("double")(), std.vector("double")(), std.vector("double")()
    wfAvgBL, wfRMSBL = std.vector("double")(), std.vector("double")()
    fitErr = std.vector("int")()

    # It's not possible to put the "out.Branch" call into a class initializer (waveLibs::latBranch). You suck, ROOT.
    b1, b2 = out.Branch("waveS1",waveS1), out.Branch("waveS2",waveS2)
    b3, b4, b5 = out.Branch("waveS3",waveS3), out.Branch("waveS4",waveS4), out.Branch("waveS5",waveS5)
    b7, b8 = out.Branch("bcMax",bcMax), out.Branch("bcMin",bcMin)
    b9, b10 = out.Branch("bandMax",bandMax), out.Branch("bandTime",bandTime)
    b11, b12, b13 = out.Branch("den10",den10), out.Branch("den50",den50), out.Branch("den90",den90)
    b14 = out.Branch("oppie",oppie)
    b15, b16, b17 = out.Branch("fitMu", fitMu), out.Branch("fitAmp", fitAmp), out.Branch("fitSlo", fitSlo)
    b18, b19 = out.Branch("fitTau",fitTau), out.Branch("fitBL",fitBL)
    b20, b21, b22 = out.Branch("matchMax", matchMax), out.Branch("matchWidth", matchWidth), out.Branch("matchTime", matchTime)
    b23, b24, b25, b26 = out.Branch("pol0", pol0), out.Branch("pol1", pol1), out.Branch("pol2", pol2), out.Branch("pol3", pol3)
    b27, b28, b29 = out.Branch("fails",fails), out.Branch("fitChi2",fitChi2), out.Branch("fitLL",fitLL)
    b30 = out.Branch("riseNoise",riseNoise)
    b31, b32, b33, b34 = out.Branch("t0_SLE",t0_SLE), out.Branch("t0_ALE",t0_ALE), out.Branch("lat",lat), out.Branch("latF",latF)
    b35, b36, b37 = out.Branch("latAF",latAF), out.Branch("latFC",latFC), out.Branch("latAFC",latAFC)
    b38 = out.Branch("nMS",nMS)
    b39, b40, b41 = out.Branch("tE50", tE50), out.Branch("latE50", latE50), out.Branch("wfStd", wfStd)
    b42, b43 = out.Branch("wfAvgBL", wfAvgBL), out.Branch("wfRMSBL", wfRMSBL)
    b44 = out.Branch("fitErr",fitErr)

    # make a dictionary that can be iterated over (avoids code repetition in the loop)
    brDict = {
        "waveS1":[waveS1, b1], "waveS2":[waveS2, b2],
        "waveS3":[waveS3, b3], "waveS4":[waveS4, b4], "waveS5":[waveS5, b5],
        "bcMax":[bcMax, b7], "bcMin":[bcMin, b8],
        "bandMax":[bandMax, b9], "bandTime":[bandTime, b10],
        "den10":[den10, b11], "den50":[den50, b12], "den90":[den90, b13],
        "oppie":[oppie, b14],
        "fitMu":[fitMu, b15], "fitAmp":[fitAmp, b16], "fitSlo":[fitSlo, b17],
        "fitTau":[fitTau, b18], "fitBL":[fitBL,b19],
        "matchMax":[matchMax, b20], "matchWidth":[matchWidth, b21], "matchTime":[matchTime, b22],
        "pol0":[pol0, b23], "pol1":[pol1, b24], "pol2":[pol2, b25], "pol3":[pol3, b26],
        "fails":[fails,b27], "fitChi2":[fitChi2,b28], "fitLL":[fitLL,b29],
        "riseNoise":[riseNoise,b30],
        "t0_SLE":[t0_SLE,b31], "t0_ALE":[t0_ALE,b32], "lat":[lat,b33], "latF":[latF,b34],
        "latAF":[latAF,b35], "latFC":[latFC,b36], "latAFC":[latAFC,b37],
        "nMS":[nMS,b38], "tE50":[tE50,b39], "latE50":[latE50,b40], "wfStd":[wfStd,b41],
        "wfAvgBL":[wfAvgBL,b42], "wfRMSBL":[wfRMSBL,b43],
        "fitErr":[fitErr,b44]
    }

    # Make a figure (-i option: select different plots)
    # fig = plt.figure(figsize=(12,9), facecolor='w')
    fig = plt.figure()
    if plotNum==0 or plotNum==7 or plotNum==8:
        p0 = plt.subplot(111)  # 0-raw waveform, 7-new trap filters
    elif plotNum==1 or plotNum==2:
        p0 = plt.subplot(211)  # 1-wavelet, 2-time points, bandpass filters, tail slope
        p1 = plt.subplot(212)
    elif plotNum==3:
        p0 = plt.subplot2grid((2,5), (0,0), colspan=3)  # oppie / freq-domain matched filter
        p1 = plt.subplot2grid((2,5), (0,3), colspan=2)
        p2 = plt.subplot2grid((2,5), (1,0), colspan=3)
    elif plotNum==4:
        p0 = plt.subplot(111)  # time-domain matched filter
    elif plotNum==5:
        p0 = plt.subplot(111)  # bandpass / bandTime
    elif plotNum==6:
        p0 = plt.subplot2grid((6,10), (0,0), colspan=10, rowspan=3) # waveform fit
        p1 = plt.subplot2grid((6,10), (3,0), colspan=10, rowspan=1) # residual
        p2 = plt.subplot2grid((6,10), (4,0), colspan=2, rowspan=2) # traces
        p3 = plt.subplot2grid((6,10), (4,2), colspan=2, rowspan=2)
        p4 = plt.subplot2grid((6,10), (4,4), colspan=2, rowspan=2)
        p5 = plt.subplot2grid((6,10), (4,6), colspan=2, rowspan=2)
        p6 = plt.subplot2grid((6,10), (4,8), colspan=2, rowspan=2)
    elif plotNum==9:
        p0 = plt.subplot2grid((5,1), (0,0)) # 9- wpt on wf fit residual
        p1 = plt.subplot2grid((5,1), (1,0), rowspan=2)
        p2 = plt.subplot2grid((5,1), (3,0), rowspan=2)
    if not batMode: plt.show(block=False)


    # Load a fast signal template - used w/ the freq-domain matched filter
    # print("Generating signal template ...")
    tSamp, tR, tZ, tAmp, tST, tSlo = 5000, 0, 15, 100, 2500, 10
    # tOrig, tOrigTS = wl.MakeSiggenWaveform(tSamp,tR,tZ,tAmp,tST,tSlo) # Damn you to hell, PDSF
    templateFile = np.load("%s/data/lat_template.npz" % os.environ['LATDIR'])
    if dsNum==2 or dsNum==6: templateFile = np.load("%s/data/lat_ds2template.npz" % os.environ['LATDIR'])
    tOrig, tOrigTS = templateFile['arr_0'], templateFile['arr_1']


    # Load stuff from DS1 forced acq. runs
    npzfile = np.load("%s/data/fft_forcedAcqDS1.npz" % os.environ['LATDIR'])
    noise_asd, noise_xFreq, avgPwrSpec, xPwrSpec, data_forceAcq, data_fft = npzfile['arr_0'],npzfile['arr_1'],npzfile['arr_2'],npzfile['arr_3'],npzfile['arr_4'],npzfile['arr_5']


    # Loop over events
    print("Starting event loop ...")
    iList = -1
    while True:
        iList += 1
        if intMode==True and iList != 0:
            value = input()
            if value=='q': break        # quit
            if value=='p': iList -= 2   # go to previous
            if (value.isdigit()):
                iList = int(value)      # go to entry number
        elif intMode==False and batMode==False:
            plt.pause(0.00001)          # rapid-draw mode
        if iList >= nList: break        # bail out, goose!

        entry = gatTree.GetEntryNumber(iList);
        gatTree.LoadTree(entry)
        gatTree.GetEntry(entry)
        nChans = gatTree.channel.size()
        event = MGTEvent()
        if gatMode: event = bltTree.event

        # Reset all branch vectors
        # NOTE: The events sometimes contain 'straggler' hits that do not pass the
        # given TCut.  This line sets ALL the new parameters to -88888 by default.
        # If you see this value in a plot, then you must be including hits that
        # passed the cut in wave-skim but did not pass the (different?) cut in LAT.
        for key in brDict: brDict[key][0].assign(nChans,-88888)
        brDict["fails"][0].assign(nChans,0) # set error code to 'true' by default
        errorCode = [0,0,0,0]


        # Loop over hits passing cuts
        numPass = gatTree.Draw("channel",theCut,"GOFF",1,iList)
        chans = gatTree.GetV1()
        chanList = list(set(int(chans[n]) for n in range(numPass)))
        hitList = (iH for iH in range(nChans) if gatTree.channel.at(iH) in chanList)  # a 'generator expression'
        for iH in hitList:

            # ------------------------------------------------------------------------
            # Waveform processing

            # load data
            run = gatTree.run
            chan = gatTree.channel.at(iH)
            dataENFCal = gatTree.trapENFCal.at(iH)
            dataENM = gatTree.trapENM.at(iH)
            dataTSMax = gatTree.trapENMSample.at(iH)*10. - 4000
            wf = MGTWaveform()
            iEvent = 0
            if gatMode:
                wf = event.GetWaveform(iH)
                iEvent = entry
            else:
                wf = gatTree.MGTWaveforms.at(iH)
                iEvent = gatTree.iEvent

            # print("%d:  run %d  chan %d  trapENFCal %.2f" % (iList, run, chan, dataENFCal))

            # be absolutely sure you're matching the right waveform to this hit
            if wf.GetID() != chan:
                print("ERROR -- Vector matching failed.  iList %d  run %d  iEvent %d" % (iList,run,iEvent))
                return

            # Let's start the show - grab a waveform.
            # Remove first 4 samples when we have multisampling
            # Remove last 2 samples to get rid of the ADC spike at the end of all wf's.
            truncLo, truncHi = 0, 2
            if dsNum==6 or dsNum==2: truncLo = 4
            signal = wl.processWaveform(wf,truncLo,truncHi)
            data = signal.GetWaveRaw()
            data_blSub = signal.GetWaveBLSub()
            dataTS = signal.GetTS()
            dataBL,dataNoise = signal.GetBaseNoise()

            # wavelet packet transform
            wp = pywt.WaveletPacket(data_blSub, 'db2', 'symmetric', maxlevel=4)
            nodes = wp.get_level(4, order='freq')
            wpCoeff = np.array([n.data for n in nodes],'d')
            wpCoeff = abs(wpCoeff)

            # wavelet parameters
            # First get length of wavelet on the time axis, the scale axis will always be the same
            # due to the number of levels in the wavelet
            wpLength = len(wpCoeff[1,:])
            waveS1[iH] = np.sum(wpCoeff[0:1,1:wpLength//4+1]) # python3 : floor division (//) returns an int
            waveS2[iH] = np.sum(wpCoeff[0:1,wpLength//4+1:wpLength//2+1])
            waveS3[iH] = np.sum(wpCoeff[0:1,wpLength//2+1:3*wpLength//4+1])
            waveS4[iH] = np.sum(wpCoeff[0:1,3*wpLength//4+1:-1])
            waveS5[iH] = np.sum(wpCoeff[2:-1,1:-1])
            S6 = np.sum(wpCoeff[2:9,1:wpLength//4+1])
            S7 = np.sum(wpCoeff[2:9,wpLength//4+1:wpLength//2+1])
            S8 = np.sum(wpCoeff[2:9,wpLength//2+1:3*wpLength//4+1])
            S9 = np.sum(wpCoeff[2:9,3*wpLength//4+1:-1])
            S10 = np.sum(wpCoeff[9:,1:wpLength//4+1])
            S11 = np.sum(wpCoeff[9:,wpLength//4+1:wpLength//2+1])
            S12 = np.sum(wpCoeff[9:,wpLength//2+1:3*wpLength//4+1])
            S13 = np.sum(wpCoeff[9:,3*wpLength//4+1:-1])
            sumList = [S6, S7, S8, S9, S10, S11, S12, S13]
            bcMax[iH] = np.max(sumList)
            bcMin[iH] = 1. if np.min(sumList) < 1 else np.min(sumList)

            # reconstruct waveform w/ only lowest frequency.
            new_wp = pywt.WaveletPacket(data=None, wavelet='db2', mode='symmetric')
            new_wp['aaa'] = wp['aaa'].data
            data_wlDenoised = new_wp.reconstruct(update=False)
            # resize in a smart way
            diff = len(data_wlDenoised) - len(data_blSub)
            if diff > 0: data_wlDenoised = data_wlDenoised[diff:]

            # waveform high/lowpass filters - parameters are a little arbitrary

            B1,A1 = butter(2, [1e5/(1e8/2),1e6/(1e8/2)], btype='bandpass')
            data_bPass = lfilter(B1, A1, data_blSub)

            # used in the multisite tagger
            B2, A2 = butter(1, 0.08)
            data_filt = filtfilt(B2, A2, data_blSub)
            data_filtDeriv = wl.wfDerivative(data_filt)
            filtAmp = np.amax(data_filtDeriv) # scale the max to match the amplitude
            data_filtDeriv = data_filtDeriv * (dataENM / filtAmp)

            B3, A3 = butter(2,1e6/(1e8/2), btype='lowpass')
            data_lPass = lfilter(B3, A3, data_blSub)

            idx = np.where((dataTS > dataTS[0]+100) & (dataTS < dataTS[-1]-100))
            windowingOffset = dataTS[idx][0] - dataTS[0]

            bandMax[iH] = np.amax(data_bPass[idx])
            bandTime[iH] = dataTS[ np.argmax(data_bPass[idx])] - windowingOffset


            # timepoints of low-pass waveforms
            tpc = MGWFTimePointCalculator();
            tpc.AddPoint(.2)
            tpc.AddPoint(.5)
            tpc.AddPoint(.9)
            mgtLowPass = wl.MGTWFFromNpArray(data_lPass)
            tpc.FindTimePoints(mgtLowPass)
            den10[iH] = tpc.GetFromStartRiseTime(0)*10
            den50[iH] = tpc.GetFromStartRiseTime(1)*10
            den90[iH] = tpc.GetFromStartRiseTime(2)*10


            # ================ xgauss waveform fitting ================

            amp, mu, sig, tau, bl = dataENM, dataTSMax, 600., -72000., dataBL
            floats = np.asarray([amp, mu, sig, tau, bl])
            temp = xgModelWF(dataTS, floats)
            if not batMode: MakeTracesGlobal()

            # get the noise of the denoised wf
            denoisedNoise,_,_ = wl.baselineParameters(data_wlDenoised)

            # NOTE: fit is to wavelet-denoised data, BECAUSE there are no HF components in the model,
            # AND we'll still calculate fitChi2 w/r/t the data, not the denoised data.
            # datas = [dataTS, data, dataNoise] # fit data
            datas = [dataTS, data_wlDenoised + dataBL, denoisedNoise] # fit wavelet-denoised data w/ Bl added back in

            # Set bounds - A,mu,sig,tau,bl.
            # bnd = ((None,None),(None,None),(None,None),(None,None),(None,None))   # often gets caught at sig=0
            bnd = ((None,None),(None,None),(2.,None),(-72001.,-71999.),(None,None)) # gets caught much less often.

            # L-BGFS-B with numerical gradient.
            start = time.clock()
            result = op.minimize(lnLike, floats, args=datas, method="L-BFGS-B", options=None, bounds=bnd)
            fitSpeed = time.clock() - start

            fitErr[iH] = 0
            if not result["success"]:
                # print("fit fail: ", result["message"])
                fitErr[iH] = 1
                errorCode[0] = 1

            amp, mu, sig, tau, bl = result["x"]

            # save parameters

            fitMu[iH], fitAmp[iH], fitSlo[iH], fitTau[iH], fitBL[iH] = mu, amp, sig, tau, bl
            floats = np.asarray([amp, mu, sig, tau, bl])
            fit = xgModelWF(dataTS, floats)

            # print("%d/%d iH %d  e %-10.2f  fs %-8.2f  f %d" % (iList, nList, iH, dataENFCal, fitSlo[iH], fitErr[iH]))

            # log-likelihood of this fit
            fitLL[iH] = result["fun"]

            # chi-square of this fit
            # Textbook is (observed - expected)^2 / expected,
            # but we'll follow MGWFCalculateChiSquare.cc and do (observed - expected)^2 / NDF.
            # NOTE: we're doing the chi2 against the DATA, though the FIT is to the DENOISED DATA.
            fitChi2[iH] = np.sum(np.square(data-fit)) / (len(data)-1)/dataNoise


            # get wavelet coeff's for rising edge only.  normalize to bcMin
            # view this w/ plot 1

            # find the window of rising edge
            fit_blSub = fit - bl
            fitMaxTime = dataTS[np.argmax(fit_blSub)]
            fitStartTime = dataTS[0]
            idx = np.where(fit_blSub < 0.1)
            if len(dataTS[idx] > 0): fitStartTime = dataTS[idx][-1]
            fitRiseTime50 = (fitMaxTime + fitStartTime)/2.

            # bcMin is 32 samples long in the x-direction.
            # if we make the window half as wide, it'll have the same # of coeff's as bcMin.
            # this is still 'cheating' since we're not summing over the same rows.
            numXRows = wpCoeff.shape[1]
            wpCtrRise = int((fitRiseTime50 - dataTS[0]) / (dataTS[-1] - dataTS[0]) * numXRows)
            wpLoRise = wpCtrRise - 8
            if wpLoRise < 0: wpLoRise = 0
            wpHiRise = wpCtrRise + 8
            if wpHiRise > numXRows: wpHiRise = numXRows

            # sum all HF wavelet components for this edge.
            riseNoise[iH] = np.sum(wpCoeff[2:-1,wpLoRise:wpHiRise]) / bcMin[iH]

            # print("%d %d %d %d e %-5.2f  bmax %-6.2f  bmin %-6.2f  mu %-5.2f  a %-5.2f  s %-5.2f  bl %-5.2f  rn %.2f" % (run,iList,iH,chan,dataENFCal,bcMax[iH],bcMin[iH],fitMu[iH],fitAmp[iH],fitSlo[iH],fitBL[iH],riseNoise[iH]))

            # =========================================================

            # optimal matched filter (freq. domain)
            # we use the pysiggen fast template (not the fit result) to keep this independent of the wf fitter.

            # pull in the template, shift it, and make sure it's the same length as the data
            guessTS = tOrigTS - 15000.
            idx = np.where((guessTS > -5) & (guessTS < dataTS[-1]))
            guessTS, guess = guessTS[idx], tOrig[idx]
            if len(guess)!=len(data):
                if len(guess)>len(data):
                    guess, guessTS = guess[0:len(data)], guessTS[0:len(data)]
                else:
                    guess = np.pad(guess, (0,len(data)-len(guess)), 'edge')
                    guessTS = np.pad(guessTS, (0,len(data)-len(guessTS)), 'edge')

            data_fft = np.fft.fft(data_blSub) # can also try taking fft of the low-pass data
            temp_fft = np.fft.fft(guess)

            datafreq = np.fft.fftfreq(data.size) * 1e8
            power_vec = np.interp(datafreq, noise_xFreq, noise_asd) # load power spectra from file

            # Apply the filter
            optimal = data_fft * temp_fft.conjugate() / power_vec
            optimal_time = 2 * np.fft.ifft(optimal)

            # Normalize the output
            df = np.abs(datafreq[1] - datafreq[0]) # freq. bin size
            sigmasq = 2 * (temp_fft * temp_fft.conjugate() / power_vec).sum() * df
            sigma = np.sqrt(np.abs(sigmasq))
            SNR = abs(optimal_time) / (sigma)
            oppie[iH] = np.amax(SNR)


            # time-domain matched filter.  use the baseline-subtracted wf as data, and fit_blSub too.

            # make a longer best-fit waveform s/t it can be shifted L/R.
            matchTS = np.append(dataTS, np.arange(dataTS[-1], dataTS[-1] + 20000, 10)) # add 2000 samples
            match = xgModelWF(matchTS, [amp, mu+10000., sig, tau, bl]) # shift mu accordingly
            match = match[::-1] - bl # time flip and subtract off bl

            # line up the max of the 'match' (flipped wf) with the max of the best-fit wf
            # this kills the 1-1 matching between matchTS and dataTS (each TS has some offset)
            matchMaxTime = matchTS[np.argmax(match)]
            matchTS = matchTS + (fitMaxTime - matchMaxTime)

            # resize match, matchTS to have same # samples as data, dataTS.
            # this is the only case we really care about
            # ("too early" and "too late" also happen, but the shift is larger than the trigger walk, making it unphysical)
            if matchTS[0] <= dataTS[0] and matchTS[-1] >= dataTS[-1]:
                idx = np.where((matchTS >= dataTS[0]) & (matchTS <= dataTS[-1]))
                match, matchTS = match[idx], matchTS[idx]
                sizeDiff = len(dataTS)-len(matchTS)
                if sizeDiff < 0:
                    match, matchTS = match[:sizeDiff], matchTS[:sizeDiff]
                elif sizeDiff > 0:
                    match = np.hstack((match, np.zeros(sizeDiff)))
                    matchTS = np.hstack((matchTS, dataTS[-1*sizeDiff:]))
                if len(match) != len(data):
                    print("FIXME: match filter array manip is still broken.")

            # compute match filter parameters
            matchMax[iH], matchWidth[iH], matchTime[iH] = -888, -888, -888
            if len(match)==len(data):
                smoothMF = gaussian_filter(match * data_blSub, sigma=5.)
                matchMax[iH] = np.amax(smoothMF)
                matchTime[iH] = matchTS[ np.argmax(smoothMF) ]
                idx = np.where(smoothMF > matchMax[iH]/2.)
                if len(matchTS[idx]>1):
                    matchWidth[iH] = matchTS[idx][-1] - matchTS[idx][0]


            # Fit tail slope to polynomial.  Guard against fit fails

            idx = np.where(dataTS >= fitMaxTime)
            tail, tailTS = data[idx], dataTS[idx]
            popt1,popt2 = 0,0
            try:
                popt1,_ = op.curve_fit(wl.tailModelPol, tailTS, tail)
                pol0[iH], pol1[iH], pol2[iH], pol3[iH] = popt1[0], popt1[1], popt1[2], popt1[3]
            except:
                # print("curve_fit tailModelPol failed, run %i  event %i  channel %i" % (run, iList, chan))
                errorCode[2] = 1
                pass

            # =========================================================

            # new trap filters.
            # params: t0_SLE, t0_ALE, lat, latF, latAF, latFC, latAFC

            # calculate trapezoids

            # standard trapezoid - prone to walking, less sensitive to noise.  use to find energy
            eTrap = wl.trapFilter(data_blSub, 400, 250, 7200.)
            eTrapTS = np.arange(0, len(eTrap)*10., 10)
            eTrapInterp = interpolate.interp1d(eTrapTS, eTrap)

            # short trapezoid - triggers more quickly, sensitive to noise.  use to find t0
            sTrap = wl.trapFilter(data_blSub, 100, 150, 7200.)
            sTrapTS = np.arange(0, len(sTrap)*10., 10)

            # asymmetric trapezoid - used to find the t0 only
            aTrap = wl.asymTrapFilter(data_blSub, 4, 10, 200, True) # (0.04us, 0.1us, 2.0us)
            aTrapTS = np.arange(0, len(aTrap)*10., 10)

            # find leading edges (t0 times)

            # limit the range from 0 to 10us, and use an ADC threshold of 1.0 as suggested by DCR
            t0_SLE[iH],_ = wl.walkBackT0(sTrap, eTrapTS[-1]+7000-4000-2000, 1., 0, 1000) # (in ns) finds leading edge from short trap
            t0_ALE[iH],_ = wl.walkBackT0(aTrap, eTrapTS[-1]+7000-4000-2000, 1., 0, 1000) # (in ns) finds leading edge from asymmetric trap

            # standard energy trapezoid w/ a baseline padded waveform
            data_pad = np.pad(data_blSub,(200,0),'symmetric')
            pTrap = wl.trapFilter(data_pad, 400, 250, 7200.)
            pTrapTS = np.linspace(0, len(pTrap)*10, len(pTrap))
            pTrapInterp = interpolate.interp1d(pTrapTS, pTrap)

            # calculate energy parameters
            # standard amplitude.  basically trapEM, but w/o NL correction if the input WF doesn't have it.
            lat[iH] = np.amax(eTrap)

            # Calculate DCR suggested amplitude, using the 50% to the left and right of the maximum point
            t0_F50,t0fail1 = wl.walkBackT0(pTrap, thresh=lat[iH]*0.5, rmin=0, rmax=len(pTrap)-1)
            t0_B50,t0fail2 = wl.walkBackT0(pTrap, thresh=lat[iH]*0.5, rmin=0, rmax=len(pTrap)-1, forward=True)
            t0_E50 = (t0_F50 + t0_B50)/2.0

            #TODO -- if it's necessary due to the trigger walk, we could potentially add a way to recursively increase the threshold until a timepoint is found, however it will still always fail for most noise events
            if not t0fail1 or not t0fail2:
                latE50[iH] = 0 # Set amplitude to 0 if one of the evaluations failed
            else:
                latE50[iH] = pTrapInterp(t0_E50) # Maybe I should call this latDCR50 to confuse people
            tE50[iH] = t0_B50 - t0_F50 # Save the difference between the middle points, can be used as a cut later

            # standard amplitude with t0 from the shorter traps
            # If either fixed pickoff time (t0) is < 0, use the first sample as the amplitude (energy).
            latF[iH] = eTrapInterp( np.amax([t0_SLE[iH]-7000+4000+2000, 0.]) ) # This should be ~trapEF
            latAF[iH] = eTrapInterp( np.amax([t0_ALE[iH]-7000+4000+2000, 0.]) )

            # amplitude from padded trapezoid, with t0 from short traps and a correction function
            # function is under development.  currently: f() = exp(p0 + p1*E), p0 ~ 7.8, p1 ~ -0.45 and -0.66
            # functional walk back distance is *either* the minimum of the function value, or 5500 (standard value)

            # t0_corr = -7000+6000+2000 # no correction
            t0_corr = -7000+6000+2000 - np.amin([np.exp(7.8 - 0.45*lat[iH]),1000.])
            t0A_corr = -7000+6000+2000 - np.amin([np.exp(7.8 - 0.66*lat[iH]),1000.])

            latFC[iH] = pTrapInterp( np.amax([t0_SLE[iH] + t0_corr, 0.]) )
            latAFC[iH] = pTrapInterp( np.amax([t0_ALE[iH] + t0A_corr, 0.]) )


            # =========================================================

            # the genius multisite event tagger - plot 8

            # decide a threshold
            dIdx = np.argmax(data_filtDeriv)
            dMax = data_filtDeriv[dIdx]
            dRMS,_,_ = wl.baselineParameters(data_filtDeriv)
            # msThresh = np.amax([dMax * .2, dRMS * 5.])
            # msThresh = dMax * .15
            msThresh = 50.  # I don't know.  this seems like a good value

            # run peak detect algorithm
            maxtab,_ = wl.peakdet(data_filtDeriv, msThresh)

            # profit
            msList = []
            for iMax in range(len(maxtab)):
                idx = int(maxtab[iMax][0])
                val = maxtab[iMax][1]
                msList.append(dataTS[idx])
                # print("%d  idx %d  TS %d  val %.2f  thresh %.2f" % (iList, idx, dataTS[idx], val, msThresh))
            nMS[iH] = len(maxtab)

            # =========================================================
            # wfStd analysis
            wfAvgBL[iH] = dataBL
            wfRMSBL[iH] = dataNoise
            wfStd[iH] = np.std(data[5:-5])

            # ------------------------------------------------------------------------
            # End waveform processing.

            # Calculate error code
            fails[iH] = 0
            for i,j in enumerate(errorCode):
                if j==1: fails[iH] += int(j)<<i
            # print("fails:",fails[iH])

            # Make plots!
            if batMode: continue
            if plotNum==0: # raw data
                p0.cla()
                p0.plot(dataTS,data,'b')
                p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f" % (run,iList,chan,dataENFCal))
                p0.set_xlabel("Time (ns)", ha='right', x=1.)
                p0.set_ylabel("Voltage (ADC)", ha='right', y=1.)

            if plotNum==1: # wavelet plot
                p0.cla()
                p0.margins(x=0)
                p0.plot(dataTS,data_blSub,color='blue',label='data (%.2f keV)' % dataENFCal)
                p0.plot(dataTS,data_wlDenoised,color='cyan',label='denoised',alpha=0.7)
                p0.axvline(fitRiseTime50,color='green',label='fit 50%',linewidth=2)
                p0.plot(dataTS,fit_blSub,color='red',label='bestfit',linewidth=2)
                # p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f  flo %.0f  fhi %.0f  fhi-flo %.0f" % (run,iList,chan,dataENFCal,fitStartTime,fitMaxTime,fitMaxTime-fitStartTime))
                p0.legend(loc='best')
                p0.set_xlabel("Time (ns)", ha='right', x=1.)
                p0.set_ylabel("Voltage (ADC)", ha='right', y=1.)

                p1.cla()
                p1.imshow(wpCoeff, interpolation='nearest', aspect="auto", origin="lower",extent=[0, 1, 0, len(wpCoeff)],cmap='viridis')
                p1.axvline(float(wpLoRise)/numXRows,color='orange',linewidth=2)
                p1.axvline(float(wpHiRise)/numXRows,color='orange',linewidth=2)
                # p1.set_title("waveS5 %.2f  bcMax %.2f  bcMin %.2f  riseNoise %.2f" % (waveS5[iH], bcMax[iH], bcMin[iH], riseNoise[iH]))
                # p1.set_xlabel("Time (%wf)", ha='right', x=1.)
                p1.set_ylabel("WPT Coefficients", ha='right', y=1.)

            if plotNum==2: # time points, bandpass filters, tail slope
                p0.cla()
                p0.plot(dataTS,data,color='blue',label='data')
                p0.axvline(den10[iH],color='black',label='lpTP')
                p0.axvline(den50[iH],color='black')
                p0.axvline(den90[iH],color='black')
                p0.plot(dataTS,fit,color='magenta',label='bestfit')
                if errorCode[2]!=1: p0.plot(tailTS, wl.tailModelPol(tailTS, *popt1), color='orange',linewidth=2, label='tailPol')
                p0.legend(loc='best')
                p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f" % (run,iEvent,chan,dataENFCal))

                p1.cla()
                p1.plot(dataTS,data_lPass,color='blue',label='lowpass')
                p1.plot(dataTS,data_filtDeriv,color='green',label='filtDeriv')
                p1.plot(dataTS,data_filt,color='black',label='filtfilt')
                p1.plot(dataTS,data_bPass,color='red',label='bpass')
                p1.axvline(bandTime[iH],color='orange',label='bandTime')
                p1.legend(loc='best')

            if plotNum==3: # freq-domain matched filter
                p0.cla()
                p0.plot(dataTS,data,'b')
                p0.plot(dataTS,temp,'r')
                p0.plot(dataTS,fit,color='cyan')
                p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f" % (run,iEvent,chan,dataENFCal))

                data_asd, data_xFreq = plt.psd(data, Fs=1e8, NFFT=2048, pad_to=2048, visible=False)
                temp_asd, temp_xFreq = plt.psd(temp, Fs=1e8, NFFT=2048, pad_to=2048, visible=False)

                p1.cla()
                p1.loglog(data_xFreq, np.sqrt(data_asd), 'b')
                p1.loglog(noise_xFreq, np.sqrt(noise_asd), 'g')
                p1.loglog(temp_xFreq, np.sqrt(temp_asd), 'r')
                p1.set_xlabel('Frequency (Hz)')
                p1.set_ylabel('ASD')
                p1.grid('on')

                p2.cla()
                p2.plot(dataTS, SNR)
                p2.set_title('oppie %.1f' % (oppie[iH]))
                p2.set_xlabel('Offset time (s)')
                p2.set_ylabel('SNR')

            if plotNum==4: # time domain match filter plot
                p0.cla()
                p0.plot(dataTS,data_blSub,color='blue',label='data',alpha=0.7)
                p0.plot(dataTS,fit_blSub,color='red',label='bestfit',linewidth=3)
                p0.axvline(matchTime[iH],color='orange',label='matchTime',linewidth=2)
                p0.plot(matchTS,smoothMF,color='magenta',label='smoothMF',linewidth=3)
                p0.plot(matchTS,match,color='cyan',label='match',linewidth=3)
                p0.set_xlabel('Time (s)')
                p0.set_ylabel('Voltage (arb)')
                p0.legend(loc='best')
                p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f  matchMax %.2f  matchTime %.2f  matchWidth %.2f" % (run,iEvent,chan,dataENFCal,matchMax[iH],matchTime[iH],matchWidth[iH]))

            if plotNum==5: # bandTime plot
                p0.cla()
                p0.plot(dataTS,data_blSub,color='blue',label='data',alpha=0.7)
                p0.plot(dataTS,data_lPass,color='magenta',label='lowpass',linewidth=4)
                p0.plot(dataTS,data_bPass,color='red',label='bpass',linewidth=4)
                p0.axvline(bandTime[iH],color='orange',label='bandTime',linewidth=4)
                p0.legend(loc='best')
                p0.set_xlabel('Time (ns)')
                p0.set_ylabel('ADC (arb)')
                p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f" % (run,iEvent,chan,dataENFCal))

            if plotNum==6: # waveform fit plot
                p0.cla()
                p0.plot(dataTS,data,color='blue',label='data')
                # p0.plot(dataTS,data_wlDenoised,color='cyan',label='wlDenoised',alpha=0.5)
                p0.plot(dataTS,temp,color='orange',label='xgauss guess')
                p0.plot(dataTS,fit,color='red',label='xgauss fit')
                p0.set_title("Run %d  evt %d  chan %d  trapENFCal %.1f  trapENM %.1f  deltaBL %.1f\n  amp %.2f  mu %.2f  sig %.2f  tau %.2f  chi2 %.2f  spd %.3f" % (run,iList,chan,dataENFCal,dataENM,dataBL-bl,amp,mu,sig,tau,fitChi2[iH],fitSpeed))
                p0.legend(loc='best')
                p1.cla()
                p1.plot(dataTS,data-fit,color='blue',label='residual')
                p1.legend(loc='best')
                p2.cla()
                p2.plot(ampTr[1:],label='amp',color='red')
                p2.legend(loc='best')
                p3.cla()
                p3.plot(muTr[1:],label='mu',color='green')
                p3.legend(loc='best')
                p4.cla()
                p4.plot(sigTr[1:],label='sig',color='blue')
                p4.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.1e'))
                p4.legend(loc='best')
                p5.cla()
                p5.plot(tauTr[1:],label='tau',color='black')
                p5.legend(loc='best')
                p6.cla()
                p6.plot(blTr[1:],label='bl',color='magenta')
                p6.legend(loc='best')

                print(gatTree.fitSlo.at(iH), sig)

            if plotNum==7: # new traps plot
                p0.cla()
                p0.plot(dataTS, data_blSub, color='blue', label='data')
                p0.plot(sTrapTS, sTrap, color='red', label='sTrap')
                p0.axvline(t0_SLE[iH], color='red')
                p0.plot(aTrapTS, aTrap, color='orange', label='aTrap')
                p0.axvline(t0_ALE[iH], color='orange')
                p0.plot(eTrapTS, eTrap, color='green', label='eTrap')
                p0.axhline(lat[iH],color='green')
                p0.plot(pTrapTS, pTrap, color='magenta', label='pTrap')
                p0.axhline(latAFC[iH], color='magenta')
                p0.axhline(latE50[iH], color='cyan')
                p0.set_title("trapENFCal %.2f  trapENM %.2f || latEM %.2f  latEF %.2f  latEAF %.2f  latEFC %.2f  latEAFC %.2f  latE50 %.2f" % (dataENFCal,dataENM,lat[iH],latF[iH],latAF[iH],latFC[iH],latAFC[iH], latE50[iH]))
                p0.legend(loc='best')

            if plotNum==8: # multisite tag plot
                p0.cla()
                p0.plot(dataTS, data_blSub, color='blue', label='data')
                p0.plot(dataTS, data_filtDeriv, color='red', label='filtDeriv')
                for mse in msList: p0.axvline(mse, color='green')
                p0.axhline(msThresh,color='red')
                p0.legend()

            if plotNum==9: # wavelet vs wf fit residual plot

                # wavelet packet transform on wf fit residual
                fitResid = data-fit
                wpRes = pywt.WaveletPacket(fitResid, 'db2', 'symmetric', maxlevel=4)
                nodesRes = wpRes.get_level(4, order='freq')
                wpCoeffRes = np.array([n.data for n in nodesRes], 'd')
                wpCoeffRes = abs(wpCoeffRes)
                R6 = np.sum(wpCoeffRes[2:9,1:wpLength//4+1])
                R7 = np.sum(wpCoeffRes[2:9,wpLength//4+1:wpLength//2+1])
                R8 = np.sum(wpCoeffRes[2:9,wpLength//2+1:3*wpLength//4+1])
                R9 = np.sum(wpCoeffRes[2:9,3*wpLength//4+1:-1])
                R10 = np.sum(wpCoeffRes[9:,1:wpLength//4+1])
                R11 = np.sum(wpCoeffRes[9:,wpLength//4+1:wpLength//2+1])
                R12 = np.sum(wpCoeffRes[9:,wpLength//2+1:3*wpLength//4+1])
                R13 = np.sum(wpCoeffRes[9:,3*wpLength//4+1:-1])
                RsumList = [R6, R7, R8, R9, R10, R11, R12, R13]
                bcMinRes = 1. if np.min(RsumList) < 1 else np.min(RsumList)
                riseNoiseRes = np.sum(wpCoeffRes[2:-1,wpLoRise:wpHiRise]) / bcMinRes
                rnCut = 1.1762 + 0.00116 * np.log(1 + np.exp((dataENFCal-7.312)/0.341))

                p0.cla()
                p0.margins(x=0)
                p0.plot(dataTS,data_blSub,color='blue',label='data')
                # p0.plot(dataTS,data_wlDenoised,color='cyan',label='denoised',alpha=0.7)
                # p0.axvline(fitRiseTime50,color='green',label='fit 50%',linewidth=2)
                p0.plot(dataTS,fit_blSub,color='red',label='bestfit',linewidth=2)
                # p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f  flo %.0f  fhi %.0f  fhi-flo %.0f" % (run,iList,chan,dataENFCal,fitStartTime,fitMaxTime,fitMaxTime-fitStartTime))
                # p0.legend(loc='best')
                p0.set_title("Run %d  Entry %d  Channel %d  ENFCal %.2f  flo %.0f  fhi %.0f  fhi-flo %.0f  approxFitE %.2f" % (run,iList,chan,dataENFCal,fitStartTime,fitMaxTime,fitMaxTime-fitStartTime,fitAmp[iH]*0.4))

                p1.cla()
                p1.plot(dataTS,fitResid,color='blue')

                p2.cla()
                p2.set_title("riseNoise %.2f  rnCut %.2f  riseNoiseRes %.2f  bcMinRes %.2f  bcMin %.2f  max %.2f" % (riseNoise[iH],rnCut,riseNoiseRes,bcMinRes,bcMin[iH],wpCoeffRes.max()))
                p2.imshow(wpCoeffRes, interpolation='nearest', aspect="auto", origin="lower",extent=[0, 1, 0, len(wpCoeff)],cmap='viridis')

            plt.tight_layout()
            plt.pause(0.000001)
            # ------------------------------------------------------------------------

        # End loop over hits, fill branches
        if batMode:
            for key in brDict:
                brDict[key][1].Fill()
            if iList%5000 == 0 and iList!=0:
                out.Write("",TObject.kOverwrite)
                print("%d / %d entries saved (%.2f %% done), time: %s" % (iList,nList,100*(float(iList)/nList),time.strftime('%X %x %Z')))

    # End loop over events
    if batMode and not intMode:
        out.Write("",TObject.kOverwrite)
        print("Wrote",out.GetBranch("channel").GetEntries(),"entries in the copied tree,")
        print("and wrote",b1.GetEntries(),"entries in the new branches.")

    stopT = time.clock()
    print("Stopped:",time.strftime('%X %x %Z'),"\nProcess time (min):",(stopT - startT)/60)
    print(float(nList)/((stopT-startT)/60.),"entries per minute.")
Example #19
0
def main(argv):
    """ Get a sweet minimizer + time domain match filter working. Also graduate. """
    scanSpeed = 1.
    iList = -1
    opt1 = ""
    intMode = False
    if (len(argv) >= 1): opt1 = argv[0]
    if "-i" in (opt1): intMode = True

    # Set input data and cuts
    inputFile = TFile("~/project/match-skim/waveletSkimDS5_run23920.root") # calibration
    # inputFile = TFile("~/project/v2-processwfs/waveletSkimDS5_90.root") # noisy BG
    waveTree = inputFile.Get("skimTree")
    theCut = inputFile.Get("cutUsedHere").GetTitle()
    # theCut += " && waveS5/trapENFCal < 1200 && trapENFCal < 10"
    theCut += " && trapENFCal < 30"

    # Print cut and events passing cut
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Using cut:\n",theCut,"\n"
    print "Found",waveTree.GetEntries(),"input entries."
    print "Found",nList,"entries passing cuts."

    # Make a figure
    fig = plt.figure(figsize=(15,10), facecolor='w')
    p1 = plt.subplot2grid((6,7), (0,0), colspan=4, rowspan=3) # data & fit
    p2 = plt.subplot2grid((6,7), (3,0), colspan=4, rowspan=3) # matched filter
    p3 = plt.subplot2grid((6,7), (0,4), colspan=3, rowspan=2) # trace 1
    p4 = plt.subplot2grid((6,7), (2,4), colspan=3, rowspan=2) # trace 2
    p5 = plt.subplot2grid((6,7), (4,4), colspan=3, rowspan=2) # trace 3
    plt.show(block=False)

    # Make template(s)
    tSamp, tR, tZ, tAmp, tST, tSlo = 5000, 0, 15, 100, 2500, 10
    tOrig, tOrigTS = wl.MakeSiggenWaveform(tSamp,tR,tZ,tAmp,tST,tSlo)

    # Loop over events
    while True:
        saveMe = False
        iList += 1
        if intMode==True and iList != 0:
            value = raw_input()
            if value=='q': break
            if value=='s': saveMe=True
            if value=='p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value) # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList);
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        numPass = waveTree.Draw("channel",theCut,"GOFF",1,iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans) if waveTree.channel.at(iH) in chanList)  # a 'generator expression'
        for iH in hitList:

            # ------------------------------------------------------------------------

            # Load data
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            dataE = waveTree.trapENFCal.at(iH)
            dataENM = waveTree.trapENM.at(iH)
            # dataMax = waveTree.trapENMSample.at(iH)*10. - 4000
            dataMax = waveTree.rt90.at(iH)
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH))
            data = signal.GetWaveBLSub()
            dataTS = signal.GetTS()
            dataBL, dataNoise = signal.GetBaseNoise()
            print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f  len %d" % (iList,nList,run,nChans,chan,dataE,len(data))

            # Load and scale template
            temp, tempTS = tOrig, tOrigTS
            temp = temp * (dataENM / tAmp)         # scale by amplitudes (not energies)
            tempMax = np.argmax(temp) * 10         # convert to ns
            tempTS = tempTS - (tempMax - dataMax)  # align @ max of rising edge
            tempMax = tempTS[np.argmax(temp)]      # get the new max TS after the shifting
            tempE = dataE # set 'calibrated' energy of template equal to data's trapENFCal.

            # Lowpass or bandpass filter the data
            # NOTE: This is tough.  There might be a feature due to rising edges, between 3e6 and 5e6 Hz.
            #       But that's only from data. Doing it w/ siggen templates yielded squat.
            # B,A = sig.butter(2, [3e6/(1e8/2),5e6/(1e8/2)], btype='bandpass')
            B,A = sig.butter(2,1e6/(1e8/2),btype='lowpass') # nice lowpass filter
            data_LowPass = sig.lfilter(B, A, data)
            B1,A1 = sig.butter(2, [1e5/(1e8/2),1e6/(1e8/2)], btype='bandpass') # attempt at bandpass
            data_BanPass = sig.lfilter(B1, A1, data)


            # -- Run minimizers

            # Set window and parameters
            loWin, hiWin = dataTS[0], dataTS[-1]
            mt, en, slo = dataMax-5, dataE+1, 20.  # guesses
            # print "guesses:        mt %.0f  en %.3f  slo %.2f" % (mt, en, slo)

            # pack into lists
            InterpFn = interpolate.interp1d(tempTS, temp, kind="linear", copy="False", assume_sorted="True")
            dataList = [data, dataTS, dataE, dataMax, loWin, hiWin, dataNoise]
            tempList = [temp, tempTS, tempE, tempMax]
            datas = [dataList, tempList, InterpFn]
            floats = [mt,en,slo]
            guess, guessTS = wm.MakeModel(dataList, tempList, floats, fn=InterpFn)

            start = time.clock()
            MakeTracesGlobal()

            fitFail = False # you should output this to ROOT

            # 0. brute - trying to make a quick initial guess for the slowness parameter
            # FIXME: this keeps returning the lowest allowed value for slowness.
            # bruteArgs = [en, datas]
            # ranges = (slice(dataMax-500,dataMax+300,100), slice(1,100,10))
            # resbrute = op.brute(bruteLnLike, ranges, args=(bruteArgs,), full_output=False, finish=None, disp=False)
            # mt, slo = resbrute[0], resbrute[1]
            # print "brute results:  mt %.0f  en %.3f  slo %.2f" % (mt, en, slo)
            # floats = [mt, en, slo]

            # 1. nelder-mead (~0.5 sec).  nobody does it better.  works almost like magic.
            result = op.minimize(findLnLike, floats, args=datas, method="Nelder-Mead")#,options={"maxiter":10})
            if not result["success"]:
                print "fit 'fail': ", result["message"]
                fitFail = True
            mt, en, slo = result["x"]
            # print "nelder results: mt %.0f  en %.3f  slo %.2f" % (mt, en, slo)
            nelder, nelderTS = wm.MakeModel(dataList, tempList, [mt,en,slo], fn=InterpFn)
            nelderStop = time.clock()

            # 2. powell "polish step" (~0.1 sec).  Sometimes screws up Nelder's good results!
            # floats = [mt,en,slo]
            # powell = op.minimize(findLnLike, floats, args=datas, method="Powell")
            # if not powell["success"]:
            #     fitFail= True
            #     print powell["message"]
            # mt, en, slo = powell["x"]
            # # print "powell results: mt %.0f  en %.3f  slo %.2f" % (mt, en, slo)
            # model, modelTS = wm.MakeModel(dataList, tempList, [mt,en,slo], fn=InterpFn)
            #
            # powellStop = time.clock()
            # print "Time: nelder %.3f  powell %.3f  total %.3f" % (nelderStop-start, powellStop-nelderStop, powellStop-start)

            # take absolute values for parameters
            mt, en, slo = abs(mt), abs(en), abs(slo)

            model, modelTS = wm.MakeModel(dataList, tempList, [mt,en,slo], fn=InterpFn)


            # compute a trap energy off the model (need pinghan's calibration constants)
            trap = np.zeros(1000)
            trap = np.append(trap,wl.trapezoidalFilter(model))
            trapTS = modelTS
            trapMax = np.amax(trap)



            # -- Time domain match filter

            match, matchTS = wm.MakeModel(dataList, tempList, [mt,en,slo], opt="nowindow")
            match = np.flip(match,0)

            # line up the max of the match with the max of the best-fit signal
            modelMaxTime = modelTS[np.argmax(model)]
            matchMaxTime = matchTS[np.argmax(match)]
            matchTS = matchTS + (modelMaxTime - matchMaxTime)

            idx = np.where((matchTS >= dataTS[0]-5) & (matchTS <= dataTS[-1]+5))
            match, matchTS = match[idx], matchTS[idx]

            # make sure match is same length as data, then compute convolution and parameters
            matchMax, matchWidth, matchArea = 0, 9999, 0
            smoothMF = np.zeros(len(dataTS))
            if len(match)!=len(data):
                print "array mismatch: len match %i  len data %i " % (len(match),len(data))
            else:
                # I can't decide which of these is better.
                # smoothMF = gaussian_filter(match * data, sigma=float(5))
                smoothMF = gaussian_filter(match * data_LowPass,sigma=float(5))

                # computer AWESOME match filter parameters
                matchMax = np.amax(smoothMF)
                idx = np.where(smoothMF > matchMax/2.)
                matchWidth = matchTS[idx][-1] - matchTS[idx][0]
                matchArea = np.sum(match[idx]) / float(len(match[idx]))


            # Plot data and template
            p1.cla()
            p1.plot(dataTS,data,'b',label='data')
            idx2 = np.where((tempTS >= dataTS[0]-5) & (tempTS <= dataTS[-1]+5))
            p1.plot(tempTS[idx2],temp[idx2],'r',label='template')
            # p1.plot(dataTS, data_LowPass, label='lowpass')
            # p1.plot(dataTS, data_BanPass, label='bandpass')
            p1.plot(trapTS,trap,color='k',label='bestfit-trap')
            p1.plot(nelderTS,nelder,color='cyan',label='bestfit')
            # p1.plot(modelTS,model,color='magenta',label='powells')
            p1.set_xlabel('Time (s)')
            p1.set_ylabel('Voltage (arb)')
            p1.set_title("Run %i  Ch %i  E %.2f  ENM %.2f  trapMax %.2f" % (run,chan,dataE,dataENM,trapMax))
            p1.legend(loc=4)

            p2.cla()
            p2.plot(dataTS,data,'b',alpha=0.8,label='data')
            # p2.plot(guessTS,guess,'y',alpha=0.8,label='guess')
            p2.plot(matchTS,match,'k',label='match')
            p2.plot(modelTS,model,color='orange',label='model')

            p2.plot(dataTS,data_LowPass,'r',label='lowpass')

            if len(match)==len(data): p2.plot(matchTS,smoothMF,'g',label='smoothMF')

            p2.axvline(matchTS[idx][-1],color='green',alpha=0.7)
            p2.axvline(matchTS[idx][0],color='green',alpha=0.7)

            p2.set_title("mMax %.2f  mWidth %.2f  mAreaNorm %.2f  mM/mW %.4f" % (matchMax,matchWidth,matchArea,matchMax/matchWidth))
            p2.legend(loc=4)


            # plot traces
            p3.cla()
            p3.set_title("maxTime %.1f  Energy %.2f  Slow %.1f" % (mt,en,slo))
            p3.plot(mtTrace[1:])
            p3.set_ylabel('maxTime')
            p4.cla()
            p4.plot(enTrace[1:])
            p4.set_ylabel('energy')
            p5.cla()
            p5.plot(sloTrace[1:])
            p5.set_ylabel('slowness')

            plt.tight_layout()
            plt.pause(scanSpeed)
Example #20
0
def main(argv):
    scanSpeed = 0.0001
    opt1, opt2 = "", ""
    intMode, batMode = False, False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print "Interactive mode selected."
    if "-b" in (opt1,opt2):
        batMode = True
        print "Batch mode selected."

    # Input: forced acquisition runs
    gatFile = TFile("~/project/mjddatadir/gatified/mjd_run13071.root")
    bltFile = TFile("~/project/mjddatadir/built/OR_run13071.root")
    waveTree = gatFile.Get("mjdTree")
    bltTree = bltFile.Get("MGTree")
    waveTree.AddFriend(bltTree)
    print "Found",waveTree.GetEntries(),"input entries."

    # Set cuts
    theCut = "rawWFMax < 200 && rawWFMin > -20"
    theCut += " && Entry$ < 10000"
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Using cut:\n",theCut,"\n"
    print "Found",nList,"entries passing cuts."

    # Loop figure (diagnostic)
    fig1 = plt.figure(figsize=(8,5), facecolor='w')
    p1 = plt.subplot(211)
    p2 = plt.subplot(212)
    if not batMode: plt.show(block=False)

    # Quantities to write to file
    avgPsd, xPsd = 0, 0 # pyplot.psd
    avgPwrSpec, xPwrSpec = 0, 0 # wl.fourierTransform
    data_forceAcq = 0 # single baseline
    data_fft = 0 # fft of single baseline

    nWF = 0
    ents = elist.GetN()

    # Loop over events
    iList = -1
    while(True):
        iList += 1
        if intMode==True and iList !=0:
            value = raw_input()
            if value=='q': break
            if value=='p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value) # go to entry
        if iList >= ents: break

        # print progress
        if (np.fabs((float(iList)/ents)%0.1) < 0.001):
            print "%i done" % (100*iList/ents), np.fabs(float(iList)/ents)%0.1

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        numPass = waveTree.Draw("channel",theCut,"GOFF",1,iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))
        event = bltTree.event  # grab waveforms from built data

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans) if waveTree.channel.at(iH) in chanList)  # a 'generator expression'
        for iH in hitList:

            # Get signal
            signal = wl.processWaveform(event.GetWaveform(iH)) # use when we have gat+blt data
            data = signal.GetWaveBLSub()
            dataTS = signal.GetTS() * 10.

            # Get power spectrum
            xPwrSpec,_,ypwr = wl.fourierTransform(data)
            avgPwrSpec += ypwr
            nWF += 1

            # Get full FFT (real, cplx)
            data_fft = np.fft.fft(data)
            data_forceAcq = data

            # power spectral density
            psd, xPsd = plt.psd(data, Fs=1e8, NFFT=2048, pad_to=2048, visible=True)
            # avgPsd += np.sqrt(psd)
            avgPsd += psd

            # Fill the figure
            if not batMode:
                p1.cla()
                p1.plot(dataTS,data,color='blue')
                p2.cla()
                plt.yscale('log')
                # p2.plot(xPwrSpec,avgPwrSpec,color='blue')
                p2.loglog(xPsd,avgPsd,color='blue')
                plt.pause(scanSpeed)


    # Plot average power spectrum
    fig2 = plt.figure(figsize=(8,5), facecolor='w')
    p3 = plt.subplot(111)
    plt.yscale('log')
    # plt.xscale('log')
    p3.set_xlabel("frequency")
    avgPwrSpec /= nWF
    idx = np.where(xPwrSpec > 10000) # low frequency cutoff
    p3.plot(xPwrSpec[idx],avgPwrSpec[idx],color='blue')
    fig2.savefig("./plots/powerSpectrum_run13071_linscale.pdf")

    # Get noise power density
    print "noise power density N_0: ", np.sum(avgPwrSpec[idx])

    # Plot power spectral density
    avgPsd /= nWF
    p3.cla()
    p3.loglog(xPsd,avgPsd,color='blue')
    fig2.savefig("./plots/psd_run13071.pdf")

    # Save stuff to file for optimal matched filter (ligo-mjd.py)
    np.savez("./data/fft_forcedAcqDS1.npz",avgPsd,xPsd,avgPwrSpec,xPwrSpec,data_forceAcq,data_fft)
Example #21
0
def main(argv):

    intMode, batMode = True, False
    for i,opt in enumerate(argv):
        if opt == "-b":
            intMode, batMode = False, True

    # set D and R
    nBL = 512
    D = 100
    R = 80
    # lo = 80

    gFile = TFile("~/project/v2-waveskim/waveSkimDS5_90.root")
    gatTree = gFile.Get("skimTree")

    # Select a NOISE POPULATION
    theCut = gFile.Get("theCut").GetTitle()
    theCut += " && trapENFCal < 2 && channel!=692 && channel!=1232"
    theCut += " && Entry$ < 10000"

    gatTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    gatTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Using cut:\n",theCut
    print "Found",gatTree.GetEntries(),"input entries."
    print "Found",nList,"entries passing cuts."

    nWF = 0
    rhoNoise = np.zeros([D,D])
    for iList in range(nList):
        entry = gatTree.GetEntryNumber(iList);
        gatTree.LoadTree(entry)
        gatTree.GetEntry(entry)
        nChans = gatTree.channel.size()
        numPass = gatTree.Draw("channel",theCut,"GOFF",1,iList)
        chans = gatTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))
        hitList = (iH for iH in xrange(nChans) if gatTree.channel.at(iH) in chanList)
        for iH in hitList:
            run = gatTree.run
            iEvent = gatTree.iEvent
            chan = gatTree.channel.at(iH)
            dataENF = gatTree.trapENFCal.at(iH)
            wf = gatTree.MGTWaveforms.at(iH)
            # print "%d:  run %d  chan %d  trapENFCal %.2f" % (iList, run, chan, dataENF)

            signal = wl.processWaveform(wf)
            data = signal.GetWaveBLSub()
            data = data[:nBL]
            binned, nBin = BinData(data,D)
            for vec in binned:
                out = np.outer(vec,vec)
                rhoNoise = np.add(rhoNoise, out)
            nWF += nBin

    # fig = plt.figure(figsize=(9,7), facecolor='w')
    # plt.imshow(rhoNoise,cmap='jet')
    # plt.colorbar()
    # plt.tight_layout()
    # plt.show()


    # ==========================================================
    # ============ Construct the KLJ/Ralston filter ============

    rhoNoise /= nWF
    eigenvals, eigenvectors = lin.eig(rhoNoise)  # eigenvectors are returned normalized.

    eigenDict = {}
    for i in range(len(eigenvals)):
        eigenDict[eigenvals[i]] = eigenvectors[i]

    # Sort the states by the np.absolute value (hopefully that's same as sorting by noise power)
    eigenSorted = sorted(eigenvals, key=lambda eigenval: np.absolute(eigenval), reverse=True)
    # for eig in eigenSorted: print np.absolute(eig), eig
    # print len(eigenSorted)

    # Now construct filters for different ranks R:
    filterDict = {}

    for i in range(len(eigenSorted)):
    # for i in range(R+1): # don't calculate too many levels
        evec = eigenDict[eigenSorted[i]]
        pia = np.outer(evec,evec)
        filterDict[i] = pia

    piNoise = filterDict[R]
    for i in range(R+1,D): piNoise += filterDict[i]

    piSignal = np.identity(D) - piNoise
    # piSignal = piNoise # crazy test

    # fig = plt.figure(figsize=(9,7), facecolor='w')
    # plt.imshow(piSignal,cmap='jet')
    # plt.colorbar()
    # plt.tight_layout()
    # plt.show()


    # ==========================================================


    # Now that we've got the filter matrix, loop back over the data.
    gFile.Close() # it's f*****g stupid I have to close and reopen.

    gFile = TFile("~/project/v2-waveskim/waveSkimDS5_90.root")
    gatTree = gFile.Get("skimTree")

    # Select a SIGNAL POPULATION
    theCut = gFile.Get("theCut").GetTitle()
    theCut += " && trapENFCal > 2 && trapENFCal < 10"

    gatTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    gatTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Second pass using cut:\n",theCut
    print "Found",gatTree.GetEntries(),"input entries."
    print "Found",nList,"entries passing cuts."

    fig = plt.figure(figsize=(8,6),facecolor='w')
    p1 = plt.subplot(111)
    # p2 = plt.subplot(212)
    plt.show(block=False)

    # Begin loop over events
    iList = -1
    while True:
        iList += 1
        if intMode and iList != 0:
            value = raw_input()
            if value=='q': break        # quit
            if value=='p': iList -= 2   # go to previous
            if (value.isdigit()):
                iList = int(value)      # go to entry number
        elif not intMode and batMode:
            plt.pause(0.001)            # rapid-draw mode
        if iList >= nList: break        # bail out, goose!

        entry = gatTree.GetEntryNumber(iList);
        gatTree.LoadTree(entry)
        gatTree.GetEntry(entry)
        nChans = gatTree.channel.size()

        numPass = gatTree.Draw("channel",theCut,"GOFF",1,iList)
        chans = gatTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))
        hitList = (iH for iH in xrange(nChans) if gatTree.channel.at(iH) in chanList)  # a 'generator expression'
        for iH in hitList:

            run = gatTree.run
            iEvent = gatTree.iEvent
            chan = gatTree.channel.at(iH)
            dataENF = gatTree.trapENFCal.at(iH)
            wf = gatTree.MGTWaveforms.at(iH)
            print "%d:  run %d  chan %d  trapENFCal %.2f" % (iList, run, chan, dataENF)

            signal = wl.processWaveform(wf)
            data = signal.GetWaveBLSub()
            dataTS = signal.GetTS()

            # partition the data into 'bins' - filter is applied to each, individually
            # filter matrix is D x D.
            # inside bins, timing resolution of order D * (sampling frequency) is expected.
            # apply the filter to the subspaces
            # transform back

            binned, nBin = BinData(data,D)
            filtBins = []
            for vec in binned:
                filtBins.append( piSignal.dot(vec) ) # dot product

            filtData = np.zeros(len(data))
            for i in range(len(filtData)):
                j, k = int(i/D), i%D
                filtData[i] = filtBins[j][k]


            # show the data
            p1.cla()
            p1.plot(dataTS,filtData,color='red',label='filt')
            p1.plot(dataTS,data,color='blue',alpha=0.7,label='data')
            p1.legend(loc=4)


            plt.tight_layout()
            plt.pause(0.0000001)
Example #22
0
def checkWave():
    """ ./check-files.py [-c] -w """
    print("Checking waves.  Cal?", checkCal)

    fileList = []

    # bkg
    if not checkCal:
        dsMap = bkg.dsMap()
        for ds in dsMap:
            for sub in range(dsMap[ds] + 1):
                fname = "%s/waveSkimDS%d_%d.root" % (dsi.waveDir, ds, sub)
                if os.path.isfile(fname):
                    fileList.append(fname)
                else:
                    print("File not found:", fname)
                    continue
    # cal
    else:
        for key in cal.GetKeys():
            ds = int(key[2])
            if skipDS6Cal and ds == 6: continue
            for cIdx in range(cal.GetIdxs(key)):  # 0-indexed
                cRuns = cal.GetCalList(key, cIdx)
                for run in cRuns:
                    fname = "%s/waveSkimDS%d_run%d.root" % (dsi.calWaveDir, ds,
                                                            run)
                    if os.path.isfile(fname):
                        fileList.append(fname)
                    else:
                        print("File not found:", fname)
                        continue
    if testMode:
        fileList = []
        ds = 1
        dsMap = bkg.dsMap()
        for sub in range(dsMap[ds] + 1):
            fname = "%s/waveSkimDS%d_%d.root" % (dsi.waveDir, ds, sub)
            fileList.append(fname)

    # check first and last few entries of every file
    for idx, fname in enumerate(fileList[:fLimit]):
        f = TFile(fname)
        t = f.Get("skimTree")
        n = t.GetEntries()

        if n == 0:
            print("No entries in file", fname)
            continue

        brSingle, brVector = [], []
        for br in t.GetListOfBranches():
            if "vector" in br.GetClassName():
                brVector.append(br.GetName())
            else:
                brSingle.append(br.GetName())

        if n < 20:
            eList = np.arange(0, n, 1)
        else:
            eList = np.arange(0, 20, 1)
            eList = np.append(eList, np.arange(n - 20, n, 1))

        for i in eList:
            t.GetEntry(i)

            # make sure individual entries are accessible (no segfaults)
            for br in brSingle:
                val = getattr(t, br)
                # print(val)
            for br in brVector:
                try:
                    nCh = getattr(t, br).size()
                except AttributeError:
                    print("Error:", br)
                for j in range(nCh):
                    val = getattr(t, br)[j]
                    # print(br,nCh,val)

            # make sure we can process waveforms
            for j in range(nCh):
                wf = t.MGTWaveforms.at(j)
                ch = t.channel.at(j)

                # be absolutely sure you're matching the right waveform to this hit
                if wf.GetID() != ch:
                    print(
                        "ERROR -- Vector matching failed. entry %d, file: %s" %
                        (i, fname))

                # run the LAT routine to convert into numpy arrays
                truncLo, truncHi = 0, 2
                if ds == 6 or ds == 2: truncLo = 4
                signal = wl.processWaveform(wf, truncLo, truncHi)

        if verbose:
            print("%d/%d  %s  nEnt %d" % (idx, len(
                fileList[:fLimit]), fname.split("/")[-1], t.GetEntries()))

        f.Close()
Example #23
0
def main(argv):
    """ Interactive-fit or 'rapid'-fit waveforms that pass a given TCut.
        BUG: Doesn't always work with a TChain.  Add input files together
        with hadd and use a single TFile.
    """
    scanSpeed = 0.2
    iList = -1
    opt1, opt2 = "", "-"
    intMode = False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print "Interactive mode selected."

    startT = time.clock()

    # Load template waveforms
    templateFile = TFile("./data/wave-m1cal.root")
    waveTemplates = templateFile.Get("waveTree")
    calDict = {640:28, 672:18, 610:16, 580:19, 582:34, 648:38, 600:21, 578:39, 592:27, 664:55, 626:62, 692:8, 598:22, 690:52, 632:9, 608:7}
    # PlotTemplateWaveforms(waveTemplates,calDict)
    # return

    # Set input data and cuts
    inputFile = TFile("~/project/wavelet-skim/hadd/waveletSkimDS3.root")
    # inputFile = TFile("~/project/wavelet-skim/waveletSkimDS3_13.root")
    waveTree = inputFile.Get("skimTree")
    print "Found",waveTree.GetEntries(),"input entries."

    # theCut = inputFile.Get("cutUsedHere").GetTitle()

    # DS3 big cut
    theCut = "trapENFCal > 0.8 && gain==0 && mHClean==1 && isGood && !muVeto && !wfDCBits && !isLNFill1 && !isLNFill2 && trapETailMin < 0 && channel!=596 && channel!=676 && channel!=676 && channel!=612 && channel!=1104 && channel!=1200 && channel!=1334 && channel!=1336 && tOffset < 10 && waveS5/TMath::Power(trapENFCal,1/4) < 1200 && (waveS3-waveS2)/trapENFCal > 100 && (waveS3-waveS2)/trapENFCal < 300 && !(channel==692 && (run==16974 || run==16975 || run==16976 || run==16977 || run==16978 || run==16979)) && butterTime < 11000"

    # theCut += " && trapENFCal > 2 && trapENFCal < 2.1 && channel==578 && run==16868"  # template fast WF (2kev)
    theCut += " && trapENFCal > 7 && trapENFCal < 10"
    # theCut += " && trapENFCal < 20 && trapENFCal > 2 && run > 17480"
    # theCut += " && kvorrT/trapENFCal > 2.2 && trapENFCal > 2 && trapENFCal < 10"

    # Print cut and events passing cut
    print "Using cut:\n",theCut,"\n"
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Found",nList,"entries passing cuts."

    stopT=time.clock()
    print "Data loading time (s): ", (stopT-startT)

    # Make a figure
    fig = plt.figure(figsize=(11,7), facecolor='w')
    p1 = plt.subplot2grid((6,7), (0,0), colspan=4, rowspan=2) # original
    p2 = plt.subplot2grid((6,7), (2,0), colspan=4, rowspan=3) # rising edge
    p3 = plt.subplot2grid((6,7), (5,0), colspan=4, rowspan=1) # residual
    p4 = plt.subplot2grid((6,7), (0,4), colspan=3, rowspan=2 )           # trace 1
    p5 = plt.subplot2grid((6,7), (2,4), colspan=3, rowspan=2, sharex=p4) # trace 2
    p6 = plt.subplot2grid((6,7), (4,4), colspan=3, rowspan=2, sharex=p4) # trace 3
    plt.show(block=False)

    # Loop over events
    while(True):
        saveMe = False
        iList += 1
        if intMode==True and iList != 0:
            value = raw_input()
            if value=='q': break
            if value=='s': saveMe=True
            if value=='p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value) # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList);
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        numPass = waveTree.Draw("channel",theCut,"GOFF",1,iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans) if waveTree.channel.at(iH) in chanList)  # a 'generator expression'
        for iH in hitList:

            # Load waveform for this hit
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            dataE = waveTree.trapENFCal.at(iH)
            dataST = waveTree.butterTime.at(iH) # replace with blrwfFMR50?
            toe = waveTree.kvorrT.at(iH)/dataE
            print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f  t/e %.1f" % (iList,nList,run,nChans,chan,dataE,toe)
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH),opt='full')
            waveBLSub = signal.GetWaveBLSub()
            waveFilt = signal.GetWaveFilt()
            waveTS = signal.GetTS()
            baseAvg, dataNoise = signal.GetBaseNoise()

            # Denoise the data waveform (take only lowest-frequency components)
            wp = pywt.WaveletPacket(data=waveBLSub, wavelet='haar', mode='symmetric',maxlevel=3)
            new_wp = pywt.WaveletPacket(data=None, wavelet='haar', mode='symmetric')
            new_wp['aaa'] = wp['aaa'].data
            waveDenoised = new_wp.reconstruct(update=False)

            # Load channel template waveform
            try: tempEntry = calDict[chan]
            except:
                print "ain't got channel",chan
                continue
            waveTemplates.GetEntry(calDict[chan])
            template = wl.processWaveform(waveTemplates.event.GetWaveform(waveTemplates.itr),opt='full')
            temp = template.GetWaveBLSub()
            tempTS = template.GetTS()
            tempE = waveTemplates.trapENFCal
            tempST = waveTemplates.blrwfFMR50

            # Window the fit around rising edge - start time calculator method
            loWin, hiWin = dataST - 1000, dataST + 4000 # ns
            if loWin < waveTS[0] or hiWin > waveTS[-1]:
                print "Window out of range!  dataST: %.1f  loWin %.1f  hiWin %.1f" % (dataST,loWin,hiWin)
            idx = np.where((waveTS >= loWin) & (waveTS <= hiWin))
            data = waveBLSub[idx]
            # data = waveDenoised[idx]
            dataTS = waveTS[idx]

            # Pack into lists
            rawList = [waveBLSub, waveTS, dataE, dataST]
            dataList = [data, dataTS, dataE, dataST, loWin, hiWin]
            tempList = [temp, tempTS, tempE, tempST]

            # Optionally save to a file
            if saveMe:
                print "Saved entry",iList,iH
                np.savez("./data/optimumInputs.npz",rawList,tempList)
                # np.savez("./data/rawInputs.npz",rawList)

            # Recreate the guess and the guess's rising edge
            guessFull, guessFullTS = wm.MakeModel(dataList, tempList, [dataST,dataE,1.], opt="full")
            guess, guessTS = wm.MakeModel(dataList, tempList, [dataST,dataE,1.], opt="!fancy")

            # Make an "almost complete" guess - no MCMC
            # st, en, slo = dataST-100, dataE, 5
            # InterpFn = interpolate.interp1d(tempTS, temp, kind="linear", copy="False", assume_sorted="True")
            # model, modelTS = wm.MakeModel(dataList, tempList, [st,en,slo], fn=InterpFn)

            # Fit with MCMC and get best-fit parameters
            numSteps, burnIn = 2000, 1000 # default - 10000, 5000.  try 3000, 2000
            myModel = wm.TemplateModel( dataList, dataNoise, tempList )
            waveModel = pymc.Model( myModel )
            M = pymc.MCMC( waveModel )
            M.use_step_method(pymc.Metropolis, M.startTime, proposal_sd=100., proposal_distribution='Normal')
            M.use_step_method(pymc.Metropolis, M.energy, proposal_sd=1., proposal_distribution='Normal')
            M.use_step_method(pymc.Metropolis, M.slowness, proposal_sd=100., proposal_distribution='Normal')
            M.sample(iter=numSteps, verbose=0) # do the fit
            st = np.median(M.trace('startTime')[burnIn:])
            en = np.median(M.trace('energy')[burnIn:])
            slo = np.median(M.trace('slowness')[burnIn:])
            InterpFn = interpolate.interp1d(tempTS, temp, kind="linear", copy="False", assume_sorted="True")
            model, modelTS = wm.MakeModel(dataList, tempList, [st,en,slo], fn=InterpFn)

            # Calculate residual, Chi2/NDF
            residual = model - data
            frac = (np.power(data - model, 2)) / np.abs(model)
            chi2NDF = np.sum(frac) / len(model)
            print "chi2/NDF:",chi2NDF

            # ** Do a separate & simple fit of the tail slope **
            # TODO: Add this to process-waveforms.py
            idxMax = np.where(guessFull == guessFull.max()) # returns an array/tuple
            idxMax = idxMax[0][0] # "cast" to int
            tail, tailTS = waveDenoised[idxMax:], waveTS[idxMax:]
            popt,_ = curve_fit(wl.tailModelPol, tailTS, tail) # poly fit
            a, b = dataE, 72000
            popt2,_ = curve_fit(wl.tailModelExp, tailTS, tail, p0=[a,b]) # expo fit

            # Fill the figure
            p1.cla()
            p1.set_ylabel("ADC")
            p1.set_title("Run %d  Channel %d  Entry %d\ntrapENFCal %.1f  T/E %.1f  ST %.1f" % (run,chan,iList,dataE,toe,dataST))
            p1.plot(waveTS,waveBLSub,color='blue')
            p1.plot(waveTS,waveDenoised,color='red',alpha=0.8)
            p1.plot(guessFullTS,guessFull,color='orange',linewidth=2)
            p1.axvline(x = dataST, color='green',linewidth=2)
            p1.axvline(x = loWin, color='black')
            p1.axvline(x = hiWin, color='black')
            p1.plot(tailTS, wl.tailModelPol(tailTS, *popt), color='cyan', linewidth=1) # tail poly fit
            p1.plot(tailTS, wl.tailModelExp(tailTS, *popt2), color='cyan', linewidth=1) # tail expo fit

            p2.cla()
            p2.plot(dataTS,data,color='blue',label='Data')
            p2.plot(guessTS,guess,color='orange',label='Guess')
            p2.plot(modelTS,model,color='red',linewidth=3,alpha=0.7,label='Fit')
            p2.legend(loc=4)

            p3.cla()
            p3.set_xlabel("Time [ns]", x=0.95, ha='right')
            p3.set_ylabel("Residual [ADC]")
            p3.plot(modelTS,residual, color='red')
            p3.axhline(y = 0, color='blue', alpha=0.3)
            p3.axhline(y = dataNoise, color='blue', alpha=0.3)
            p3.axhline(y = -1.0*dataNoise, color='blue', alpha=0.3)

            p4.cla()
            minST = tempST - tempTS[-1] + hiWin
            maxST = tempST - tempTS[0] + loWin
            p4.set_title("startTime %.1f  Energy %.2f\nSlow %.1f  chi2/ndf %.1f  Min %d  Max %d" % (st,en,slo,chi2NDF,minST,maxST))
            p4.plot(M.trace('startTime')[:])
            p4.set_ylabel('startTime')

            p5.cla()
            p5.plot(M.trace('energy')[:])
            p5.set_ylabel('energy')

            p6.cla()
            p6.plot(M.trace('slowness')[:])
            p6.set_ylabel('slowness')

            plt.tight_layout()
            plt.subplots_adjust(hspace=0.35)
            plt.pause(scanSpeed)
Example #24
0
def updateFile(dsNum, cal):
    """ ./lat2.py -upd [options]

    Cruel twist of fate: Not gonna use the calibration stuff above rn.
    Am gonna use this to update each dataset's LAT files with Ralph's
    sigma parameter.

    11/16/2017 - This has big problems when used on the PDSF queue.  It randomly corrupts files and
    causes segfaults when the tree is read. For some reason it works fine when run on login nodes.
    Short term fix for wfStd is to do it with the login nodes.
    If we ever implement LAT2 energy calibration, we will have to deal with this issue.
    """
    import ROOT
    from ROOT import std

    filePath = bgDir + "/latSkimDS%d*.root" % dsNum
    if cal == True:
        filePath = calDir + "/latSkimDS%d*.root" % dsNum

    print "Globbing", filePath
    files = glob.glob(filePath)
    # print files

    # return

    # comment this block out for normal running
    # skip ahead to where these jobs died last
    # smallList = []
    # foundLeftOff = False
    # for fileName in sorted(files):
    #     if dsNum==0:
    #         if foundLeftOff:
    #             smallList.append(fileName)
    #         if fileName == calDir + "/latSkimDS0_run3439_0.root":
    #             foundLeftOff = True
    #     elif dsNum==1:
    #         if foundLeftOff:
    #             smallList.append(fileName)
    #         if fileName == calDir + "/latSkimDS1_run12729_2.root":
    #             foundLeftOff = True
    # print len(files), len(smallList)
    # files = smallList

    # run over just one file
    # files = ["/global/homes/w/wisecg/project/cal-lat/latSkimDS0_run4841_0.root"]

    for fileName in sorted(files):

        start = time.clock()
        print "Now scanning", fileName

        f = TFile(fileName, "UPDATE")
        tree = f.Get("skimTree")
        nEnt = tree.GetEntries()

        # wipe the wfstd branch if it already exists before creating a new one
        b0 = tree.GetListOfBranches().FindObject("wfstd")
        if isinstance(b0, ROOT.TBranchElement):
            tree.GetListOfBranches().Remove(b0)
            tree.Write()

        wfstd = std.vector("double")()
        b1 = tree.Branch("wfstd", wfstd)

        # loop over events
        for iList in range(nEnt):
            tree.GetEntry(iList)
            nChans = tree.channel.size()
            nWFs = tree.MGTWaveforms.size()
            if (nChans != nWFs):
                print "Wrong num entries.  Bailing!"
                exit(1)
            wfstd.assign(nChans, -88888)

            # loop over hits
            for iH in range(nWFs):
                run = tree.run
                chan = tree.channel.at(iH)
                energy = tree.trapENFCal.at(iH)
                wf = tree.MGTWaveforms.at(iH)
                signal = wl.processWaveform(wf, 0, 0)
                waveRaw = signal.GetWaveRaw()
                waveTS = signal.GetTS()
                # print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f" % (iList,nList,run,nChans,chan,energy)

                wfstd[iH] = np.std(waveRaw[5:-5])
                maxAdc = max(waveRaw[5:-5])
                minAdc = min(waveRaw[5:-5])
                nBins = int(maxAdc - minAdc)

            # End loop over hits, fill branches
            b1.Fill()

        # End loop over events
        tree.Write("", ROOT.TObject.kOverwrite)
        print " - Tree entries: %d  Branch entries: %d  Time (min): %.2f" % (
            tree.GetEntries(), b1.GetEntries(), (time.clock() - start) / 60.)

        f.Close()
Example #25
0
def main(argv):
    """ Interactive-fit or 'rapid'-fit waveforms that pass a given TCut.
        BUG: Doesn't always work with a TChain.  Add input files together
        with hadd and use a single TFile.
    """
    scanSpeed = 0.2
    iList = -1
    opt1, opt2 = "", "-"
    intMode = False
    if (len(argv) >= 1): opt1 = argv[0]
    if (len(argv) >= 2): opt2 = argv[1]
    if "-i" in (opt1, opt2):
        intMode = True
        print "Interactive mode selected."
    # if opt2.isdigit:
    # iList = int(opt2) - 1

    startT = time.clock()

    # Load template waveforms
    templateFile = TFile("./data/wave-m1cal.root")
    waveTemplates = templateFile.Get("waveTree")
    calDict = {
        640: 28,
        672: 18,
        610: 16,
        580: 19,
        582: 34,
        648: 38,
        600: 21,
        578: 39,
        592: 27,
        664: 55,
        626: 62,
        692: 8,
        598: 22,
        690: 52,
        632: 9,
        608: 7
    }
    # PlotTemplateWaveforms(waveTemplates,calDict)

    # Set input data and cuts
    # waveTree = TChain("skimTree") # BUG: Can't always recognize MGTWaveforms branch
    # waveTree.Add("~/project/wavelet-skim/waveletSkimDS3*")
    # inputFile = TFile("~/project/wavelet-skim/hadd/waveletSkimDS3.root")
    inputFile = TFile("~/project/wavelet-skim/waveletSkimDS3_13.root")
    waveTree = inputFile.Get("skimTree")
    print "Found", waveTree.GetEntries(), "input entries."

    # theCut = inputFile.Get("cutUsedHere").GetTitle()
    # theCut = "trapENFCal > 0.8 && gain==0 && mH==1 && isGood && !muVeto && !wfDCBits && !isLNFill1 && !isLNFill2 && trapETailMin < 0 && channel!=596 && channel!=676 && channel!=676 && channel!=612 && channel!=1104 && channel!=1200 && channel!=1334 && channel!=1336"

    # DS3 big cut
    theCut = "trapENFCal > 0.8 && gain==0 && mHClean==1 && isGood && !muVeto && !wfDCBits && !isLNFill1 && !isLNFill2 && trapETailMin < 0 && channel!=596 && channel!=676 && channel!=676 && channel!=612 && channel!=1104 && channel!=1200 && channel!=1334 && channel!=1336 && tOffset < 10 && waveS5/TMath::Power(trapENFCal,1/4) < 1200 && (waveS3-waveS2)/trapENFCal > 100 && (waveS3-waveS2)/trapENFCal < 300 && !(channel==692 && (run==16974 || run==16975 || run==16976 || run==16977 || run==16978 || run==16979))"

    # theCut += " && trapENFCal > 2 && trapENFCal < 2.1 && channel==578 && run==16868"  # template fast WF (2kev)
    theCut += " && trapENFCal > 3 && trapENFCal < 4"
    # theCut += " && trapENFCal < 10 && trapENFCal > 1"

    # Print cut and events passing cut
    print "Using cut:\n", theCut, "\n"
    waveTree.Draw(">>elist", theCut, "entrylist")
    elist = gDirectory.Get("elist")
    waveTree.SetEntryList(elist)
    nList = elist.GetN()
    print "Found", nList, "entries passing cuts."

    stopT = time.clock()
    print "Data loading time (s): ", (stopT - startT)

    # Make a figure
    fig = plt.figure(figsize=(8, 7), facecolor='w')
    gs = gridspec.GridSpec(3, 1, height_ratios=[2, 3, 1])
    a1 = plt.subplot(gs[0])
    a2 = plt.subplot(gs[1])
    a3 = plt.subplot(gs[2])
    plt.show(block=False)

    # Loop over events
    while (True):
        iList += 1
        if intMode == True and iList != 0:
            value = raw_input()
            if value == 'q': break
            if value == 'p': iList -= 2  # previous
            if (value.isdigit()): iList = int(value)  # go to entry
        if iList >= elist.GetN(): break

        entry = waveTree.GetEntryNumber(iList)
        waveTree.LoadTree(entry)
        waveTree.GetEntry(entry)
        nChans = waveTree.channel.size()
        numPass = waveTree.Draw("channel", theCut, "GOFF", 1, iList)
        chans = waveTree.GetV1()
        chanList = list(set(int(chans[n]) for n in xrange(numPass)))

        # Loop over hits passing cuts
        hitList = (iH for iH in xrange(nChans)
                   if waveTree.channel.at(iH) in chanList
                   )  # a 'generator expression'
        for iH in hitList:

            # Load waveform for this hit
            run = waveTree.run
            chan = waveTree.channel.at(iH)
            energy = waveTree.trapENFCal.at(iH)
            print "%d / %d  Run %d  nCh %d  chan %d  trapENF %.1f" % (
                iList, nList, run, nChans, chan, energy)
            signal = wl.processWaveform(waveTree.MGTWaveforms.at(iH),
                                        opt='full')
            waveBLSub = signal.GetWaveBLSub()
            waveFilt = signal.GetWaveFilt()
            waveTS = signal.GetTS()
            baseAvg, noiseAvg = signal.GetBaseNoise()
            riseTime = waveTree.butterTime.at(iH)  # replace with blrwfFMR50?

            # Load channel template waveform
            try:
                tempEntry = calDict[chan]
            except:
                print "ain't got channel", chan
                continue
            waveTemplates.GetEntry(calDict[chan])
            template = wl.processWaveform(waveTemplates.event.GetWaveform(
                waveTemplates.itr),
                                          opt='full')
            templateENF = waveTemplates.trapENFCal
            templateT50 = waveTemplates.blrwfFMR50
            tempTS = template.GetTS()
            tempBLSub = template.GetWaveBLSub()

            # Guess scaling parameters & fill arrays
            scaleGuess = energy / templateENF
            tDiffGuess = riseTime - templateT50
            tempGuess = tempBLSub * scaleGuess
            tempTSGuess = tempTS + tDiffGuess
            tempGuessRT = templateT50 + tDiffGuess

            # Fit around rising edge - rise time calculator method
            lo, hi = 300, 700  # samples before and after the start time
            loWin = riseTime / 10 - lo
            hiWin = riseTime / 10 + hi
            waveEndsRT = np.concatenate(
                (np.arange(0, loWin), np.arange(hiWin, waveBLSub.size)),
                axis=0)
            waveEdgeRT = np.delete(waveBLSub, waveEndsRT)
            tsEdgeRT = np.delete(waveTS, waveEndsRT)

            # Fit with MCMC
            numSteps, burnin = 10000, 4000
            # numSteps, burnin = 1000, 400
            waveModel = pymc.Model(
                wm.WaveformModel(waveEdgeRT, tsEdgeRT, tempBLSub, tempTS,
                                 tDiffGuess, scaleGuess, noiseAvg))
            M = pymc.MCMC(waveModel)
            M.use_step_method(pymc.Metropolis,
                              M.riseTime,
                              proposal_sd=4.,
                              proposal_distribution='Normal')
            M.use_step_method(pymc.Metropolis,
                              M.slowness,
                              proposal_sd=0.1,
                              proposal_distribution='Normal')
            M.use_step_method(pymc.Metropolis,
                              M.scale,
                              proposal_sd=0.1,
                              proposal_distribution='Normal')
            M.sample(iter=numSteps, verbose=0)  # do the fit
            rt = np.median(M.trace('riseTime')[burnin:])
            slowness = np.median(M.trace('slowness')[burnin:])
            scale = np.median(M.trace('scale')[burnin:])

            # Recreate the guess, the best-fit signal, and the residual
            templateTSRT = tempTS + rt
            lo, hi = tsEdgeRT[0], tsEdgeRT[-1] + 10
            idx = np.where((templateTSRT >= lo) & (templateTSRT <= hi))
            scaled = tempBLSub[idx] * scale
            smoothed = gaussian_filter(scaled, sigma=float(slowness))
            smoothedTS = templateTSRT[idx]
            guess = tempBLSub[idx] * scaleGuess
            guessTS = templateTSRT[idx]
            residual1 = smoothed - guess
            residual2 = smoothed - waveEdgeRT
            residual3 = smoothed - waveFilt[idx]

            # Calculate the Chi2 of the fit

            # Fill the figure
            a1.cla()
            a1.set_ylabel("ADC")
            a1.set_title("Run %d  Channel %d  Entry %d  trapENFCal %.1f" %
                         (run, chan, iList, energy))
            a1.plot(waveTS, waveBLSub, color='blue')
            a1.plot(waveTS, waveFilt, color='green', alpha=0.6)
            a1.plot(tempTSGuess, tempGuess, color='orange')
            a1.axvline(x=riseTime, color='red', linewidth=3)
            a1.axvline(x=tempGuessRT, color='green', alpha=0.8)
            a1.axvline(x=loWin * 10, color='cyan')
            a1.axvline(x=hiWin * 10, color='cyan')

            a2.cla()
            a2.plot(tsEdgeRT, waveEdgeRT, color='blue')
            a2.plot(smoothedTS, smoothed, color='red', linewidth=4)
            a2.plot(guessTS, guess, color='orange')

            a3.cla()
            a3.set_xlabel("Time [ns]", x=0.95, ha='right')
            a3.set_ylabel("Residual [ADC]")
            a3.plot(smoothedTS, residual1, color='red')
            # a3.plot(smoothedTS,residual2, color='cyan')
            # a3.plot(smoothedTS,residual3, color='cyan')
            a3.axhline(y=0, color='blue', alpha=0.3)

            plt.tight_layout()
            plt.subplots_adjust(hspace=0.15)
            plt.pause(scanSpeed)