From 47a31378f44ca64b4d3f6241f8e3faa3ff0b6b9c Mon Sep 17 00:00:00 2001
From: Savannah Rose Shively <sshively@lxplus752.cern.ch>
Date: Mon, 20 Feb 2023 15:51:07 +0100
Subject: [PATCH] many plots

---
 .../PairVertex/scripts/NtupleReader.py        | 410 ++++++++++++++++--
 .../PairVertex/scripts/NtupleReaderROOT.py    |  99 +++++
 .../PairVertex/scripts/PairVertexReader.py    |  24 +-
 .../PairVertex/scripts/PlotHelper.py          |  23 +-
 .../PairVertex/scripts/PlotHelperROOT.py      | 108 +++++
 .../PairVertex/scripts/Utilities.py           |   8 +-
 6 files changed, 635 insertions(+), 37 deletions(-)
 create mode 100644 Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReaderROOT.py
 create mode 100644 Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelperROOT.py

diff --git a/Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReader.py b/Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReader.py
index 08f0888f..6b07cc96 100644
--- a/Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReader.py
+++ b/Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReader.py
@@ -2,11 +2,12 @@
 from PlotHelper import *
 from Utilities import *
 from glob import glob
+from copy import deepcopy
 
 #CUTS
 #attr: [>,<,==,!=] if none --> skip
 REALCUT={
-    'longTracks':[1,None,None,None],}
+    'longTracks':[None,None,2,None],}
 #     'Track_nLayers':[6,None,None,None],
 #     'Track_nDoF':[0,None,None,None],
 #     'Track_Chi2':[0,None,None,None],
@@ -14,50 +15,225 @@ REALCUT={
 #     'Preshower1_charge':[0,None,None,None]   
 # }
 
+{'longTracks':[None,None,2,None]}
+
+BASELINE={
+        'VetoNu0_charge':[None,40,None,None],
+        'VetoNu1_charge':[None,40,None,None],
+        'VetoSt10_charge':[None,40,None,None],
+        'VetoSt20_charge':[None,40,None,None],
+        'VetoSt21_charge':[None,40,None,None],
+        'Preshower0_charge':[2.5,None,None,None],
+        'Preshower1_charge':[2.5,None,None,None],
+        'Calo_total_E_EM':[0,None,None,None]      
+}
+
+BASELINETEST={
+        'VetoNu0_charge':[None,40,None,None],
+        'VetoNu1_charge':[None,40,None,None],
+        'VetoSt10_charge':[None,40,None,None],
+        'VetoSt20_charge':[None,40,None,None],
+        'VetoSt21_charge':[None,40,None,None],
+        'Preshower0_charge':[2.5,None,None,None],
+        'Preshower1_charge':[2.5,None,None,None],
+        'Calo_total_E_EM':[0,None,None,None]  
+}
+
+BASELINEL=[]
+
+VETOCUTS={
+        'VetoNu0_charge':[None,None,0,None],
+        'VetoNu1_charge':[None,None,0,None],
+        'VetoSt10_charge':[None,None,0,None],
+        'VetoSt11_charge':[None,None,0,None],
+        'VetoSt20_charge':[None,None,0,None]}
+
+WAVEFORMD={
+    'Preshower0_charge':[0,None,None,None],
+    'Preshower1_charge':[0,None,None,None] }
+
 #LAMBDAS AND CONDITIONALS
 
 REALLAMBDAS=[
     lambda event: event.Timing0_charge+event.Timing1_charge+event.Timing2_charge+event.Timing3_charge>0,
-    lambda event: event.Calo0_charge+event.Calo1_charge+event.Calo2_charge+event.Calo3_charge>20000]
+    lambda event: event.Calo0_charge+event.Calo1_charge+event.Calo2_charge+event.Calo3_charge>0]
 #     lambda event: AnyCaloThreshold,
 #     lambda event: all([event.Track_nLayers[i]>6 for i in event.longTracks])
 # ]
 
