SND@LHC Software
Loading...
Searching...
No Matches
Scifi_monitoring.py
Go to the documentation of this file.
1#!/usr/bin/env python
2import ROOT,os,sys
3import rootUtils as ut
4import shipunit as u
5import ctypes
6from array import array
7import numpy as np
8
9A,B = ROOT.TVector3(),ROOT.TVector3()
10parallelToZ = ROOT.TVector3(0., 0., 1.)
11detector = "scifi-"
12class Scifi_hitMaps(ROOT.FairTask):
13 " produce hitmaps for Scifi"
14 def Init(self,options,monitor):
15 self.M = monitor
16 h = self.M.h
17 ioman = ROOT.FairRootManager.Instance()
18 self.OT = ioman.GetSink().GetOutTree()
19 if self.M.fsdict or self.M.hasBunchInfo : self.xing = {'':True,'B1only':False,'B2noB1':False,'noBeam':False}
20 else: self.xing = {'':True}
21 self.mat_label = {}
22 self.nScifi = self.M.Scifi.GetConfParI("Scifi/nscifi")
23 self.nMats = self.M.Scifi.GetConfParI("Scifi/nmats")
24 self.nMatsAll = self.nScifi*self.nMats*2
25 for xi in self.xing:
26 for s in range(2*self.nScifi):
27 ut.bookHist(h,detector+'posX_'+str(s)+xi,'x; x [cm]',2000,-100.,100.)
28 ut.bookHist(h,detector+'posY_'+str(s)+xi,'y; y[cm]',2000,-100.,100.)
29 if s%2==1: ut.bookHist(h,detector+'mult_'+str(s)+xi,'mult vertical station '+str(s//2+1)+'; #hits',100,-0.5,99.5)
30 else: ut.bookHist(h,detector+'mult_'+str(s)+xi,'mult horizontal station '+str(s//2+1)+'; #hits',100,-0.5,99.5)
31 for mat in range(self.nMatsAll):
32 s = mat//6
33 p = 'H'
34 if mat%6>2: p='V'
35 m = mat%3
36 ut.bookHist(h,detector+'mat_'+str(mat)+xi,'hit map station '+str(s)+p+' mat '+str(m)+'; #channel',512,-0.5,511.5)
37 ut.bookHist(h,detector+'sig_'+str(mat)+xi,'signal '+str(s)+p+' mat '+str(m)+'; QDC [a.u.]',200,-50.0,150.)
38 ut.bookHist(h,detector+'tdc_'+str(mat)+xi,'tdc '+str(s)+p+' mat '+str(m)+'; timestamp [LHC clock cycles]',200,-1.,4.)
39 if xi=='': self.mat_label[mat] = str(s)+p+' mat '+str(m)
40 def ExecuteEvent(self,event):
41 h = self.M.h
42 W = self.M.Weight
43 mult = [0]*10
44 for aHit in event.Digi_ScifiHits:
45 if not aHit.isValid(): continue
46 X = self.M.Scifi_xPos(aHit.GetDetectorID())
47 self.M.fillHist1(detector+'mat_'+str(X[0]*3+X[1]),X[2])
48 self.M.fillHist1(detector+'sig_'+str(X[0]*3+X[1]),aHit.GetSignal(0))
49 self.M.fillHist1(detector+'tdc_'+str(X[0]*3+X[1]),aHit.GetTime(0))
50 self.M.Scifi.GetSiPMPosition(aHit.GetDetectorID(),A,B)
51 if aHit.isVertical(): self.M.fillHist1(detector+'posX_'+str(X[0]),A[0])
52 else: self.M.fillHist1(detector+'posY_'+str(X[0]),A[1])
53 mult[X[0]]+=1
54 for s in range(10):
55 self.M.fillHist1(detector+'mult_'+str(s),mult[s])
56 def Plot(self):
57 h = self.M.h
58 # parameters for the signal median
59 q05=np.array([0.5])
60 med=np.array([0.])
61 signal_attributes={}
62 for xi in self.xing:
63 if not self.M.fsdict and not self.M.hasBunchInfo and xi!='': continue
64 ut.bookCanvas(h,detector+'hitmaps'+xi,' ',1024,768,6,5)
65 ut.bookCanvas(h,detector+'signal'+xi,' ',1024,768,6,5)
66 ut.bookCanvas(h,detector+'tdc'+xi,' ',1024,768,6,5)
67 for mat in range(self.nMatsAll):
68 tc = self.M.h[detector+'hitmaps'+xi].cd(mat+1)
69 tc.SetLogy(1)
70 self.M.h[detector+'mat_'+str(mat)+xi].Draw()
71 ROOT.gStyle.SetOptStat(10)
72 tc = self.M.h[detector+'signal'+xi].cd(mat+1)
73 rc = self.M.h[detector+'sig_'+str(mat)+xi]
74 rc.Draw()
75 rc.GetQuantiles(1,med,q05)
76 signal_attributes[mat]={"median":med[0],
77 "std":rc.GetStdDev(),
78 "max":rc.FindLastBinAbove(0),
79 "percent_overflow":rc.GetBinContent(rc.GetNbinsX()+1)/rc.Integral()*100. if rc.Integral()>0 else 0.}
80 tc = self.M.h[detector+'tdc'+xi].cd(mat+1)
81 self.M.h[detector+'tdc_'+str(mat)+xi].Draw()
82
83# summary canvases of the median, maximum and overflow of signals
84 # overflow is always 0, so skip it
85 ut.bookCanvas(h,detector+'signalsSummary'+xi,' ',1024,768,1,1)
86 signal_medians, signal_maxima = ROOT.TGraphErrors(), ROOT.TGraphErrors()
87 signal_medians.SetTitle("Median of signal per mat")
88 signal_medians.GetYaxis().SetTitle("median QDC [a.u.]")
89 signal_maxima.SetTitle("Maximal signal per mat")
90 signal_maxima.GetYaxis().SetTitle("maximum QDC [a.u.]")
91 Area = {}
92 for mat in range(self.nMatsAll):
93 signal_medians.SetPoint(mat, mat,signal_attributes[mat]["median"])
94 signal_medians.SetPointError(mat,0,signal_attributes[mat]["std"])
95 signal_maxima.SetPoint(mat, mat,signal_attributes[mat]["max"])
96 signal_maxima.SetPointError(mat,0,0)
97 graph_list = [signal_medians]
98 for counter, graph in enumerate(graph_list):
99 h[detector+'signalsSummary'+xi].cd(counter+1)
100 ROOT.gPad.SetBottomMargin(0.2)
101 ROOT.gPad.SetGrid(0)
102 graph.Draw('AP')
103 xAxis = graph.GetXaxis()
104 # get rid of the original ticks
105 xAxis.SetTickLength(0)
106 ymin = graph.GetHistogram().GetMinimum()
107 ymax = graph.GetHistogram().GetMaximum()
108 for mat in range(self.nMatsAll):
109 bin_index = xAxis.FindBin(mat)
110 xAxis.SetBinLabel(bin_index,self.mat_label[mat])
111 # Draw custom grid lines for the X axis
112 grid = ROOT.TLine(graph.GetPointX(mat), ymin, graph.GetPointX(mat), ymax)
113 grid.SetLineStyle(3)
114 grid.DrawClone()
115 # Draw ticks
116 tick = ROOT.TLine(graph.GetPointX(mat), ymin, graph.GetPointX(mat), ymin + 0.03*(ymax-ymin))
117 tick.DrawClone()
118 # redraw the graph
119 graph.Draw('P,same')
120 # draw a bkg
121 Area[counter] = ROOT.TBox(ROOT.TMath.MinElement(graph.GetN(), graph.GetX()),
122 graph.GetHistogram().GetMinimum(),
123 ROOT.TMath.MaxElement(graph.GetN(), graph.GetX()),
124 graph.GetHistogram().GetMaximum())
125 Area[counter].SetLineWidth(0)
126 Area[counter].SetFillStyle(3003)
127 Area[counter].SetFillColor(ROOT.kBlue)
128 Area[counter].Draw("same")
129 graph.SetMarkerStyle(20)
130 graph.SetMarkerColor(ROOT.kBlue)
131 graph.SetLineColor(ROOT.kBlue)
132# end of the summary QDC shifter canvases
133
134 ut.bookCanvas(h,detector+'positions'+xi,' ',2048,768,5,2)
135 ut.bookCanvas(h,detector+'mult'+xi,' ',2048,768,5,2)
136 for s in range(5):
137 tc = self.M.h[detector+'positions'+xi].cd(s+1)
138 self.M.h[detector+'posY_'+str(2*s)+xi].Draw()
139 tc = self.M.h[detector+'positions'+xi].cd(s+6)
140 self.M.h[detector+'posX_'+str(2*s+1)+xi].Draw()
141
142 tc = self.M.h[detector+'mult'+xi].cd(s+1)
143 tc.SetLogy(1)
144 self.M.h[detector+'mult_'+str(2*s)+xi].Draw()
145 tc = self.M.h[detector+'mult'+xi].cd(s+6)
146 tc.SetLogy(1)
147 self.M.h[detector+'mult_'+str(2*s+1)+xi].Draw()
148
149 for item in h:
150 if isinstance(h[item], ROOT.TH2):
151 h[item].SetStats(0)
152
153 canvas = detector+'signalsSummary'+xi
154 self.M.h[canvas].Update()
155 if xi!='': self.M.myPrint(self.M.h[canvas],"Scifi-"+canvas,subdir='scifi/shifter/'+xi)
156 else: self.M.myPrint(self.M.h[canvas],"Scifi-"+canvas,subdir='scifi/shifter')
157
158 for canvas in [detector+'hitmaps'+xi,detector+'signal'+xi,detector+'mult'+xi]:
159 self.M.h[canvas].Update()
160 if canvas.find('hitmaps')>0: role='shifter'
161 else : role='expert'
162 if xi!='': self.M.myPrint(self.M.h[canvas],"Scifi-"+canvas,subdir='scifi/'+role+'/'+xi)
163 else: self.M.myPrint(self.M.h[canvas],"Scifi-"+canvas,subdir='scifi/'+role)
164
165class Scifi_residuals(ROOT.FairTask):
166 " produce residuals for Scifi"
167 def Init(self,options,monitor):
168 NbinsRes = options.ScifiNbinsRes
169 xmin = options.Scifixmin
170 alignPar = options.ScifialignPar
171 self.unbiased = options.ScifiResUnbiased
172
173 self.M = monitor
174 h = self.M.h
175 self.projs = {1:'V',0:'H'}
176 self.parallelToZ = ROOT.TVector3(0., 0., 1.)
177 run = ROOT.FairRunAna.Instance()
178 ioman = ROOT.FairRootManager.Instance()
179 self.OT = ioman.GetSink().GetOutTree()
180 self.nav = ROOT.gGeoManager.GetCurrentNavigator()
181 self.trackTask = self.M.FairTasks['simpleTracking']
182 if not self.trackTask: self.trackTask = run.GetTask('houghTransform')
183
184 for s in range(1,6):
185 for o in range(2):
186 for p in self.projs:
187 proj = self.projs[p]
188 xmax = -xmin
189 ut.bookHist(h,'res'+proj+'_Scifi'+str(s*10+o),'residual '+proj+str(s*10+o)+'; [#mum]',NbinsRes,xmin,xmax)
190 ut.bookHist(h,'resX'+proj+'_Scifi'+str(s*10+o),'residual '+proj+str(s*10+o)+'; [#mum]',NbinsRes,xmin,xmax,100,-50.,0.)
191 ut.bookHist(h,'resY'+proj+'_Scifi'+str(s*10+o),'residual '+proj+str(s*10+o)+'; [#mum]',NbinsRes,xmin,xmax,100,10.,60.)
192 ut.bookHist(h,'resC'+proj+'_Scifi'+str(s*10+o),'residual '+proj+str(s*10+o)+'; [#mum]',NbinsRes,xmin,xmax,128*4*3,-0.5,128*4*3-0.5)
193 ut.bookHist(h,'track_Scifi'+str(s*10+o),'track x/y '+str(s*10+o)+'; x [cm]; y [cm]',80,-70.,10.,80,0.,80.)
194 ut.bookHist(h,'dx','DS track X - scifi X; X[cm]',100,-20.,20.)
195 ut.bookHist(h,'dy','DS track Y - scifi Y; Y[cm]',100,-20.,20.)
196
197 ut.bookHist(h,detector+'trackChi2/ndof','track chi2/ndof vs ndof; #chi^{2}/Ndof; Ndof',100,0,100,20,0,20)
198# type of crossing, check for b1only,b2nob1,nobeam
199 self.xing = {'':True,'B1only':False,'B2noB1':False,'noBeam':False}
200 '''
201 for xi in self.xing:
202 if not self.M.fsdict and not self.M.hasBunchInfo and xi!='': continue
203 ut.bookHist(h,detector+'trackSlopes'+xi,'track slope; x/z [mrad]; y/z [mrad]',1000,-100,100,1000,-100,100)
204 ut.bookHist(h,detector+'trackSlopesXL'+xi,'track slope; x/z [rad]; y/z [rad]',2200,-1.1,1.1,2200,-1.1,1.1)
205 ut.bookHist(h,detector+'trackPos'+xi,'track pos; x [cm]; y [cm]',100,-90,10.,80,0.,80.)
206 ut.bookHist(h,detector+'trackPosBeam'+xi,'beam track pos slopes<0.1rad; x [cm]; y [cm]',100,-90,10.,80,0.,80.)
207 for item in h:
208 if isinstance(h[item], ROOT.TH2) and (item.find('trackPos')>0 or item.find('trackSlopes')>0):
209 h[item].SetTitleOffset(1.1, 'Y')
210 '''
211 if alignPar:
212 for x in alignPar:
213 self.M.Scifi.SetConfPar(x,alignPar[x])
214
215 self.zExVeto = self.M.zPos['MuFilter'][10]
216 self.zEx = self.M.zPos['Scifi'][10]
217 self.res = 10.
218
219 def ExecuteEvent(self,event):
220 h = self.M.h
221 W = self.M.Weight
222 nav = self.nav
223 if not hasattr(event,"Cluster_Scifi"):
224 self.trackTask.scifiCluster()
225 clusters = self.trackTask.clusScifi
226 else:
227 clusters = event.Cluster_Scifi
228# overall tracking
229 MufiTracks = []
230 ScifiTracks = []
231 k = -1
232 for theTrack in self.M.Reco_MuonTracks:
233 k+=1
234 fitStatus = theTrack.getFitStatus()
235 if not fitStatus.isFitConverged(): continue
236 if theTrack.GetUniqueID()==1: ScifiTracks.append(k)
237 if theTrack.GetUniqueID()==3: MufiTracks.append(k)
238 if len(MufiTracks)==0 or len(ScifiTracks)==0: return
239 vetoHits = []
240 k = -1
241 for aHit in event.Digi_MuFilterHits:
242 k+=1
243 Minfo = self.M.MuFilter_PlaneBars(aHit.GetDetectorID())
244 s,l,bar = Minfo['station'],Minfo['plane'],Minfo['bar']
245 if s>1: continue
246 X = aHit.GetAllSignals()
247 if len(X)<5: continue # number of fired SiPMs
248 vetoHits.append(k)
249 xExTag,yExTag = -10000,-10000
250 for kMu in MufiTracks:
251 theTrack = self.M.Reco_MuonTracks[kMu]
252 fstate = theTrack.getFittedState()
253 posT,momT = fstate.getPos(),fstate.getMom()
254 slopeXT = momT.X()/momT.Z()
255 slopeYT = momT.Y()/momT.Z()
256 if not abs(slopeXT)<0.1 or not abs(slopeYT)<0.1: continue
257 lam = (self.zEx-posT.z())/momT.z()
258 yExTag = posT.y()+lam*momT.y()
259 xExTag = posT.x()+lam*momT.x()
260 # eventually require hit in veto to remove ghost tracks
261 if xExTag < -9000: return
262 ok = False
263 for k in vetoHits:
264 aHit = event.Digi_MuFilterHits[k]
265 self.M.MuFilter.GetPosition(aHit.GetDetectorID(),A,B)
266# calculate DOCA
267 lam = (self.zExVeto-posT.z())/momT.z()
268 xExV,yExV = posT.x()+lam*momT.x(),posT.y()+lam*momT.y()
269 pq = A-posT
270 uCrossv= (B-A).Cross(momT)
271 doca = pq.Dot(uCrossv)/uCrossv.Mag()
272 if abs(doca)<self.res:
273 ok=True
274 break
275 if not ok: return
276 # DS track confirmed by Veto hit
277
278 theTrack = False
279 for theTrack in self.M.Reco_MuonTracks:
280 if theTrack.GetUniqueID()==1:
281 fitStatus = theTrack.getFitStatus()
282 if fitStatus.isFitConverged():
283 state = theTrack.getFittedState()
284 pos = state.getPos()
285 mom = state.getMom()
286 slopeX = mom.X()/mom.Z()
287 slopeY = mom.Y()/mom.Z()
288 rc = h[detector+'trackChi2/ndof'].Fill(fitStatus.getChi2()/(fitStatus.getNdf()+1E-10),fitStatus.getNdf())
289 '''
290 self.M.fillHist2(detector+'trackSlopes',slopeX*1000-pos.X()/48.2,slopeY*1000-pos.Y()/48.2)
291 self.M.fillHist2(detector+'trackSlopesXL',slopeX-pos.X()/48200,slopeY-pos.Y()/48200)
292 self.M.fillHist2(detector+'trackPos',pos.X(),pos.Y())
293 if abs(slopeX)<0.1 and abs(slopeY)<0.1: self.M.fillHist2(detector+'trackPosBeam',pos.X(),pos.Y())
294 '''
295
296 if not theTrack: return
297
298 sortedClusters={}
299 for aCl in clusters:
300 so = aCl.GetFirst()//100000
301 if not so in sortedClusters: sortedClusters[so]=[]
302 sortedClusters[so].append(aCl)
303# select events with clusters in each plane for making residuals
304 if len(sortedClusters)<10: return
305 goodEvent = True
306 for s in sortedClusters:
307 if len(sortedClusters[s])>3:
308 goodEvent=False
309 break
310 if not goodEvent: return
311
312 for s in range(1,6):
313 if self.unbiased:
314# build trackCandidate
315 hitlist = {}
316 if self.unbiased or s==1:
317 k=0
318 Nproj = {0:0,1:0}
319 for so in sortedClusters:
320 if so//10 == s and self.unbiased: continue
321 Nproj[so%2]+=1
322 for x in sortedClusters[so]:
323 hitlist[k] = x
324 k+=1
325 if Nproj[0]<3 or Nproj[1]<3: continue
326 theTrack = self.trackTask.fitTrack(hitlist)
327 if not hasattr(theTrack,"getFittedState"): continue
328# check residuals
329 fitStatus = theTrack.getFitStatus()
330 if not fitStatus.isFitConverged():
331 theTrack.Delete()
332 continue
333# confirm track with DS track
334 fstate = theTrack.getFittedState()
335 pos,mom = fstate.getPos(),fstate.getMom()
336 lam = (self.zExVeto-pos.z())/mom.z()
337 yEx = pos.y()+lam*mom.y()
338 xEx = pos.x()+lam*mom.x()
339 dx = xExTag-xEx
340 dy = yExTag-yEx
341 rc = h['dx'].Fill(dx)
342 rc = h['dy'].Fill(dy)
343 if abs(dy)>self.res or abs(dx)>self.res:
344 if self.unbiased: continue
345 else: break
346
347# test plane
348 for o in range(2):
349 testPlane = s*10+o
350 z = self.M.zPos['Scifi'][testPlane]
351 rep = ROOT.genfit.RKTrackRep(13)
352 state = ROOT.genfit.StateOnPlane(rep)
353# find closest track state
354 mClose = 0
355 mZmin = 999999.
356 for m in range(0,theTrack.getNumPointsWithMeasurement()):
357 st = ROOT.getFittedState(theTrack,m)
358 if not st: break
359 Pos = st.getPos()
360 if abs(z-Pos.z())<mZmin:
361 mZmin = abs(z-Pos.z())
362 mClose = m
363 if mZmin>10000:
364 print("something wrong here with measurements",mClose,mZmin,theTrack.getNumPointsWithMeasurement())
365 break
366 fstate = theTrack.getFittedState(mClose)
367 pos,mom = fstate.getPos(),fstate.getMom()
368 rep.setPosMom(state,pos,mom)
369 NewPosition = ROOT.TVector3(0., 0., z) # assumes that plane in global coordinates is perpendicular to z-axis, which is not true for TI18 geometry.
370 rep.extrapolateToPlane(state, NewPosition, parallelToZ )
371 pos = state.getPos()
372 xEx,yEx = pos.x(),pos.y()
373 rc = h['track_Scifi'+str(testPlane)].Fill(xEx,yEx,W)
374 for aCl in sortedClusters[testPlane]:
375 aCl.GetPosition(A,B)
376 detID = aCl.GetFirst()
377 channel = detID%1000 + ((detID%10000)//1000)*128 + (detID%100000//10000)*512
378# calculate DOCA
379 pq = A-pos
380 uCrossv= (B-A).Cross(mom)
381 doca = pq.Dot(uCrossv)/uCrossv.Mag()
382 rc = h['resC'+self.projs[o]+'_Scifi'+str(testPlane)].Fill(doca/u.um,channel,W)
383 rc = h['res'+self.projs[o]+'_Scifi'+str(testPlane)].Fill(doca/u.um,W)
384 rc = h['resX'+self.projs[o]+'_Scifi'+str(testPlane)].Fill(doca/u.um,xEx,W)
385 rc = h['resY'+self.projs[o]+'_Scifi'+str(testPlane)].Fill(doca/u.um,yEx,W)
386
387 if self.unbiased: theTrack.Delete()
388
389# analysis and plots
390 def Plot(self):
391 h = self.M.h
392 P = {'':'','X':'colz','Y':'colz','C':'colz'}
393 Par = {'mean':1,'sigma':2}
394 h['globalPos'] = {'meanH':ROOT.TGraphErrors(),'sigmaH':ROOT.TGraphErrors(),'meanV':ROOT.TGraphErrors(),'sigmaV':ROOT.TGraphErrors()}
395 h['globalPosM'] = {'meanH':ROOT.TGraphErrors(),'sigmaH':ROOT.TGraphErrors(),'meanV':ROOT.TGraphErrors(),'sigmaV':ROOT.TGraphErrors()}
396 for x in h['globalPosM']:
397 h['globalPos'][x].SetMarkerStyle(21)
398 h['globalPos'][x].SetMarkerColor(ROOT.kBlue)
399 h['globalPosM'][x].SetMarkerStyle(21)
400 h['globalPosM'][x].SetMarkerColor(ROOT.kBlue)
401 globalPos = h['globalPos']
402 for proj in P:
403 ut.bookCanvas(h,'scifiRes'+proj,'',1600,1900,2,5)
404 k=1
405 j = {0:0,1:0}
406 for s in range(1,6):
407 for o in range(2):
408 so = s*10+o
409 tc = h['scifiRes'+proj].cd(k)
410 k+=1
411 hname = 'res'+proj+self.projs[o]+'_Scifi'+str(so)
412 h[hname].Draw(P[proj])
413 if proj == '':
414 rc = h[hname].Fit('gaus','SQ')
415 fitResult = rc.Get()
416 if not fitResult: continue
417 for p in Par:
418 globalPos[p+self.projs[o]].SetPoint(s-1,s,fitResult.Parameter(Par[p]))
419 globalPos[p+self.projs[o]].SetPointError(s-1,0.5,fitResult.ParError(1))
420 if proj == 'C':
421 for m in range(3):
422 h[hname+str(m)] = h[hname].ProjectionX(hname+str(m),m*512,m*512+512)
423 rc = h[hname+str(m)].Fit('gaus','SQ0')
424 fitResult = rc.Get()
425 if not fitResult: continue
426 for p in Par:
427 h['globalPosM'][p+self.projs[o]].SetPoint(j[o], s*10+m, fitResult.Parameter(Par[p]))
428 h['globalPosM'][p+self.projs[o]].SetPointError(j[o],0.5,fitResult.ParError(1))
429 j[o]+=1
430
431 S = ctypes.c_double()
432 M = ctypes.c_double()
433 h['alignPar'] = {}
434 alignPar = h['alignPar']
435 for p in globalPos:
436 ut.bookCanvas(h,p,p,750,750,1,1)
437 tc = h[p].cd()
438 globalPos[p].SetTitle(p+';station; offset [#mum]')
439 globalPos[p].Draw("ALP")
440 if p.find('mean')==0:
441 for n in range(globalPos[p].GetN()):
442 rc = globalPos[p].GetPoint(n,S,M)
443 print("station %i: offset %s = %5.2F um"%(S.value,p[4:5],M.value))
444 s = int(S.value*10)
445 if p[4:5] == "V": s+=1
446 alignPar["Scifi/LocD"+str(s)] = M.value
447
448 ut.bookCanvas(h,'mean&sigma',"mean and sigma",1200,1200,2,2)
449 k=1
450 for p in h['globalPosM']:
451 ut.bookCanvas(h,p+'M',p,750,750,1,1)
452 tc = h[p+'M'].cd()
453 h['globalPosM'][p].SetTitle(p+';mat ; offset [#mum]')
454 h['globalPosM'][p].Draw("ALP")
455 tc = h['mean&sigma'].cd(k)
456 h['globalPosM'][p].Draw("ALP")
457 k+=1
458 if p.find('mean')==0:
459 for n in range(h['globalPosM'][p].GetN()):
460 rc = h['globalPosM'][p].GetPoint(n,S,M)
461 print("station %i: offset %s = %5.2F um"%(S.value,p[4:5],M.value))
462 s = int(S.value*10)
463 if p[4:5] == "V": s+=1
464 alignPar["Scifi/LocM"+str(s)] = M.value
465 T = ['mean&sigma']
466 for proj in P: T.append('scifiRes'+proj)
467 for canvas in T:
468 self.M.myPrint(self.M.h[canvas],"Scifi-"+canvas,subdir='scifi/expert')
469 '''
470 for xi in self.xing:
471 if not self.M.fsdict and not self.M.hasBunchInfo and xi!='': continue
472 tname = detector+'trackDir'+xi
473 ut.bookCanvas(h,tname,"track directions",1600,1800,3,2)
474 h[tname].cd(1)
475 rc = h[detector+'trackSlopes'+xi].Draw('colz')
476 h[tname].cd(2)
477 rc = h[detector+'trackSlopes'+xi].ProjectionX("slopeX"+xi)
478 rc.Draw()
479 rc.SetTitle('track X slope')
480 h[tname].cd(3)
481 rc = h[detector+'trackSlopes'+xi].ProjectionY("slopeY"+xi)
482 rc.Draw()
483 rc.SetTitle('track Y slope')
484 h[tname].cd(4)
485 rc = h[detector+'trackSlopesXL'+xi].Draw('colz')
486 h[tname].cd(5)
487 rc = h[detector+'trackSlopesXL'+xi].ProjectionX("slopeXL"+xi)
488 rc.Draw()
489 rc.SetTitle('track X slope')
490 h[tname].cd(6)
491 rc = h[detector+'trackSlopesXL'+xi].ProjectionY("slopeYL"+xi)
492 rc.Draw()
493 rc.SetTitle('track Y slope')
494 if x=='': self.M.myPrint(self.M.h[tname],tname,subdir='scifi/shifter')
495 else: self.M.myPrint(self.M.h[tname],tname,subdir='scifi/shifter/'+xi)
496 tname = detector+'TtrackPos'+xi
497 ut.bookCanvas(h,tname,"track position first state",600,1200,1,2)
498 h[tname].cd(1)
499 rc = h[detector+'trackPosBeam'+xi].Draw('colz')
500 h[tname].cd(2)
501 rc = h[detector+'trackPos'+xi].Draw('colz')
502 if x=='': self.M.myPrint(self.M.h[tname],detector+'trackPos'+xi,subdir='scifi/shifter')
503 else: self.M.myPrint(self.M.h[tname],detector+'trackPos'+xi,subdir='scifi/shifter/'+xi)
504 '''
505
506class Scifi_trackEfficiency(ROOT.FairTask):
507 " track efficiency tag with DS track"
508 def Init(self,options,monitor):
509 self.M = monitor
510 self.debug = False
511 h = self.M.h
512 ut.bookHist(h,'DStag','DS track X/Y at scifi 1; X[cm]; Y[cm]',100,-50,0.,100,10,60)
513 ut.bookHist(h,'Xdx','DS track X - scifi X; X[cm]',100,-20.,20.)
514 ut.bookHist(h,'Xdy','DS track Y - scifi Y; Y[cm]',100,-20.,20.)
515 ut.bookHist(h,'scifiTrack','scifi track X/Y at scifi 1; X[cm]; Y[cm]',100,-50,0.,100,10,60)
516 ut.bookHist(h,'USQDC','US QDC for matched tracks; qdc',220,-10,2190.)
517 ut.bookHist(h,'clSize','Scifi cluster size for matched tracks; n hits',10,-0.5,9.5)
518 ut.bookHist(h,'hitPerPlane','Scifi hits per detector ; n hits',50,-0.5,49.5)
519 ut.bookHist(h,'flightDir','flight direction',100,-20.,20.)
520 for s in range(6):
521 ut.bookHist(h,'XscifiTrack_'+str(s),'scifi track X/Y at scifi 1 missing station '+str(s)+'; X[cm]; Y[cm]',100,-50,0.,100,10,60)
522 if s==0: continue
523 ut.bookHist(h,'XscifiTrack_0'+str(s),'scifi track X/Y at scifi 1 missing station '+str(s)+'; X[cm]; Y[cm]',100,-50,0.,100,10,60)
524 for proj in range(2):
525 ut.bookHist(h,'XscifiTrack_'+str(10*s+proj),'scifi track X/Y at scifi 1 missing plane '+str(s*10+proj)+'; X[cm]; Y[cm]',100,-50,0.,100,10,60)
526 ut.bookHist(h,'2scifiTrack_1','scifi track X/Y at scifi 1 missing station 1 and 2; X[cm]; Y[cm]',100,-50,0.,100,10,60)
527 ut.bookHist(h,'2scifiTrack_01','scifi track X/Y at scifi 1 missing station 1 and 2; X[cm]; Y[cm]',100,-50,0.,100,10,60)
528 for proj in range(2):
529 ut.bookHist(h,'2scifiTrack_'+str(10*1+proj),'scifi track X/Y at scifi 1 missing plane '+str(proj)+' in 1 and 2; X[cm]; Y[cm]',100,-50,0.,100,10,60)
530 self.zEx = self.M.zPos['Scifi'][10]
531 self.zExVeto = self.M.zPos['MuFilter'][10]
532 self.res = 10.
533 self.unbiased = options.ScifiResUnbiased
534 self.masked = options.ScifiStationMasked
535 self.deadTime = 100
536 self.eventBefore={'T':-1,'N':-1,'hits':{1:0,0:0,'0L':0,'0R':0,'1L':0,'1R':0}}
537 def ExecuteEvent(self,event):
538 vetoHitsFromPrev = 0
539 if event.EventHeader.GetRunId() < 6204 and event.EventHeader.GetRunId() > 5480: vetoHitsFromPrev = 5
540 # special treatment for first 10fb-1 in 2023, wrong time alignment, again!
541 N1 = event.GetReadEntry()
542 Tcurrent = event.EventHeader.GetEventTime()
543 dT = abs(Tcurrent-self.eventBefore['T'])
544 prevAdded = False
545 vetoHits = []
546 USQDC = 0
547 for j in [0,-1]:
548 if j<0 and N1>0:
549 if dT > vetoHitsFromPrev: continue
550 rc = event.GetEvent(N1-1) # add veto hits from prev event
551 prevAdded = True
552 for aHit in event.Digi_MuFilterHits:
553 Minfo = self.M.MuFilter_PlaneBars(aHit.GetDetectorID())
554 s,l,bar = Minfo['station'],Minfo['plane'],Minfo['bar']
555 if s==2 and j==0: USQDC += aHit.SumOfSignals()['Sum']
556 if s>1: continue
557 X = aHit.GetAllSignals()
558 if len(X)<5: continue # number of fired SiPMs
559 vetoHits.append(aHit.GetDetectorID())
560 if prevAdded and N1>1:
561 rc = event.GetEvent(N1-2)
562 Tprevprev = event.EventHeader.GetEventTime()
563 dT = abs(Tcurrent-Tprevprev)
564 if prevAdded: event.GetEvent(N1)
565 prevEvent = False
566 if dT < self.deadTime and dT > vetoHitsFromPrev:
567 return
568 self.eventBefore['T'] = Tcurrent
569
570 h = self.M.h
571 W = self.M.Weight
572 MufiTracks = []
573 ScifiTracks = []
574 k = -1
575 for theTrack in self.M.Reco_MuonTracks:
576 k+=1
577 fitStatus = theTrack.getFitStatus()
578 if not fitStatus.isFitConverged(): continue
579 if theTrack.GetUniqueID()==1: ScifiTracks.append(k)
580 if theTrack.GetUniqueID()==3: MufiTracks.append(k)
581 if len(MufiTracks)==0: return
582
583 xExTag, yExTag = -10000,-10000
584 for kMu in MufiTracks:
585 theTrack = self.M.Reco_MuonTracks[kMu]
586 fstate = theTrack.getFittedState()
587 posT,momT = fstate.getPos(),fstate.getMom()
588 slopeXT = momT.X()/momT.Z()
589 slopeYT = momT.Y()/momT.Z()
590 if not abs(slopeXT)<0.1 or not abs(slopeYT)<0.1: continue
591 lam = (self.zEx-posT.z())/momT.z()
592 yExTag = posT.y()+lam*momT.y()
593 xExTag = posT.x()+lam*momT.x()
594 # eventually require hit in veto to remove ghost tracks
595 ok = False
596 for detID in vetoHits:
597 self.M.MuFilter.GetPosition(detID,A,B)
598# calculate DOCA
599 lam = (self.zExVeto-posT.z())/momT.z()
600 xExV,yExV = posT.x()+lam*momT.x(),posT.y()+lam*momT.y()
601 pq = A-posT
602 uCrossv= (B-A).Cross(momT)
603 doca = pq.Dot(uCrossv)/uCrossv.Mag()
604 if abs(doca)<self.res:
605 ok=True
606 break
607 if not ok: continue
608 rc = h['DStag'].Fill(xExTag,yExTag)
609 for kSc in ScifiTracks:
610 scifiTrack = self.M.Reco_MuonTracks[kSc]
611 fstate = scifiTrack.getFittedState()
612 pos,mom = fstate.getPos(),fstate.getMom()
613 lam = (self.zEx-pos.z())/mom.z()
614 yEx = pos.y()+lam*mom.y()
615 xEx = pos.x()+lam*mom.x()
616 dx = xExTag-xEx
617 dy = yExTag-yEx
618 rc = h['Xdx'].Fill(dx)
619 rc = h['Xdy'].Fill(dy)
620 if abs(dy)<self.res and abs(dx)<self.res:
621 rc = h['scifiTrack'].Fill(xExTag,yExTag)
622 rc = h['USQDC'].Fill(USQDC)
623 sortedClusters={}
624 NscifiTot = 0
625 for aCl in self.M.trackTask.clusScifi:
626 s = aCl.GetFirst()//100000
627 if not (s in sortedClusters): sortedClusters[s]=0
628 sortedClusters[s]+=aCl.GetN()
629 rc = h['clSize'].Fill(aCl.GetN())
630 for s in sortedClusters:
631 rc = h['hitPerPlane'].Fill(sortedClusters[s])
632# finished for Scifi track efficiency
633# start of Scifi plane inefficiency
634 if len(ScifiTracks) < 1: return
635 if xExTag< -9000 or not ok: return
636 sortedClusters={}
637 for aCl in self.M.trackTask.clusScifi:
638 so = aCl.GetFirst()//100000
639 if not so in sortedClusters: sortedClusters[so]=0
640 sortedClusters[so]+=1
641 trackClusters = {}
642 for x in self.M.trackTask.trackCandidates['Scifi'][0]:
643 aCl = self.M.trackTask.trackCandidates['Scifi'][0][x]
644 so = aCl.GetFirst()//100000
645 if not so in trackClusters: trackClusters[so]=0
646 trackClusters[so]+=1
647
648 for s in range(1,6):
649 # s is test station
650 if self.unbiased:
651 # build trackCandidate without s
652 self.M.trackTask.maskPlane = s
653 self.M.trackTask.fittedTracks.Delete()
654 self.M.trackTask.ExecuteTask(option='Scifi')
655 if self.M.trackTask.fittedTracks.GetEntries()==0: continue
656 theTrack = self.M.trackTask.fittedTracks[0]
657 if not hasattr(theTrack,"getFittedState"): continue
658 if not theTrack.getFitStatus().isFitConverged():
659 self.M.trackTask.fittedTracks.Delete()
660 continue
661 else:
662 # check that test station not required for making track
663 nproj = {0:0,1:0}
664 for aCl in trackClusters:
665 sq = aCl//10
666 if sq==s or self.masked.find(str(sq))>-0.5: continue
667 nproj[aCl%10]+=1
668 if nproj[0]<3 or nproj[1]<3: continue
669 theTrack = self.M.Reco_MuonTracks[ScifiTracks[0]]
670
671 flightDir = self.M.trackTask.trackDir(theTrack)
672 rc = h['flightDir'].Fill(flightDir[0])
673 if flightDir[0] < -100:
674 if self.unbiased: self.M.trackTask.fittedTracks.Delete()
675 continue
676 fstate = theTrack.getFittedState()
677 pos,mom = fstate.getPos(),fstate.getMom()
678 lam = (self.zEx-pos.z())/mom.z()
679 yEx = pos.y()+lam*mom.y()
680 xEx = pos.x()+lam*mom.x()
681 dx = xExTag-xEx
682 dy = yExTag-yEx
683 slopeX = mom.X()/mom.Z()
684 slopeY = mom.Y()/mom.Z()
685 if not abs(slopeX)<0.1 or not abs(slopeY)<0.1:
686 if self.unbiased: self.M.trackTask.fittedTracks.Delete()
687 continue
688 if abs(dy)>self.res or abs(dx)>self.res:
689 if self.unbiased: self.M.trackTask.fittedTracks.Delete()
690 continue
691 testPlane = 10*s
692 z = self.M.zPos['Scifi'][testPlane]
693 lam = (z-pos.z())/mom.z()
694 yEx = pos.y()+lam*mom.y()
695 xEx = pos.x()+lam*mom.x()
696 rc = h['XscifiTrack_0'+str(s)].Fill(xEx,yEx)
697 if not ( (s*10 in sortedClusters) or ( (s*10+1) in sortedClusters) ):
698 rc = h['XscifiTrack_'+str(s)].Fill(xEx,yEx)
699 if -39<xEx and xEx<-16 and 22<yEx and yEx<47 and self.debug:
700 print('inefficient scifi detector ',s,self.M.EventNumber,xEx,yEx,len(vetoHits))
701 if not (s*10 in sortedClusters):
702 rc = h['XscifiTrack_'+str(s*10)].Fill(xEx,yEx)
703 if not ((s*10+1) in sortedClusters):
704 rc = h['XscifiTrack_'+str(s*10+1)].Fill(xEx,yEx)
705 if s==1:
706 nproj = {0:0,1:0}
707 for aCl in trackClusters:
708 sq = aCl//10
709 if sq==2 or sq==1: continue
710 nproj[aCl%10]+=1
711 if nproj[0]<3 or nproj[1]<3: continue
712 rc = h['2scifiTrack_0'+str(s)].Fill(xEx,yEx)
713 if not ( (s*10 in sortedClusters) or ( (s*10+1) in sortedClusters) or ( (2*10) in sortedClusters) or ( (2*10+1) in sortedClusters) ):
714 rc = h['2scifiTrack_'+str(s)].Fill(xEx,yEx)
715 if not (s*10 in sortedClusters or 2*10 in sortedClusters ):
716 rc = h['2scifiTrack_'+str(s*10)].Fill(xEx,yEx)
717 if not ((s*10+1) in sortedClusters or (2*10+1) in sortedClusters):
718 rc = h['2scifiTrack_'+str(s*10+1)].Fill(xEx,yEx)
719 if self.unbiased:
720# restore original track
721 self.M.trackTask.maskPlane = -1
722 self.M.trackTask.fittedTracks.Delete()
723# analysis and plots
724 def Plot(self):
725 h = self.M.h
726 ut.bookCanvas(h,'dxdy','',1200,1200,2,1)
727 tc = h['dxdy'].cd(1)
728 h['Xdx'].Draw()
729 tc = h['dxdy'].cd(2)
730 h['Xdy'].Draw()
731 self.M.myPrint(h['dxdy'],'ScifiMufiPulls',subdir='scifi/expert')
732 ut.bookCanvas(h,'scifiEff','',1600,800,3,1)
733 tc = h['scifiEff'].cd(1)
734 h['DStag'].Draw('colz')
735 tc = h['scifiEff'].cd(2)
736 h['scifiTrack'].Draw('colz')
737 h['eff']=h['scifiTrack'].Clone('eff')
738 h['eff'].Divide(h['DStag'])
739 tc = h['scifiEff'].cd(3)
740 h['eff'].DrawCopy('colz')
741 self.M.myPrint(h['scifiEff'],'ScifiTrackEfficiency',subdir='scifi/expert')
742 limits = {1:{'X':[-44,-8],'Y':[16,50]},2:{'X':[-40,-12],'Y':[18,47]}}
743 bins = {}
744 for l in limits :
745 bins[l] = []
746 for p in limits[l]:
747 for x in limits[l][p]:
748 bins[l].append(eval('h["DStag"].Get'+p+'axis().FindBin(x)'))
749 e = h['scifiTrack'].Integral(bins[l][0],bins[l][1],bins[l][2],bins[l][3])/h['DStag'].Integral(bins[l][0],bins[l][1],bins[l][2],bins[l][3])*100
750 print('average efficiency: %5.2F<X<%5.2F %5.2F<Y<%5.2F = %5.2F%%'%(limits[l]['X'][0],limits[l]['X'][1],limits[l]['Y'][0],limits[l]['Y'][1],e))
751 # station inefficiency
752 ut.bookCanvas(h,'Tsineff','',1200,900,3,2)
753 sRef=1
754 border = [14.964849051657234, 54.00431913184336, -46.21974599493218, -7.146496817384938] # scifi 1 boundaries
755 h['TlineTop'+str(sRef)] = ROOT.TLine(border[2],border[1],border[3],border[1])
756 h['TlineBot'+str(sRef)] = ROOT.TLine(border[2],border[0],border[3],border[0])
757 h['TlineLef'+str(sRef)] = ROOT.TLine(border[2],border[0],border[2],border[1])
758 h['TlineRig'+str(sRef)] = ROOT.TLine(border[3],border[0],border[3],border[1])
759 for x in ['TlineTop'+str(sRef),'TlineBot'+str(sRef),'TlineLef'+str(sRef),'TlineRig'+str(sRef)]:
760 h[x].SetLineWidth(2)
761 h[x].SetLineColor(ROOT.kRed)
762 for s in range(1,6):
763 tc = h['Tsineff'].cd(s)
764 tc.SetRightMargin(0.1)
765 tc.SetLogz(1)
766 h['sineff'+str(s)] = h['XscifiTrack_'+str(s)].Clone('sineff'+str(s))
767 h['sineff'+str(s)].Divide(h['XscifiTrack_0'])
768 h['sineff'+str(s)].SetStats(0)
769 h['sineff'+str(s)].SetMaximum(0.1)
770 h['sineff'+str(s)].DrawCopy('colz')
771 for x in ['TlineTop'+str(sRef),'TlineBot'+str(sRef),'TlineLef'+str(sRef),'TlineRig'+str(sRef)]: h[x].Draw('same')
772 tc.Update()
773 for l in limits :
774 e = h['XscifiTrack_'+str(s)].Integral(bins[l][0],bins[l][1],bins[l][2],bins[l][3])/h['scifiTrack'].Integral(bins[l][0],bins[l][1],bins[l][2],bins[l][3])
775 print('average efficiency station: %2i %5.2F<X<%5.2F %5.2F<Y<%5.2F = %5.2G'%(s,limits[l]['X'][0],limits[l]['X'][1],limits[l]['Y'][0],limits[l]['Y'][1],e))
776 self.M.myPrint(h['Tsineff'],'ScifiStationInEfficiency',subdir='scifi/expert')
777 ut.bookCanvas(h,'Tqdc','',1200,900,1,1)
778 tc = h['Tqdc'].cd()
779 h['USQDC'].Draw()
780 self.M.myPrint(h['Tqdc'],'US QDC for muon track',subdir='mufilter/expert')
void GetPosition(Int_t id, TVector3 &vLeft, TVector3 &vRight)
Definition MuFilter.cxx:639
Init(self, options, monitor)
void GetSiPMPosition(Int_t SiPMChan, TVector3 &A, TVector3 &B)
Definition Scifi.cxx:625
void SetConfPar(TString name, Float_t value)
Definition Scifi.h:46
Int_t GetConfParI(TString name)
Definition Scifi.h:50