SND@LHC Software
Loading...
Searching...
No Matches
vetoTimeCalibration.py
Go to the documentation of this file.
1import ROOT,os,sys
2import rootUtils as ut
3import shipunit as u
4import pickle
5import ctypes
6from array import array
7import statistics
8
9A,B = ROOT.TVector3(),ROOT.TVector3()
10refChannel = 0
11detector = 'scifi'
12
13def FCN(npar, gin, f, par, iflag):
14#calculate chisquare
15 chisq = 0
16 for bar in range(nbars):
17 for bar1 in [bar-1,bar,bar+1]:
18 if bar1 < 0 or bar1 > nbars: continue
19 if X[bar][bar1][0]==0: continue
20 d = X[bar][bar1][0] - par[bar] - par[bar1+nbars]
21 if X[bar][bar1][1]>0: chisq += d**2/X[bar][bar1][1]**2
22 f.value = chisq
23 return
24
25class vetoTDCplaneCalibration(ROOT.FairTask):
26 "plane alignment"
27 def Init(self,options,monitor):
28 self.M = monitor
29 h = self.M.h
30 self.minChannels = 4
31 self.tag = ""
32 self.xCheck = False
33 if options.xCheck :
34 self.xCheck = True
35 self.tag = "X"
36
37 s = 1
38 # delta T between bar i of plane 0 and bar i-1,i,i+1 of plane 1
39 l = 0
40 self.nbars = self.M.systemAndBars[s]
41 for bar in range(self.nbars):
42 ut.bookHist(h,'exBar_0'+str(bar),'ex y;dy [cm]',50,-10.,10.)
43 ut.bookHist(h,'exBar_1'+str(bar),'ex y;dy [cm]',50,-10.,10.)
44 for side in ['L','R']:
45 for bar1 in [bar-1,bar,bar+1]:
46 if bar1 < 0 or bar1 > self.nbars: continue
47 key = self.M.sdict[s]+str(bar)+'_'+str(bar1)+side+self.tag
48 ut.bookHist(h,'dtBar_'+key,'dt '+key+";dt [timestamp]",200,-1.,1.)
49 with open('tdcVetoInternalCalibration', 'rb') as fh:
50 self.tdcVetoCalib = pickle.load(fh)
51 if self.xCheck:
52 with open('tdcVetoPlaneCalibration', 'rb') as fh:
53 self.tdcVetoPlaneCalib = pickle.load(fh)
54
55 ut.bookHist(h,detector+'trackSlopes','track slope; x/z [mrad]; y/z [mrad]',1000,-100,100,1000,-100,100)
56 ut.bookHist(h,detector+'trackSlopesXL','track slope; x/z [rad]; y/z [rad]',120,-1.1,1.1,120,-1.1,1.1)
57 ut.bookHist(h,detector+'trackPos','track pos; x [cm]; y [cm]',100,-90,10.,80,0.,80.)
58 ut.bookHist(h,detector+'trackPosBeam','beam track pos slopes<0.1rad; x [cm]; y [cm]',100,-90,10.,80,0.,80.)
59
60 def ExecuteEvent(self,event):
61 h = self.M.h
62 s = 1
63 vetoHits = {10:[],11:[]}
64 for aHit in event.Digi_MuFilterHits:
65 if not aHit.isValid(): continue
66 detID = aHit.GetDetectorID()//1000
67 if not detID<20: continue
68 vetoHits[detID].append(aHit)
69 if not(len(vetoHits[10])==1) and not(len(vetoHits[11])==1): return
70 for aTrack in event.Reco_MuonTracks:
71 if not aTrack.GetUniqueID()==1: continue
72 tdc = {10:{},11:{}}
73 S = aTrack.getFitStatus()
74 if S.isFitConverged(): continue
75 state = aTrack.getFittedState()
76 mom = state.getMom()
77 slopeX = mom.X()/mom.Z()
78 slopeY = mom.Y()/mom.Z()
79 pos = state.getPos()
80 rc = h[detector+'trackSlopes'].Fill(slopeX*1000,slopeY*1000)
81 rc = h[detector+'trackSlopesXL'].Fill(slopeX,slopeY)
82 rc = h[detector+'trackPos'].Fill(pos.X(),pos.Y())
83 if abs(slopeX)<0.1 and abs(slopeY)<0.1: rc = h[detector+'trackPosBeam'].Fill(pos.X(),pos.Y())
84
85 if abs(mom.x()/mom.z())>0.25: continue # 4cm distance, 250mrad = 1cm
86 if mom.y()/mom.z()>0.05: continue
87
88 for l in range(2):
89 zEx = self.M.zPos['MuFilter'][1*10+l]
90 lam = (zEx-pos.z())/mom.z()
91 yEx = pos.y()+lam*mom.y()
92 xEx = pos.x()+lam*mom.x() # needed for correction of signal propagation
93 for aHit in vetoHits[10+l]:
94 detID = aHit.GetDetectorID()
95 bar = (detID%1000)
96 self.M.MuFilter.GetPosition(detID,A,B)
97 D = (A[1]+B[1])/2. - yEx
98 rc = h['exBar_'+str(l)+str(bar)].Fill(D)
99 if abs(D)<5:
100 tdc[10+l][bar] = {'L':{},'R':{}}
101 for k in range(16):
102 qdc = aHit.GetSignal(k)
103 if qdc <0: continue
104 kx = k
105 side = 'L'
106 if not k < 8 :
107 kx = k - 8
108 side = 'R'
109 cor = 0
110 if kx in self.tdcVetoCalib[s*10+l][side][bar]:
111 cor = self.tdcVetoCalib[s*10+l][side][bar][kx][0]
112 elif kx>0: print('no correction:',s,l,side,bar,kx)
113 tdc[10+l][bar][side][kx] = aHit.GetTime(k) - cor
114 if self.xCheck:
115 tdc[10+l][bar][side][kx] -= self.tdcVetoPlaneCalib[s*10+l][side][bar]
116
117 # make plane alignment
118 l0 = 0
119 l1 = 1
120 for bar in tdc[10+l0]:
121 for side in tdc[10+l0][bar]:
122 tdc0 = 0
123 n=0
124 fastTDC0 = 999.
125 for k in tdc[10+l0][bar][side]:
126 n+=1
127 tdc0+=tdc[10+l0][bar][side][k]
128 if tdc[10+l0][bar][side][k] < fastTDC0 : fastTDC0 = tdc[10+l0][bar][side][k]
129
130 if n<self.minChannels: continue
131 tdc0 = tdc0/n
132 for bar1 in [bar-1,bar,bar+1]:
133 if not bar1 in tdc[10+l1]: continue
134 if not side in tdc[10+l1][bar1]: continue
135 tdc1 = 0
136 n=0
137 fastTDC1 = 999.
138 for k in tdc[10+l1][bar1][side]:
139 n+=1
140 tdc1+=tdc[10+l1][bar1][side][k]
141 if tdc[10+l1][bar1][side][k] < fastTDC1 : fastTDC1 = tdc[10+l1][bar1][side][k]
142 if n<self.minChannels: continue
143 tdc1 = tdc1/n
144 # dt = tdc1-tdc0
145 dt = fastTDC1 - fastTDC0
146 key = self.M.sdict[s]+str(bar)+'_'+str(bar1)+side+self.tag
147 rc = h['dtBar_'+key].Fill(dt)
148
149 def minimize(self):
150 h = self.M.h
151 s = 1
152 h['tdcCalibPlane'] = {10:{'L':{},'R':{}},11:{'L':{},'R':{}}}
153 for side in ['L','R']:
154 global X
155 X = h['matrix'][side]
156 global nbars
157 nbars = self.M.systemAndBars[s]
158 npar = nbars*2
159 ierflg = ctypes.c_int(0)
160 vstart = array('d',[0]*npar)
161 gMinuit = ROOT.TMinuit(npar)
162 gMinuit.SetFCN(FCN)
163 gMinuit.SetErrorDef(1.0)
164 gMinuit.SetMaxIterations(10000)
165 p = 0
166 err = 1E-3
167 for l in range(2):
168 for o in range(nbars):
169 name = "o"+str(10*l+o)
170 gMinuit.mnparm(p, name, vstart[p], err, 0.,0.,ierflg)
171 p+=1
172 gMinuit.FixParameter(4)
173 strat = array('d',[0])
174 gMinuit.mnexcm("SET STR",strat,1,ierflg) # 0 faster, 2 more reliable
175 gMinuit.mnexcm("SIMPLEX",vstart,npar,ierflg)
176 gMinuit.mnexcm("MIGRAD",vstart,npar,ierflg)
177 cor0 = ctypes.c_double(0)
178 ecor0 = ctypes.c_double(0)
179 cor1 = ctypes.c_double(0)
180 ecor1 = ctypes.c_double(0)
181
182 for bar in range(npar):
183 if bar<7: l=0
184 else: l=1
185 rc = gMinuit.GetParameter(bar,cor0,ecor0)
186 h['tdcCalibPlane'][10+l][side][bar-7*l] = cor0.value
187
188 for bar in range(nbars):
189 for bar1 in [bar-1,bar,bar+1]:
190 if bar1 < 0 or bar1 > nbars: continue
191 if X[bar][bar1][0]==0: continue
192 rc = gMinuit.GetParameter(bar,cor0,ecor0)
193 rc = gMinuit.GetParameter(bar1+nbars,cor1,ecor1)
194 d = X[bar][bar1][0] - (cor1.value - cor0.value)
195 print("relation between veto0 %i and veto1 %i, before correction %6.4F and after %6.4F"%(bar,bar1,X[bar][bar1][0],d))
196
197 with open('tdcVetoPlaneCalibration', 'wb') as fh:
198 pickle.dump(h['tdcCalibPlane'], fh)
199
200 def Finalize(self):
201 h = self.M.h
202 s = 1
203 h['matrix'+self.tag] = {}
204 ut.bookCanvas(h,'dummy','',900,600,1,1)
205 h['dummy'].cd()
206 for side in ['L','R']:
207 h['matrix'+self.tag][side] = {}
208 for bar in range(self.nbars):
209 h['matrix'+self.tag][side][bar] = {}
210 for bar1 in [bar-1,bar,bar+1]:
211 if bar1 < 0 or bar1 > self.nbars: continue
212 histo = h['dtBar_Veto'+str(bar)+'_'+str(bar1)+side+self.tag]
213 rc = histo.Fit('gaus','SQ')
214 h['matrix'+self.tag][side][bar][bar1] = [histo.GetMean(),histo.GetMeanError()]
215
216class vetoTDCchannelCalibration(ROOT.FairTask):
217 "internal alignment"
218 def Init(self,options,monitor):
219 self.M = monitor
220 self.options = options
221 self.xCheck = False
222 self.tag = ""
223 if options.xCheck :
224 self.xCheck = True
225 self.tag = "X"
226 h = self.M.h
227 s = 1
228 for l in range(self.M.systemAndPlanes[s]):
229 for bar in range(self.M.systemAndBars[s]):
230 for side in ['L','R']:
231 for k in range(8):
232 key = self.M.sdict[s]+str(s*10+l)+'_'+str(bar)+side+str(k)+self.tag
233 ut.bookHist(h,'dtChan_'+key,'dt '+key+";dt [timestamp]",200,-1.,1.)
234 if self.xCheck:
235 with open('tdcVetoInternalCalibration', 'rb') as fh:
236 self.tdcVetoCalib = pickle.load(fh)
237
238 def ExecuteEvent(self,event):
239 h = self.M.h
240 s = 1
241 vetoHits = {10:[],11:[]}
242 for aHit in event.Digi_MuFilterHits:
243 if not aHit.isValid(): continue
244 detID = aHit.GetDetectorID()//1000
245 if not detID<20: continue
246 vetoHits[detID].append(aHit)
247 if not(len(vetoHits[10])==1) and not(len(vetoHits[11])==1): return
248
249 for aTrack in event.Reco_MuonTracks:
250 if not aTrack.GetUniqueID()==1: continue
251 tdc = {10:{},11:{}}
252 S = aTrack.getFitStatus()
253 if S.isFitConverged(): continue
254 mom = aTrack.getFittedState().getMom()
255 pos = aTrack.getFittedState().getPos()
256
257 for l in range(2):
258 zEx = self.M.zPos['MuFilter'][1*10+l]
259 lam = (zEx-pos.z())/mom.z()
260 yEx = pos.y()+lam*mom.y()
261 xEx = pos.x()+lam*mom.x() # needed for correction of signal propagation
262 for aHit in vetoHits[10+l]:
263 detID = aHit.GetDetectorID()
264 self.M.MuFilter.GetPosition(detID,A,B)
265 D = (A[1]+B[1])/2. - yEx
266 if abs(D)<5:
267 bar = (detID%1000)
268 tdc[10+l][bar] = {'L':{},'R':{}}
269 for k in range(16):
270 qdc = aHit.GetSignal(k)
271 if qdc <0: continue
272 kx = k
273 side = 'L'
274 if not k < 8 :
275 kx = k - 8
276 side = 'R'
277 tdc[10+l][bar][side][kx] = aHit.GetTime(k)
278 if self.xCheck:
279 cor = 0
280 if kx in self.tdcVetoCalib[s*10+l][side][bar]:
281 cor = self.tdcVetoCalib[s*10+l][side][bar][kx][0]
282 tdc[10+l][bar][side][kx] -= cor
283 # make internal alignment
284 for l in range(2):
285 for bar in tdc[10+l]:
286 for side in tdc[10+l][bar]:
287 if not refChannel in tdc[10+l][bar][side]: continue
288 t0 = tdc[10+l][bar][side][refChannel]
289 for k in tdc[10+l][bar][side]:
290 dt = tdc[10+l][bar][side][k]-t0
291 key = self.M.sdict[s]+str(10+l)+'_'+str(bar)+side+str(k)+self.tag
292 rc = h['dtChan_'+key].Fill(dt)
293
294 def Finalize(self):
295 h = self.M.h
296 s = 1
297 h['tdcCalib'] = {10:{'L':{},'R':{}},11:{'L':{},'R':{}}}
298 ut.bookCanvas(h,'dummy','',900,600,1,1)
299 h['dummy'].cd()
300 for l in range(self.M.systemAndPlanes[s]):
301 for side in ['L','R']:
302 tname = 'v'+str(l)+side+self.tag
303 ut.bookCanvas(h,tname,tname,2048,2048,8,8)
304 for bar in range(self.M.systemAndBars[s]):
305 h['tdcCalib'][s*10+l][side][bar] = {}
306 for k in range(0,8):
307 h[tname].cd(bar*8+k+1)
308 key = self.M.sdict[s]+str(10+l)+'_'+str(bar)+side+str(k)+self.tag
309 dt = h['dtChan_'+key]
310 if not k == refChannel:
311 rc = dt.Fit('gaus','SQ')
312 result = rc.Get()
313 if result: h['tdcCalib'][s*10+l][side][bar][k]=[result.Parameter(1),result.Parameter(2)]
314 h['dtChan_'+key].Draw()
315
316 ut.bookHist(h,'TDCshiftsMean'+self.tag,'TDCshiftsMean '+self.tag,100,-0.2,0.2)
317 ut.bookHist(h,'TDCshiftsSigma'+self.tag,'TDCshiftsSigma '+self.tag,100,0.,0.25)
318 for l in h['tdcCalib']:
319 for side in h['tdcCalib'][l]:
320 for bar in h['tdcCalib'][l][side]:
321 for k in h['tdcCalib'][l][side][bar]:
322 if k==refChannel: continue
323 rc = h['TDCshiftsMean'+self.tag].Fill(h['tdcCalib'][l][side][bar][k][0])
324 rc = h['TDCshiftsSigma'+self.tag].Fill(h['tdcCalib'][l][side][bar][k][1])
325 ut.bookCanvas(h,'ChannelSummary'+self.tag,'Channel Summary',1200,600,2,1)
326 tc = h['ChannelSummary'+self.tag].cd(1)
327 h['TDCshiftsMean'+self.tag].Draw()
328 tc = h['ChannelSummary'+self.tag].cd(2)
329 h['TDCshiftsSigma'+self.tag].Draw()
330
331 if not self.xCheck:
332 with open('tdcVetoInternalCalibration', 'wb') as fh:
333 pickle.dump(h['tdcCalib'], fh)
334 ut.writeHists(h,'tdcCalib.root')
335 else:
336 ut.writeHists(h,'tdcCalibCor.root')
337
338class vetoTimeWalk(ROOT.FairTask):
339 "meausure time walk with scifi tracks"
340 def Init(self,options,monitor):
341 self.M = monitor
342 self.zPos = monitor.zPos
343 self.options = options
344 h = monitor.h
345 s = 1
346 for l in range(self.M.systemAndPlanes[s]):
347 for bar in range(self.M.systemAndBars[s]):
348 for side in ['L','R']:
349 for k in range(8):
350 key = self.M.sdict[s]+str(s*10+l)+'_'+str(bar)+side+str(k)
351 ut.bookHist(h,'tvsQDC_'+key,'t '+key+";QDC [a.u.];t [ns]",60,0.,60.,120,-7.,5.)
352 ut.bookHist(h,'trms', "rms of scifi times;t [ns]",100,0.,1.)
353 with open('ScifiTimeAlignment_v2', 'rb') as fh:
354 self.tdcScifiStationCalib = pickle.load(fh)
355 self.V = 15 * u.cm/u.ns
356 self.C = 299792458 * u.m/u.s
357 self.Vveto = 13.5 * u.cm/u.ns
358
359
360 def ExecuteEvent(self,event):
361 h = self.M.h
362 s = 1
363 vetoHits = {10:[],11:[]}
364 for aHit in event.Digi_MuFilterHits:
365 if not aHit.isValid(): continue
366 detID = aHit.GetDetectorID()//1000
367 if not detID<20: continue
368 vetoHits[detID].append(aHit)
369 if not(len(vetoHits[10])==1) and not(len(vetoHits[11])==1): return
370
371 DetID2Key={}
372 for nHit in range(event.Digi_ScifiHits.GetEntries()):
373 DetID2Key[event.Digi_ScifiHits[nHit].GetDetectorID()] = nHit
374
375 Z0 = self.zPos['Scifi'][10]
376 times = []
377 for aTrack in event.Reco_MuonTracks:
378 if not aTrack.GetUniqueID()==1: continue
379 tdc = {10:{},11:{}}
380 S = aTrack.getFitStatus()
381 if not S.isFitConverged(): continue
382 mom = aTrack.getFittedState().getMom()
383 pos = aTrack.getFittedState().getPos()
384 slopeX = mom.X()/mom.Z()
385 slopeY = mom.Y()/mom.Z()
386# get time of track by averaging all times of the clusters correcting for track length
387 for nM in range(aTrack.getNumPointsWithMeasurement()):
388 state = aTrack.getFittedState(nM)
389 Meas = aTrack.getPointWithMeasurement(nM)
390 W = Meas.getRawMeasurement()
391 clkey = W.getHitId()
392 aCl = event.Cluster_Scifi[clkey]
393 aHit = event.Digi_ScifiHits[DetID2Key[aCl.GetFirst()]]
394 s = aCl.GetFirst()//1000000
395 aCl.GetPosition(A,B)
396 mat = (aCl.GetFirst()//10000)%10
397 if aHit.isVertical():
398 proj = 'V'
399 L = B[1]-state.getPos()[1]
400 else:
401 proj = 'H'
402 L = A[0]-state.getPos()[0]
403 time = aCl.GetTime() # Get time in ns, use fastest TDC of cluster
404 time-= self.tdcScifiStationCalib[s][1][proj][mat] # correct as function of station / projection / mat
405 time-= self.tdcScifiStationCalib[s][0] # internal station calibration
406 time-= abs(L)/self.V # signal along fibre
407#
408 dZ = (A[2]+B[2])/2. - Z0
409 dL = dZ * ROOT.TMath.Sqrt( slopeX**2+slopeY**2+1 )
410 if slopeY>0.1: dL = -dL # cosmics from the back
411 time-= dL/self.C # track length with respect to sation0
412#
413 times.append(time)
414
415 sTime = statistics.mean(times)
416 rms = statistics.stdev(times)
417 rc = h['trms'].Fill(rms)
418 s = 1
419 for l in range(2):
420 zEx = self.M.zPos['MuFilter'][1*10+l]
421 lam = (zEx-pos.z())/mom.z()
422 yEx = pos.y()+lam*mom.y()
423 xEx = pos.x()+lam*mom.x() # needed for correction of signal propagation
424 for aHit in vetoHits[10+l]:
425 detID = aHit.GetDetectorID()
426 self.M.MuFilter.GetPosition(detID,A,B)
427 D = (A[1]+B[1])/2. - yEx
428 if abs(D)<5:
429 bar = (detID%1000)
430 tdc[10+l][bar] = {'L':{},'R':{}}
431 for k in range(16):
432 qdc = aHit.GetSignal(k)
433 if qdc <0: continue
434 kx = k
435 side = 'L'
436 L = A[0]-xEx
437 if not k < 8 :
438 kx = k - 8
439 side = 'R'
440 L = B[0]-xEx
441 T = aHit.GetTime(k) * self.M.TDC2ns
442 T-= abs(L)/self.Vveto # signal along bar
443
444 dZ = (A[2]+B[2])/2. - Z0
445 dL = dZ * ROOT.TMath.Sqrt( slopeX**2+slopeY**2+1 )
446 if slopeY>0.1: dL = -dL # cosmics from the back
447 T-= dL/self.C # track length with respect to sation0
448 key = self.M.sdict[s]+str(s*10+l)+'_'+str(bar)+side+str(kx)
449 # print(key,T,sTime)
450 h['tvsQDC_'+key].Fill(qdc,T-sTime)
451
452 def Plot(self):
453 h = self.M.h
454 M=self.M
455 s = 1
456 for l in range(M.systemAndPlanes[s]):
457 for side in ['L','R']:
458 ut.bookCanvas(h,'plane'+str(l)+side,'',2400,1800,8,7)
459 for kx in range(8):
460 for bar in range(M.systemAndBars[s]):
461 tc = h['plane'+str(l)+side].cd(kx+bar*8+1)
462 key = M.sdict[s]+str(s*10+l)+'_'+str(bar)+side+str(kx)
463 h['tvsQDC_'+key].Draw('colz')
464
465 def Finalize(self):
466 h = self.M.h
467 s = 1
468 ut.writeHists(h,'timeWalk_'+self.M.sdict[s]+'.root')
469
void GetPosition(Int_t id, TVector3 &vLeft, TVector3 &vRight)
Definition MuFilter.cxx:639
FCN(npar, gin, f, par, iflag)