-def GeneralPlotter(arrDict,dcuts=[],lcuts=[],showplot=True,savefig=False):
+WAVEFORMLAMBDAS=[
+    lambda event: event.Timing0_charge+event.Timing1_charge+event.Timing2_charge+event.Timing3_charge>0,
+    lambda event: event.Calo0_charge+event.Calo1_charge+event.Calo2_charge+event.Calo3_charge>0]
+
+def BoolTimingBaseline(event):
+    th=70
+    return (event.Timing0_charge+event.Timing1_charge+event.Timing2_charge+event.Timing3_charge>th)
+
+def BoolGoodTracks(event):
+    gt_i=[]
+    for i in range(event.longTracks):
+        tests=[]
+        if event.Track_nDoF[i]==0: continue
+        else: tests+=[event.Track_Chi2[i]/event.Track_nDoF[i]<25]
+        tests+=[event.Track_nLayers[i]>=7]
+        R=95
+        tests+=[sqrt(event.Track_x0[i]**2+event.Track_y0[i]**2)<R and sqrt(event.Track_x1[i]**2+event.Track_y1[i]**2)<R and  sqrt(event.Track_X_atVetoNu[i]**2+event.Track_Y_atVetoNu[i]**2)<R]
+        if all(tests): gt_i+=[i]
+    
+    return len(gt_i)>=1
+
+    #iterate over all tracks
+    #count tracks that are good
+    #nlayers, chi2/dof, r<100mm
+
+def BoolLowCollAreDaughters(event):
+    if event.longTracks<2: return False
+
+    angleIndexSorted=[i for i in range(event.longTracks)]
+    theta=[] #in order of track number
+    for tr in range(event.longTracks):
+        theta+=[arctan(event.Track_x0[tr]/event.Track_z0[tr])]
+
+    angleIndexSorted.sort(key=lambda elem: theta[elem]) #lowest to highest px/pz angle
+    #print(f"IndeciesSorted:{angleIndexSorted} \nTheta:{theta} \nEventBarcode: {event.t_barcode}\n")
+
+    diff_i=0
+    diff_v=theta[angleIndexSorted[0]]-theta[angleIndexSorted[1]] #if there are only 2 tracks, they make the smallest diff
+    
+    for i in range(event.longTracks-1):
+        dv=theta[angleIndexSorted[i]]-theta[angleIndexSorted[i+1]]
+        if dv<diff_v:
+            diff_v=dv
+            diff_i=i
+
+    i_lowcol1=angleIndexSorted[diff_i] #lowest diff
+    i_lowcol2=angleIndexSorted[diff_i+1]
+    test= event.t_barcode[i_lowcol1] in [2,3] and event.t_barcode[i_lowcol2] in [2,3] and event.t_barcode[i_lowcol1]!=event.t_barcode[i_lowcol2]
+    #if not test: print(f"IndeciesSorted:{angleIndexSorted} \nTheta:{theta} \nEventBarcode: {event.t_barcode}\n")
+    return test
+
+    #collinearity of all tracks vs collin specifically of matched daughters
+    #for events with tracks>2: are the matched daughters the most collin?
+
+def GetThetaPxPz(event):
+    theta=[] #in order of track number
+    for tr in range(event.longTracks):
+        theta+=[1000*arctan(event.Track_px0[tr]/event.Track_pz0[tr])]
+    return theta
+
+def GetThetaPyPz(event):
+    theta=[] #in order of track number
+    for tr in range(event.longTracks):
+        theta+=[1000*arctan(event.Track_py0[tr]/event.Track_pz0[tr])]
+    return theta
+
+def BoolLayersHit(event):
+    return all([event.tracksNLayersHit[i]>=7 for i in range(len(event.Track_nLayers))])
+
+def BoolBothDaughtersFiducial(event):
+    dp=[0,0]
+    for tp in range(len(event.truthParticleBarcode)):
+        #print(event.truthParticleBarcode)
+        if event.truthParticleBarcode[tp]==2: dp[0]=event.truthParticleIsFiducial[tp]
+        if event.truthParticleBarcode[tp]==3: dp[1]=event.truthParticleIsFiducial[tp]
+        if event.truthParticleBarcode[tp]>3: break
+    return all(dp)
+
+def BoolDaughtersMatched(event):
+    #both daughter particles are matched to tracks
+    if event.longTracks>=2:
+        return 2 in event.t_barcode and 3 in event.t_barcode
+    else: return False
+
+def IntDaughtersMatched(event):
+    #both daughter particles are matched to tracks
+    dm=0
+    if 2 in event.t_barcode: dm+=1
+    if 3 in event.t_barcode: dm+=1
+        
+    #if len(event.t_barcode)>2: print(event.t_barcode)
+    
+    return dm
+
+def BoolDM0(event):
+    return IntDaughtersMatched(event)>0
+
+def BoolDM1(event):
+    return IntDaughtersMatched(event)==1
+
+def BoolDM2(event):
+    return IntDaughtersMatched(event)==2
+
+def IntBothDaughtersFiducial(event):
+    dp=0
+    for tp in range(len(event.truthParticleBarcode)):
+        #print(event.truthParticleBarcode)
+        if event.truthParticleBarcode[tp] in [2,3]: dp+=1
+        if event.truthParticleBarcode[tp]>3: break
+    return dp
+
+
+def GeneralPlotter(t,arrDict,dcuts=[],lcuts=[],showplot=True,savefig=False,titleextra='',label=None):
     nans=0
+    for name in arrDict.keys():
+        ph=''
+        if 'lkwargs' in list(arrDict[name].keys()): ph=arrDict[name]['lkwargs']
+        arrDict[name]=deepcopy(MainArrDict[name])
+        if 'lkwargs' in list(arrDict[name].keys()): arrDict[name]['lkwargs']=ph
+        print(arrDict[name]['array'])
+
+    x=0
     ecount=0
     for event in t:
-        
-        if ApplyAllCuts(event,dcuts,lcuts):
+        ecount+=1
+        if ApplyAllCuts(event,dcuts,lcuts): #Check that event passes given cuts before doing anything with it
             for name in arrDict.keys():
+                #if x%10**5==0: print(x)
+                #Get value that will go in arrray for plotting
                 value=nan
                 if 'lkwargs' in list(arrDict[name].keys()): 
+                    #print(arrDict[name]['lkwargs'])
                     value = arrDict[name]['lambda'](event,**arrDict[name]['lkwargs'])
                 else: value = arrDict[name]['lambda'](event)
+
+                #Check that all values to be added to the plot-array are valid
                 checkReal=True
                 if type(value)==list: checkReal = all([v != inf and v !=nan and v !=-1*inf for v in value])
                 else: checkReal = value != inf and value !=nan and value !=-1*inf
-
-                if checkReal and type(value)==list:
-                    if arrDict[name]['plotterfunc'] in [configBasicHist]: arrDict[name]['array']+=value
-                    else:
+                
+                #If the value is valid, add it to the plot array.
+                if checkReal and type(value)==list: 
+                    if arrDict[name]['plotterfunc'] in [configBasicHist]: arrDict[name]['array']+=value #when plotting on a subset of items like tracks instead of events
+                    else: #MultiHist
                         for iv in range(len(value)):
                             arrDict[name]['array'][iv]+=[value[iv]]
-                elif checkReal: arrDict[name]['array']+=[value]
+                elif checkReal: arrDict[name]['array']+=[value] #Basic histogram
+                elif 'SepHist' in list(arrDict[name].keys()): #are subarrays allowed to have different lengths?
+                    checkList=[v != inf and v !=nan and v !=-1*inf for v in value] #if yes, check each value returned for nans (may be nan if cut; actual nancount doesnt apply here)
+                    for ich in len(checkList):
+                        if checkList[ich]: arrDict[name]['array'][ich]+=[value[ich]]
+
                 else: nans+=1
-        if ecount%100000==0:print(ecount,' events processed')
-        ecount+=1
 
     print(f"# of NaNs:{nans}")
     for name in arrDict.keys():
-        isPrintout= arrDict[name]['plotterfunc'] in [PrintBoolPercent]
+        isPrintout= arrDict[name]['plotterfunc'] in [PrintBoolPercent] #Is it text-only output?
         print(name)
-        print('LEN:',len(arrDict[name]['array']))
-        arrDict[name]['plotterfunc']( arrDict[name]['array'], **arrDict[name]['plotkwargs'])
+        #print(arrDict[name]['descr'])
+        print('LEN:',len(arrDict[name]['array'])) #how many events remain after the cut?
+        if label:
+            arrDict[name]['plotkwargs'].update({'label':label})
+            arrDict[name]['plotkwargs']['pckwargs'].update({'legend':True})
+
+        arrDict[name]['plotterfunc']( arrDict[name]['array'], **arrDict[name]['plotkwargs']) #plot using the given function
         if not isPrintout:
-            plt.title(user_input+name)
+            plt.title(user_input+name+titleextra)
             if savefig: plt.savefig(user_input+name)
             if showplot: plt.show()
+
+        print()
+    print("EVENTS: ",ecount)
+    
 COUNT=0
 def ReadoutTest(event):
     value = event.longTracks
@@ -68,19 +244,89 @@ def ReadoutTest(event):
     if value>1: print(value)
     return value
 
+def OrderChecker(arrDict):
+    x=0
+    for name in arrDict.keys():
+        arrDict[name]=deepcopy(MainArrDict[name])
+        print(arrDict[name]['array'])
+
+    for event in t:
+        x+=1
+        if x%10**5==0: print(x)
+
+#TRACK EFFICIENCY STUFF
+def GetTrackEfficiency(t,dcutN=[],dcutD=[],lcutN=[],lcutD=[],plim=0):
+    narray=0.0
+    darray=0.0
+    for event in t:
+        if ApplyAllCuts(event,dcutN,lcutN) and BoolTrackPCut(event,plim): narray+=1
+            #each track
+            # for tr in range(event.longTracks):
+            #     if event.Track_p0[tr]>plim:
+            #         narray+=1.0
+        if ApplyAllCuts(event,dcutD,lcutD) and BoolBothDaughtersFiducial(event): darray+=1 
+            # for tr in range(event.longTracks):
+            #     darray+=IntBothDaughtersFiducial(event)
+    if darray==0:return 0
+    return (narray/darray)*100
+
+def BoolTrackPCut(event,plim=0):
+    #require all tracks to pass the cut
+    for tr in range(event.longTracks):
+        if event.Track_p0[tr]<plim: return False
+    return True
+
+def GetTrackEffCoords(t):
+    plims = [0,10,20,30,40,50]
+    ycoords=[] #list of lists
+    calocuts=[0,100,200,300,400,500]
+    
+    for cl in calocuts:
+        y=[]
+        for pl in plims:
+            y+=[GetTrackEfficiency(t,dcutN=[BASELINE],lcutN=[lambda event: event.Calo_total_E_EM>cl*(10**3),BoolGoodTracks,BoolTimingBaseline],lcutD=[],plim=pl*(10**3))]
+        ycoords+=[y]
+    labels=[f'CaloEM_Tot > {c}GeV' for c in calocuts]
+    return plims,ycoords,labels
+
+def TrackEfficiencyShow(t,title=''):
+    x,ys,labels=GetTrackEffCoords(t)
+    for i in range(len(ys)):
+        PlotTrackEfficiency(x,ys[i],labels[i])
+    
+    PlotConfigs(xscale='linear',title=title,ylim=(0,100),show=True,xlabel='Upstream Pmag Cut (GeV)',ylabel='Efficiency (%)',legend=True)
+
+#TRACK SEPARATION VS MOMENTUM STUDY
+def ShowTrackSepVsRecoMom(t):
+    x1,x2=([],[]) #track sep
+    y1,y2=([],[]) #reco momentum
+    for event in t:
+        if ApplyAllCuts(event,[BASELINE],[BoolTimingBaseline,BoolGoodTracks]):
+            if IntDaughtersMatched(event)==1:
+                x1+=[sqrt((event.truthd0_x[0]-event.truthd1_x[0])**2+(event.truthd0_y[0]-event.truthd1_y[0])**2)]
+                y1+=[max(event.Track_p0)]
+            if IntDaughtersMatched(event)==2:
+                x2+=[sqrt((event.truthd0_x[0]-event.truthd1_x[0])**2+(event.truthd0_y[0]-event.truthd1_y[0])**2)]
+                y2+=[max(event.Track_p0)]
+    
+    PlotTrackEfficiency(x1,y1,'Matched Tracks==1')
+    PlotTrackEfficiency(x2,y2,'Matched Tracks==2')
+    PlotConfigs(xscale='linear',title='Track Sep vs Max Reco Momentum',show=True,xlabel='Track Separation (mm)',ylabel='Max Upstream Pmag (MeV)',legend=True)
+
+
 #
 MainArrDict={
     'CutTest':{
         'array':[],
         'lambda': ApplyAllCuts,
-        'lkwargs':{'dcuts':[REALCUT],'lcuts':REALLAMBDAS}, 
+        'lkwargs':{'dcuts':[BASELINE],'lcuts':[BoolTimingBaseline, BoolGoodTracks,BoolDM0]}, 
         'plotterfunc': PrintBoolPercent,
         'plotkwargs' : {},
         'descr':'Check how much a cut cuts.'
     },
     'BasicHist':{
         'array':[],
-        'lambda': ReadoutTest,
+        'lambda': IntDaughtersMatched,
         'plotterfunc': configBasicHist,
         'plotkwargs' : {},
         'descr':'Single variable tests.'
@@ -98,30 +344,144 @@ MainArrDict={
         'plotterfunc': configMultiHist,
         'plotkwargs' : {'label':['Lowest','Highest'],'pckwargs':{'xscale':'symlog','xlabel':"Momentum (MeV)",'legend':True}},
         'descr':'Look at 2 highest momentum tracks downstream'
-    },}
+    },
+    'TrackCount':{
+        'array':[],
+        'lambda': lambda event: event.longTracks,
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[0,25]},'pckwargs':{}}
+    },
+    'CaloTotal':{
+        'array':[],
+        'lambda': lambda event: event.Calo_total_E_EM, #event.Calo0_charge+event.Calo1_charge+event.Calo2_charge+event.Calo3_charge,
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'pckwargs':{}}
+    },
+    'Momentum':{
+        'array':[],
+        'lambda': lambda event: [p for p in event.Track_p0],
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[10**3,10**10]},'pckwargs':{'xscale':'symlog','xlabel':"Momentum (MeV)",'ylabel':"#Tracks",'legend':True},'rrange':[10**3,10**12]},#
+        'descr':'Look at momentum tracks upstream'
+    },
+    'TruthMomentum':{
+        'array':[],
+        'lambda': lambda event: [event.truthd0_P[0],event.truthd1_P[0]],
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[10**3,10**10]},'pckwargs':{'xscale':'symlog','xlabel':"Momentum (MeV)",'ylabel':"#Tracks",'legend':True},'rrange':[10**3,10**12]},#
+        'descr':'Look at momentum tracks upstream'
+    },
+    'MaxRecoMomentumUp':{
+        'array':[],
+        'lambda': lambda event: max(event.Track_p0),
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'bins':50,'kwargs':{'range':[10**3,10**11]},'pckwargs':{'xscale':'log','xlabel':"Momentum (MeV)",'legend':True}},
+        'descr':'Look at highest momentum tracks upstream'
+    },
+    'ThPxPz':{
+        'array':[],
+        'lambda':GetThetaPxPz,
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[-5,5]},'pckwargs':{'xlabel':"Theta_PxPz (mrad)",'ylabel':"#Tracks"}},#
+        'descr':'Look at collinearity'
+    },
+    'ThPyPz':{
+        'array':[],
+        'lambda':GetThetaPyPz,
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[-5,5]},'pckwargs':{'xlabel':"Theta_PyPz (mrad)",'ylabel':"#Tracks"}},#
+        'descr':'Look at collinearity'
+    },
+    'CollPxPz':{
+        'array':[],
+        'lambda': BoolLowCollAreDaughters,
+        'plotterfunc': PrintBoolPercent,
+        'plotkwargs' : {},
+        'descr':'Check how much a cut cuts.'
+    },
+    'RecoSep2trk':{
+        'array':[],
+        'lambda': lambda event: sqrt((event.Track_X_atTrig[0]-event.Track_X_atTrig[1])**2+(event.Track_Y_atTrig[0]-event.Track_Y_atTrig[1])**2),
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[0,20]},'pckwargs':{}},
+        'descr':'Single variable tests.'
+    },
+    'TruthSep2trk':{
+        'array':[],
+        'lambda': lambda event: sqrt((event.t_st1_x[0]-event.t_st1_x[1])**2+(event.t_st1_y[0]-event.t_st1_y[1])**2),
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[0,20]},'pckwargs':{}},
+        'descr':'Single variable tests.'
+    },
+    }
 
 TestArrDict=dict()
 testname='HighestMomentumDown' #Any key from MainArrDict
 TestArrDict[testname]=MainArrDict[testname]
 
-def getRunFiles(rnum,dataDir="/eos/experiment/faser/phys/2022/r0011/"):
-    dataDir=f"{dataDir}{rnum}/"
+def getRunFiles(rnum,dataDir="/eos/experiment/faser/phys/2022/r0013/"):
+    dataDir=f"/eos/experiment/faser/sim/mc22/foresee/{rnum}/phy/r0013/" #f"{dataDir}{rnum}/"
     return sorted(glob(f"{dataDir}/Faser*"))
 
-def getRunNums(dataDir="/eos/experiment/faser/phys/2022/r0011/"):
+def getRunNums(dataDir="/eos/experiment/faser/phys/2022/r0013/"):
     return [rn.split(dataDir)[1] for rn in sorted(glob(f"{dataDir}*"))]
 
+def MakePlotDict(entry):
+    TestArrDict=dict()
+    if type(entry)==list:
+        for e in entry:
+            testname=e #Any key from MainArrDict
+            TestArrDict[testname]=deepcopy(MainArrDict[testname])
+    else:
+        testname=entry #Any key from MainArrDict
+        TestArrDict[testname]=deepcopy(MainArrDict[testname])
+    return TestArrDict
 
 #EXECUTE
 if __name__ == "__main__":
     #runnum = '008301'
     t = TChain("nt") 
     nfiles = 0
-    for runnum in getRunNums():
+    fgrab=''
+    for runnum in [f'1100{ri}' for ri in range(22,56)]:#,52,55,35,42,49,36,43,50,37,44,31,45]]:#getRunNums():
+        #if int(runnum[-2:]) in [28,33,38,51]: continue
+        if int(runnum[-2:]) != 38: continue
+        #if int(runnum[-2:]) not in [48,49]: continue#43,44,45,35,36,37,31,32 52,48,49,50,41,42
+        
         files = getRunFiles(runnum)
+        user_input=f'Ntuple_Run{runnum}'
+        
         for f in files:
             print(f)
+            fgrab=f
             nfiles += t.Add(f) #t.Add("/eos/experiment/faser/phys/2022/r0011/"+user_input+".root") 
-            
+        
+    rnlab = fgrab.split("FaserMC-MC22_")[1].split(f'-1100')[0]
+    print(rnlab)
+    #rnlab = "All 5k-event Models"
+
+    #TrackEfficiencyShow(t,title=f'{rnlab} TrackEfficiency (Good Trks>=1)')
+
+    # Momentum plot
+    # for li in [0,5,10,50,100]:
+    #     mpd=MakePlotDict('Momentum')
+    #     mpd['Momentum']['lkwargs']['lim']=li*10**3
+    #     #print(mpd)
+    #     try:
+    #         emcut=100
+    #         GeneralPlotter(t,mpd,dcuts=[],lcuts=[lambda event: event.Calo_total_E_EM>emcut*(10**3)],showplot=False,label=f'Pmag>{li}GeV Cut ')
+    #     except ValueError:
+    #         print("Empty after cut: ",li,"Gev")
+    #         continue
+    # plt.title(f"FaserMC Aee {rnlab} Pmag CaloCut={emcut} GeV")
+    # plt.show()
     
-    GeneralPlotter(TestArrDict,dcuts=[{'longTracks':[None,None,2,None],}],lcuts=[],savefig=True)
\ No newline at end of file
+    # GeneralPlotter(t,MakePlotDict('CutTest'),dcuts=[],lcuts=[BoolBothDaughtersFiducial])
+    #GeneralPlotter(t,MakePlotDict('BasicHist'),dcuts=[BASELINE],lcuts=[BoolTimingBaseline, BoolGoodTracks,BoolBothDaughtersFiducial])
+    GeneralPlotter(t,MakePlotDict('MaxRecoMomentumUp'),dcuts=[BASELINE,{'longTracks':[None,None,1,None],}],lcuts=[BoolTimingBaseline,BoolGoodTracks])
+    #GeneralPlotter(t,MakePlotDict('MaxRecoMomentumUp'),dcuts=[BASELINE],lcuts=[BoolTimingBaseline,BoolGoodTracks,BoolDM2],label='Matched Tracks==2')
+    #GeneralPlotter(t,MakePlotDict('TruthMomentum'),dcuts=[BASELINETEST,REALCUT],lcuts=[BoolDaughtersMatched,BoolBothDaughtersFiducial],label='Truth')
+    #GeneralPlotter(t,MakePlotDict('CollPxPz'),dcuts=[{'longTracks':[None,None,1,None]}],lcuts=[])
+
+    #ShowTrackSepVsRecoMom(t)
+    
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReaderROOT.py b/Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReaderROOT.py
new file mode 100644
index 00000000..bfc730e7
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/PairVertex/scripts/NtupleReaderROOT.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+import ROOT as R
+from glob import glob
+from copy import deepcopy
+
+#CUTS
+#attr: [>,<,==,!=] if none --> skip
+REALCUT={
+    'longTracks':[None,None,1,None],}
+#     'Track_nLayers':[6,None,None,None],
+#     'Track_nDoF':[0,None,None,None],
+#     'Track_Chi2':[0,None,None,None],
+#     'Preshower0_charge':[0,None,None,None],
+#     'Preshower1_charge':[0,None,None,None]   
+# }
+
+VETOCUTS={
+        'VetoNu0_charge':[None,None,0,None],
+        'VetoNu1_charge':[None,None,0,None],
+        'VetoSt10_charge':[None,None,0,None],
+        'VetoSt11_charge':[None,None,0,None],
+        'VetoSt20_charge':[None,None,0,None]}
+
+WAVEFORMD={
+    'Preshower0_charge':[0,None,None,None],
+    'Preshower1_charge':[0,None,None,None] }
+
+#LAMBDAS AND CONDITIONALS
+
+REALLAMBDAS=[
+    lambda event: event.Timing0_charge+event.Timing1_charge+event.Timing2_charge+event.Timing3_charge>0,
+    lambda event: event.Calo0_charge+event.Calo1_charge+event.Calo2_charge+event.Calo3_charge>0]
+#     lambda event: AnyCaloThreshold,
+#     lambda event: all([event.Track_nLayers[i]>6 for i in event.longTracks])
+# ]
+
+WAVEFORMLAMBDAS=[
+    lambda event: event.Timing0_charge+event.Timing1_charge+event.Timing2_charge+event.Timing3_charge>0,
+    lambda event: event.Calo0_charge+event.Calo1_charge+event.Calo2_charge+event.Calo3_charge>0]
+
+def RootFilterFromDict(dcuts): #accepts dictionary of cuts, returns a string
+    output=''
+    symbols=['>=','<=','==','!=']
+    for k in dcuts.keys():
+        for ib in range(0,4):
+            if dcuts[k][ib]!=None: 
+                o1=''
+                o1+=f'{k}{symbols[ib]}{dcuts[k][ib]}'
+                if output!='': o1=' && '+o1
+                output+=o1
+    
+    return output
+
+COUNT=0
+def ReadoutTest(event):
+    value = event.longTracks
+    global COUNT
+    COUNT+=1
+    if COUNT<1000: print(value)
+    if COUNT==1000: print("Reached 1000 events. Stopping printout except when value>1")
+    if value>1: print(value)
+    return value
+
+def OrderChecker(arrDict):
+    x=0
+    for name in arrDict.keys():
+        arrDict[name]=deepcopy(MainArrDict[name])
+        print(arrDict[name]['array'])
+
+    for event in t:
+        x+=1
+        if x%10**5==0: print(x)
+
+def getRunFiles(rnum,dataDir="/eos/experiment/faser/phys/2022/r0013/"):
+    dataDir=f"{dataDir}{rnum}/"
+    return [sorted(glob(f"{dataDir}/Faser*"))[0]]
+
+def getRunNums(dataDir="/eos/experiment/faser/phys/2022/r0013/"):
+    return [rn.split(dataDir)[1] for rn in sorted(glob(f"{dataDir}*"))]
+
+#EXECUTE
+if __name__ == "__main__":
+    runnum = 110031#'009148'
+    # Utilise multiple cores
+    R.EnableImplicitMT()
+    R.gROOT.SetBatch(True)
+    
+    # Create Dataframe
+    #df = R.RDataFrame("nt", f"/eos/experiment/faser/phys/2022/r0013/{runnum}/Faser-Physics-{runnum}-*-PHYS.root") #DATA
+    df = R.RDataFrame("nt", f"/eos/experiment/faser/sim/mc22/foresee/{runnum}/phy/r0013/FaserMC-MC22_FS_Aee_*-PHYS.root") #SIM
+
+    filterstr=RootFilterFromDict(WAVEFORMD)
+    #df.Filter(filterstr)
+    #df.Draw("Track_p0")
+    histo = df.Histo1D(("Track_p0", "; Pmag_up; NTracks", 100, 0, 10**10), "Track_p0")
+    c = R.TCanvas()
+    histo.Draw()
+    
+    input()
\ No newline at end of file
diff --git a/Tracker/TrackerRecAlgs/PairVertex/scripts/PairVertexReader.py b/Tracker/TrackerRecAlgs/PairVertex/scripts/PairVertexReader.py
index 76947280..953b35c2 100644
--- a/Tracker/TrackerRecAlgs/PairVertex/scripts/PairVertexReader.py
+++ b/Tracker/TrackerRecAlgs/PairVertex/scripts/PairVertexReader.py
@@ -327,6 +327,12 @@ MainArrDict={
         'descr':'How many clusters have energy deposits from both daughter particles?',
         'SepHist':'arrays allowed to have different lengths'
     },
+    'TrackCount':{
+        'array':[],
+        'lambda': lambda event: event.TrackCount,
+        'plotterfunc': configBasicHist,
+        'plotkwargs' : {'kwargs':{'range':[0,25]},'pckwargs':{}}
+    },
     
     }
 
@@ -393,18 +399,30 @@ def GeneralPlotter(arrDict,dcuts=[],lcuts=[],showplot=True,savefig=False,titleex
 
         print()
 
+def OrderChecker(arrDict):
+    nans=0
+    for name in arrDict.keys():
+        arrDict[name]=deepcopy(MainArrDict[name])
+        print(arrDict[name]['array'])
+
+    for event in t:
+        x=1
 
 #EXECUTE
 if __name__ == "__main__":
-    DP_fnames=['Ntuple_FaserMC_MC22_FS_Aee_100MeV_1Em5']#  'Ntuple_Aee_10MeV_1Em4_' 'Ntuple_Aee_100MeV_1Em5_','Ntuple_Aee_10MeV_1Em5_', ,'Ntuple_Amm_316MeV_2Em6_' .root
+    DP_fnames=['Ntuple_Aee_100MeV_1Em5_']#  'Ntuple_Aee_10MeV_1Em4_' '','Ntuple_Aee_10MeV_1Em5_', ,'Ntuple_Amm_316MeV_2Em6_' .root
+    #r0013  Ntuple_FaserMC_MC22_FS_Aee_100MeV_1Em5
     for f in DP_fnames:
         user_input=f
         t = TChain("events") 
         nfiles = 0
-        nfiles += t.Add("/eos/home-s/sshively/CALYPZONE/run/"+user_input+".root") 
+        nfiles += t.Add("/eos/home-s/sshively/CALYPZONE/run/BackUp2/"+user_input+".root") 
         print(f)
 
-        GeneralPlotter(MakePlotDict('RecoMaxMomentum'),dcuts=[{}],lcuts=[])
+        OrderChecker(MakePlotDict('TrackCount'))
+        # GeneralPlotter(MakePlotDict('TrackCount'),dcuts=[{}],lcuts=[],label='No Cuts',showplot=False)
+        # GeneralPlotter(MakePlotDict('TrackCount'),dcuts=[WaveformCuts],lcuts=WaveformCuts2,label='WF Cut')
+        # GeneralPlotter(MakePlotDict('TrackCount'),dcuts=[{}],lcuts=[lambda e: e.Calo0_integral+e.Calo1_integral+e.Calo2_integral+e.Calo3_integral>10**5],label='>1 TeV cut',)
 
     
 
diff --git a/Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelper.py b/Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelper.py
index db770dea..50c4686c 100644
--- a/Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelper.py
+++ b/Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelper.py
@@ -6,6 +6,8 @@ from ROOT import TEfficiency, TH1F
 def PlotConfigs(xscale='linear',yscale='linear',xlim=None,ylim=None,title=None,show=False,xticks=None,xlabel=None,ylabel='#Events',legend=False,legloc='best',save=False):
     plt.xscale(xscale)
     plt.yscale(yscale)
+    if xlim: plt.xlim(xlim)
+    if ylim: plt.ylim(ylim)
     if xticks: plt.xticks(xticks)
     if xlabel: plt.xlabel(xlabel)
     if ylabel: plt.ylabel(ylabel)
@@ -28,8 +30,9 @@ def configHitMap(arrays,bins=(50,50),pckwargs={'xlabel':"X (mm)",'ylabel':"Y (mm
 def configBasicHist(arr,bins=25,label=None,pckwargs={'xscale':'linear'},kwargs={},rrange=None):
     #1D Histogram
     if 'xscale' in pckwargs.keys() and 'log' in pckwargs['xscale']: 
-        if rrange:CorrectBinsForLog(arr,bins,pckwargs['xscale'],rrange=rrange)
-        else: bins=CorrectBinsForLog(arr,bins,pckwargs['xscale'])
+        #if rrange:CorrectBinsForLog(arr,bins,pckwargs['xscale'],rrange=rrange)
+        #else: 
+            bins=CorrectBinsForLog(arr,bins,pckwargs['xscale'])
     n, binsOut, patches = plt.hist(arr,bins=bins,label=label,align="left",histtype=u'step',**kwargs)
     PlotConfigs(**pckwargs)
 
@@ -92,17 +95,23 @@ def PlotRootRatio(arrlist,bins=15,hmin=0,hmax=10000,title=None):
 #Utilities
 def CorrectBinsForLog(arr,bins,xscale,rrange=None):
     minx,maxx = (min(arr),max(arr))
-    if rrange!=None:  minx,maxx = (rrange[0],rrange[1])
+    if rrange!=None:  
+        minx,maxx = (rrange[0],rrange[1])
     if minx==maxx: 
         maxx+=1
         bins=1
-    bins = logspace(start=log10(minx), stop=log10(maxx), num=bins)
+    minx=10.0**3
+    maxx=10.0**11
+    bins2 = logspace(start=log10(minx), stop=log10(maxx), num=bins)
     if xscale=='symlog':
-        bins = [0]+list(logspace(start=log10(1), stop=log10(maxx), num=24))
-        if minx>1: bins = logspace(start=log10(minx), stop=log10(maxx), num=25)
+        bins2 = [0]+list(logspace(start=log10(1), stop=log10(maxx), num=24))
+        if minx>1: bins2 = logspace(start=log10(minx), stop=log10(maxx), num=25)
 
-    return bins
+    return bins2
 
+def PlotTrackEfficiency(x,y,label=''):
+    plt.plot(x,y,label=label)
+    plt.scatter(x,y)
 
     
 
diff --git a/Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelperROOT.py b/Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelperROOT.py
new file mode 100644
index 00000000..db770dea
--- /dev/null
+++ b/Tracker/TrackerRecAlgs/PairVertex/scripts/PlotHelperROOT.py
@@ -0,0 +1,108 @@
+from numpy import log10,logspace
+from cmcrameri import cm
+import matplotlib.pyplot as plt
+from ROOT import TEfficiency, TH1F
+
+def PlotConfigs(xscale='linear',yscale='linear',xlim=None,ylim=None,title=None,show=False,xticks=None,xlabel=None,ylabel='#Events',legend=False,legloc='best',save=False):
+    plt.xscale(xscale)
+    plt.yscale(yscale)
+    if xticks: plt.xticks(xticks)
+    if xlabel: plt.xlabel(xlabel)
+    if ylabel: plt.ylabel(ylabel)
+    if legend: plt.legend(loc=legloc)
+    if title:plt.title(title)
+    if show: plt.show()
+    #filename = title.replace(" ", "_").replace("(", "").replace(")", "")
+    #if save: plt.savefig(filename)
+
+
+def configHitMap(arrays,bins=(50,50),pckwargs={'xlabel':"X (mm)",'ylabel':"Y (mm)"},counts=False,kwargs={}):
+    #2D Histogram with colors
+    arrayx=arrays[0]
+    arrayy=arrays[1]
+    plt.hist2d(arrayx, arrayy, bins=bins, cmap=cm.imola,**kwargs)
+    plt.colorbar()
+    if counts: plt.text(50,-185,"#EVENTS: {}".format(len(arrayx)))
+    PlotConfigs(**pckwargs)
+
+def configBasicHist(arr,bins=25,label=None,pckwargs={'xscale':'linear'},kwargs={},rrange=None):
+    #1D Histogram
+    if 'xscale' in pckwargs.keys() and 'log' in pckwargs['xscale']: 
+        if rrange:CorrectBinsForLog(arr,bins,pckwargs['xscale'],rrange=rrange)
+        else: bins=CorrectBinsForLog(arr,bins,pckwargs['xscale'])
+    n, binsOut, patches = plt.hist(arr,bins=bins,label=label,align="left",histtype=u'step',**kwargs)
+    PlotConfigs(**pckwargs)
+
+    return n,binsOut
+
+def configMultiHist(arrlist,bins=25,label=[],pckwargs={'xscale':'linear','legloc':'upper left'},kwargs={}):
+    #1D Histogram for comparison
+    megarr=[]
+    for a in arrlist: megarr+=a
+
+    if 'log' in pckwargs['xscale']: bins=CorrectBinsForLog(megarr,bins,pckwargs['xscale'])
+    for iarr in range(len(arrlist)):
+        arr=arrlist[iarr]
+        labelused=''
+        if len(arr)==0:
+            print(f"Empty array.")
+        else: 
+            if len(label)==len(arrlist): labelused=label[iarr]
+            else: 
+                print("Insufficient labels given.")
+            plt.hist(arr,bins=bins,align="left",histtype=u'step',label=labelused,**kwargs)
+        
+    PlotConfigs(**pckwargs)
+
+def config2DScatter(arrlist,pckwargs=dict(),kwargs={}):
+    x=arrlist[0]
+    y=arrlist[1]
+    # plt.ylim(-25,25)
+    # plt.xlim(-10**-5,10**-5)
+    plt.scatter(x,y,**kwargs)
+    PlotConfigs(**pckwargs)
+
+def PrintBoolPercent(arr,kwargs={}):
+    #For an array of boolians, print out the % of elements that are "true".
+    n=0.0
+    d=len(arr)
+    for x in arr:
+        if x: n+=1.0
+    
+    finalval= (n/d)*100
+    print("Calculating...")
+    print(f"{n}/{d}")
+    print('Percent:'+'{:.2f}'.format(finalval)+'%')
+
+def PlotRootRatio(arrlist,bins=15,hmin=0,hmax=10000,title=None):
+
+    narray,darray=arrlist[0],arrlist[1]
+    h_numerator=TH1F("num","num",bins,hmin,hmax)
+    h_denominator=TH1F("den","den",bins,hmin,hmax)
+    for i in narray: h_numerator.Fill(i)
+    for j in darray: h_denominator.Fill(j)
+
+    h_ratio = TEfficiency(h_numerator,h_denominator)
+    c = h_ratio.CreateGraph()
+    c.GetYaxis().SetLimits(0.0, 1.05)
+    if title: h_ratio.SetTitle(title)
+    h_ratio.Draw("ep")
+    input()
+
+#Utilities
+def CorrectBinsForLog(arr,bins,xscale,rrange=None):
+    minx,maxx = (min(arr),max(arr))
+    if rrange!=None:  minx,maxx = (rrange[0],rrange[1])
+    if minx==maxx: 
+        maxx+=1
+        bins=1
+    bins = logspace(start=log10(minx), stop=log10(maxx), num=bins)
+    if xscale=='symlog':
+        bins = [0]+list(logspace(start=log10(1), stop=log10(maxx), num=24))
+        if minx>1: bins = logspace(start=log10(minx), stop=log10(maxx), num=25)
+
+    return bins
+
+
+    
+
diff --git a/Tracker/TrackerRecAlgs/PairVertex/scripts/Utilities.py b/Tracker/TrackerRecAlgs/PairVertex/scripts/Utilities.py
index 03d4cba8..01db4344 100644
--- a/Tracker/TrackerRecAlgs/PairVertex/scripts/Utilities.py
+++ b/Tracker/TrackerRecAlgs/PairVertex/scripts/Utilities.py
@@ -7,7 +7,7 @@ from operator import lt,eq,ne,gt
 from numpy import nan, seterr, inf,arctan, array
 from numpy import sum as npsum
 import numpy as np
-from math import sqrt
+from math import sqrt,isnan
 print("Other stuff loaded.")
 
 user_input=''
@@ -31,7 +31,11 @@ def ApplyCut(event, cut):
             try:
                 if cut[attr][i]!=None: 
                     value = getattr(event,attr)
-                    bool1 += [tests[i](value,cut[attr][i]) and value != inf and value !=nan and value !=-1*inf]
+                    #print(value)
+                    if 'Veto' in attr: 
+                        if isnan(value): value=0
+                        bool1 += [tests[i](value,cut[attr][i]) and value != inf and value !=-1*inf]
+                    else: bool1 += [tests[i](value,cut[attr][i]) and value != inf and not isnan(value) and value !=-1*inf]
                     if not all(bool1): break
             except AttributeError:
                 if attr not in missingattr:
-- 
GitLab