SND@LHC Software
Loading...
Searching...
No Matches
convertRawData_muTestbeam.py
Go to the documentation of this file.
1#!/usr/bin/env python
2import ROOT,os,sys
3import global_variables
4import shipRoot_conf
5import rootUtils as ut
6h={}
7
8# raw data from Ettore: https://cernbox.cern.ch/index.php/s/Ten7ilKuD3qdnM2
10
11chi2Max = 2000.
12saturationLimit = 0.95
13
14mufi_hitThreshold = 2
15
16from argparse import ArgumentParser
17parser = ArgumentParser()
18parser.add_argument("-r", "--runNumber", dest="runNumber", help="run number", type=int,required=True)
19parser.add_argument("-P", "--partition", dest="partition", help="partition of data", type=int,required=False,default=-1)
20parser.add_argument("-p", "--path", dest="path", help="path to raw data", default='/mnt/hgfs/VMgate/')
21parser.add_argument("-n", "--nEvents", dest="nEvents", help="number of events to process", type=int,default=-1)
22parser.add_argument("-t", "--nStart", dest="nStart", help="first event to process", type=int,default=-1)
23parser.add_argument("-d", "--Debug", dest="debug", help="debug", default=False)
24parser.add_argument("-s",dest="stop", help="do not start running", default=False)
25parser.add_argument("-zM",dest="minMuHits", help="noise suppresion min MuFi hits", default=-1, type=int)
26parser.add_argument("-zS",dest="minScifiHits", help="noise suppresion min ScifFi hits", default=-1, type=int)
27parser.add_argument("-b", "--heartBeat", dest="heartBeat", help="heart beat", type=int,default=10000)
28
29withGeoFile = False
30
31options = parser.parse_args()
32runNr = str(options.runNumber).zfill(6)
33path = options.path+'run_'+ runNr+'/'
34part = ""
35if options.partition > 0: part = str(options.partition).zfill(4)
36inFile = 'data_'+part+'.root'
37outFile = "sndsw_raw_"+runNr+'-'+part+'.root'
38
39local = False
40if path.find('eos')<0 or os.path.isdir(path):
41 local = True
42 fqdc_cal = open(path+'/qdc_cal.csv')
43 Lqdc = fqdc_cal.readlines()
44 ftdc_cal = open(path+'/tdc_cal.csv')
45 Ltdc = ftdc_cal.readlines()
46else:
47 from XRootD import client
48 # https://xrootd.slac.stanford.edu/doc/python/xrootd-python-0.1.0/examples.html
49 server = os.environ['EOSSHIP']
50 with client.File() as f:
51 # "/eos/experiment/sndlhc/testbeam/MuFilter/run_000032/qdc_cal.csv"
52 f.open(server+path+"/qdc_cal.csv")
53 status, L = f.read()
54 Lqdc = L.decode().split('\n')
55 f.close()
56 f.open(server+path+"/tdc_cal.csv")
57 status, L = f.read()
58 Ltdc = L.decode().split('\n')
59 f.close()
60
61# read MuFilter mappings of SiPM channel to tofpet_id and tofpet_channel
62import csv
63SiPMmap={}
64TofpetMap = {}
65for system in ['DS','US','Veto']:
66 infile = "/eos/experiment/sndlhc/testbeam/MuFilter/SiPM_mappings/"+system+"_SiPM_mapping.csv"
67 SiPMmap[system] = {}
68 if os.path.isdir("/eos/experiment/sndlhc/testbeam/MuFilter/SiPM_mappings"):
69 with open(infile, "r") as f:
70 reader = csv.DictReader(f, delimiter=',')
71 for i, row in enumerate(reader):
72 SiPMmap[system][int(row['SiPM'])] = [int(row['CN']), int(row['pin']), int(row['TOFPET']), int(row['CHANNEL'])]
73 else:
74 from XRootD import client
75 server = os.environ['EOSSHIP']
76 with client.File() as f:
77 f.open(server+infile)
78 status, tmp = f.read()
79 for x in tmp.decode().split('\r\n'):
80 if x.find('TOF')>0: continue
81 row = x.split(',')
82 SiPMmap[system][int(row[0])] = [int(row[1]), int(row[2]), int(row[3]), int(row[4])]
83 TofpetMap[system] = {}
84 for channel in SiPMmap[system]:
85 row = SiPMmap[system][channel]
86 TofpetMap[system][row[2]*1000+row[3]] = channel
87# calibration data
88qdc_cal = {}
89
90L = Lqdc
91for l in range(1,len(L)):
92 tmp = L[l].replace('\n','').split(',')
93 if len(tmp)<10:continue
94 board_id = int(tmp[0])
95 if not board_id in qdc_cal: qdc_cal[board_id]={}
96 fe_id = int(tmp[1])
97 if not fe_id in qdc_cal[board_id]: qdc_cal[board_id][fe_id]={}
98 channel = int(tmp[2])
99 if not channel in qdc_cal[board_id][fe_id]: qdc_cal[board_id][fe_id][channel]={}
100 tac = int(tmp[3])
101 if not tac in qdc_cal[board_id][fe_id][channel]: qdc_cal[board_id][fe_id][channel][tac]={}
102 X = qdc_cal[board_id][fe_id][channel][tac]
103 X['a']=float(tmp[4])
104 X['b']=float(tmp[5])
105 X['c']=float(tmp[6])
106 X['d']=float(tmp[8])
107 X['e']=float(tmp[10])
108 if float(tmp[9]) < 2: X['chi2Ndof'] = 999999.
109 else: X['chi2Ndof']=float(tmp[7])/float(tmp[9])
110
111L=Ltdc
112for l in range(1,len(L)):
113 tmp = L[l].replace('\n','').split(',')
114 if len(tmp)<9:continue
115 board_id = int(tmp[0])
116 if not board_id in qdc_cal: qdc_cal[board_id]={}
117 fe_id = int(tmp[1])
118 if not fe_id in qdc_cal[board_id]: qdc_cal[board_id][fe_id]={}
119 channel = int(tmp[2])
120 if not channel in qdc_cal[board_id][fe_id]: qdc_cal[board_id][fe_id][channel]={}
121 tac = int(tmp[3])
122 if not tac in qdc_cal[board_id][fe_id][channel]: qdc_cal[board_id][fe_id][channel][tac]={}
123 tdc = int(tmp[4])
124 if not tdc in qdc_cal[board_id][fe_id][channel][tac]: qdc_cal[board_id][fe_id][channel][tac][tdc]={}
125 X = qdc_cal[board_id][fe_id][channel][tac][tdc]
126 X['a']=float(tmp[5])
127 X['b']=float(tmp[6])
128 X['c']=float(tmp[7])
129 X['d']=float(tmp[9])
130 if float(tmp[10]) < 2: X['chi2Ndof'] = 999999.
131 else: X['chi2Ndof']=float(tmp[8])/float(tmp[10])
132
133# following procedure in https://gitlab.cern.ch/scifi-telescope/scifi-rec/-/blob/ettore-tofpet/lib/processors/applycalibration.cpp
134def qdc_calibration(board_id,tofpet_id,channel,tac,v_coarse,v_fine,tf):
135 GQDC = 1.0 # or 3.6
136 par = qdc_cal[board_id][tofpet_id][channel][tac]
137 x = v_coarse - tf
138 fqdc = -par['c']*ROOT.TMath.Log(1+ROOT.TMath.Exp( par['a']*(x-par['e'])**2-par['b']*(x-par['e']) )) + par['d']
139 value = (v_fine-fqdc)/GQDC
140 return value
141
142def qdc_chi2(board_id,tofpet_id,channel,tac,TDC=0):
143 par = qdc_cal[board_id][tofpet_id][channel][tac]
144 parT = qdc_cal[board_id][tofpet_id][channel][tac][TDC]
145 return max(par['chi2Ndof'],parT['chi2Ndof'])
146
147def qdc_sat(board_id,tofpet_id,channel,tac,v_fine):
148 par = qdc_cal[board_id][tofpet_id][channel][tac]
149 return v_fine/par['d']
150
151def time_calibration(board_id,tofpet_id,channel,tac,t_coarse,t_fine,TDC=0): #??
152 par = qdc_cal[board_id][tofpet_id][channel][tac][TDC]
153 x = t_fine
154 ftdc = (-par['b']-ROOT.TMath.Sqrt(par['b']**2-4*par['a']*(par['c']-x)))/(2*par['a']) # Ettore 28/01/2022 +par['d']
155 timestamp = t_coarse+ftdc
156 return timestamp
157
158def comb_calibration(board_id,tofpet_id,channel,tac,v_coarse,v_fine,t_coarse,t_fine,GQDC = 1.0, TDC=0): # max gain QDC = 3.6
159 par = qdc_cal[board_id][tofpet_id][channel][tac]
160 parT = par[TDC]
161 x = t_fine
162 ftdc = (-parT['b']-ROOT.TMath.Sqrt(parT['b']**2-4*parT['a']*(parT['c']-x)))/(2*parT['a']) # Ettore 28/01/2022 +parT['d']
163 timestamp = t_coarse + ftdc
164 tf = timestamp - t_coarse
165 x = v_coarse - tf
166 fqdc = -par['c']*ROOT.TMath.Log(1+ROOT.TMath.Exp( par['a']*(x-par['e'])**2-par['b']*(x-par['e']) )) + par['d']
167 value = (v_fine-fqdc)/GQDC
168 return timestamp,value,max(par['chi2Ndof'],parT['chi2Ndof']),v_fine/par['d']
169
170def comb_calibration(board_id,tofpet_id,channel,tac,v_coarse,v_fine,t_coarse,t_fine,GQDC = 1.0, TDC=0): # max gain QDC = 3.6
171 par = qdc_cal[board_id][tofpet_id][channel][tac]
172 parT = par[TDC]
173 x = t_fine
174 ftdc = (-parT['b']-ROOT.TMath.Sqrt(parT['b']**2-4*parT['a']*(parT['c']-x)))/(2*parT['a'])+parT['d']
175 timestamp = t_coarse + ftdc
176 tf = timestamp - t_coarse
177 x = v_coarse - tf
178 fqdc = -par['c']*ROOT.TMath.Log(1+ROOT.TMath.Exp( par['a']*(x-par['e'])**2-par['b']*(x-par['e']) )) + par['d']
179 value = (v_fine-fqdc)/GQDC
180 return timestamp,value,max(par['chi2Ndof'],parT['chi2Ndof']),v_fine/par['d']
181
183 ut.bookHist(h,'chi2','chi2',1000,0.,10000)
184 report = {}
185 TDC = 0
186 for b in qdc_cal:
187 for t in qdc_cal[b]:
188 for c in qdc_cal[b][t]:
189 for tac in qdc_cal[b][t][c]:
190 par = qdc_cal[b][t][c][tac]
191 if 'chi2Ndof' in par: chi2 = par['chi2Ndof']
192 else: chi2=-1
193 parT = qdc_cal[b][t][c][tac][TDC]
194 if 'chi2Ndof' in parT: chi2T = parT['chi2Ndof']
195 else: chi2T=-1
196 key = tac +10*c + t*10*100 + b*10*100*100
197 if not key in report: report[key]=[chi2,chi2T]
198 for key in report:
199 rc=h['chi2'].Fill(report[key][0])
200 rc=h['chi2'].Fill(report[key][1])
201 h['chi2'].Draw()
202 return report
203
204# station mapping for SciFi
205stations = {}
206stations['M1Y'] = {0:29, 1:3, 2:30} # three fibre mats per plane
207stations['M1X'] = {0:11, 1:17, 2:28}
208stations['M2Y'] = {0:16, 1:14, 2:18}
209stations['M2X'] = {0:1, 1:2, 2:25}
210stations['M3Y'] = {0:15, 1:9, 2:5}
211stations['M3X'] = {0:22, 1:27, 2:4}
212if path.find("commissioning-h6")>0: stations['M4Y'] = {0:46, 1:40, 2:20} # board 40 replaces 23
213else: stations['M4Y'] = {0:46, 1:23, 2:20}
214stations['M4X'] = {0:8, 1:50, 2:49}
215stations['M5Y'] = {0:19, 1:13, 2:36}
216stations['M5X'] = {0:21, 1:10, 2:6}
217
218# board mapping for Scifi
219boardMaps = {}
220boardMaps['Scifi'] = {}
221for station in stations:
222 for mat in stations[station]:
223 board = 'board_'+str(stations[station][mat])
224 boardMaps['Scifi'][board]=[station,mat]
225
226boardMaps['MuFilter'] = {}
227# H6
228boardMaps['MuFilter']['board_43'] = {'A':'US_1Left','B':'US_2Left','C':'US_2Right','D':'US_1Right'}
229boardMaps['MuFilter']['board_60'] = {'A':'US_3Left','B':'US_4Left','C':'US_4Right','D':'US_3Right'}
230boardMaps['MuFilter']['board_41'] = {'A':'US_5Left','B':'DS_1Left','C':'DS_1Right','D':'US_5Right'}
231boardMaps['MuFilter']['board_59'] = {'A':'DS_2Left','B':'DS_1Vert','C':'DS_2Vert','D':'DS_2Right'}
232slots = {0:'A',1:'A',2:'B',3:'B',4:'C',5:'C',6:'D',7:'D'}
233
234MufiSystem = {}
235for b in boardMaps['MuFilter']:
236 board_id = int(b.split('_')[1])
237 MufiSystem[board_id]={}
238 for x in boardMaps['MuFilter'][b]:
239 for slot in slots:
240 s = 0
241 tmp = boardMaps['MuFilter'][b][x].split('_')[0]
242 if tmp=='US': s = 1
243 elif tmp=='DS': s = 2
244 if slots[slot]==x: MufiSystem[board_id][slot]=s
245
246offMap={}
247 # first bar, number of sipm channels / bar and direction
248for s in range(1,3):
249 for o in ['Left','Right']:
250 offMap['VETO_'+str(s)+o] =[10000 + (s-1)*1000+ 9,-8,2]
251for s in range(1,6):
252 for o in ['Left','Right']:
253 offMap['US_'+str(s)+o] =[20000 + (s-1)*1000+ 9,-8,2]
254for s in range(1,5):
255 for o in ['Vert']:
256 offMap['DS_'+str(s)+o] =[30000 + (s-1)*1000+ 119, -1,1] # direction not known
257 if s>3: continue
258 for o in ['Left','Right']:
259 offMap['DS_'+str(s)+o] =[30000 + (s-1)*1000+ 59,-1,2] # direction not known
260
261def channel(tofpet_id,tofpet_channel,position):
262 return (64 * tofpet_id + 63 - tofpet_channel + 512*position) # 512 channels per mat, 1536 channels per plane
263 # one channel covers all 6 layers of fibres
264
265# reading hits and converting to event information
266X=''
267if not local: X = server
268part = ""
269if not (options.partition < 0): part = '_'+str(options.partition).zfill(4)
270dataName = 'data'+part+'.root'
271f0=ROOT.TFile.Open(X+path+dataName)
272if options.nEvents<0: nEvent = f0.event.GetEntries()
273else: nEvent = min(options.nEvents,f0.event.GetEntries())
274print('converting ',nEvent,' events ',' of run',options.runNumber)
275
276boards = {}
277for b in f0.GetListOfKeys():
278 name = b.GetName()
279 if name.find('board')!=0: continue
280 boards[name]=f0.Get(name)
281
282fSink = ROOT.FairRootFileSink(outFile)
283sTree = ROOT.TTree('rawConv','raw data converted')
284ROOT.gDirectory.pwd()
285header = ROOT.FairEventHeader()
286eventSND = sTree.Branch("EventHeader",header,32000,-1)
287
288digiSciFi = ROOT.TClonesArray("sndScifiHit")
289digiSciFiBranch = sTree.Branch("Digi_ScifiHits",digiSciFi,32000,1)
290digiMuFilter = ROOT.TClonesArray("MuFilterHit")
291digiMuFilterHitBranch = sTree.Branch("Digi_MuFilterHits",digiMuFilter,32000,1)
292#scifi clusters
293if withGeoFile:
294 clusScifi = ROOT.TClonesArray("sndCluster")
295 clusScifiBranch = sTree.Branch("Cluster_Scifi",clusScifi,32000,1)
296
297B = ROOT.TList()
298B.SetName('BranchList')
299B.Add(ROOT.TObjString('sndScifiHit'))
300B.Add(ROOT.TObjString('MuFilterHit'))
301B.Add(ROOT.TObjString('FairEventHeader'))
302fSink.WriteObject(B,"BranchList", ROOT.TObject.kSingleKey)
303
304import time
305def run(nEvent):
306 event = f0.event
307 for eventNumber in range(options.nStart,nEvent):
308 ncreated = 0
309 rc = event.GetEvent(eventNumber)
310 T = event.timestamp
311 if eventNumber%options.heartBeat==0:
312 tt = time.ctime()
313 print('run ',options.runNumber, ' event',eventNumber," ",tt)
314 # find entry numbers for all boards
315 otherEvents={}
316 maxHits = 0
317 found = False
318 for board in boards:
319 board_id = int(board.split('_')[1])
320 bt = boards[board]
321 rc = bt.GetEvent(eventNumber)
322 if bt.n_hits < 1: continue
323 if bt.n_hits > maxHits:
324 maxHits = bt.n_hits
325 maxBoard = board_id
326 t1 = asyn[board_id]
327 for boardx in boards:
328 boardx_id = int(boardx.split('_')[1])
329 t2 = asyn[boardx_id]
330 dt = t2 - t1
331 newT = T + dt
332 if newT<0 or dt==0: continue
333 if newT in theMap:
334 if options.debug: print("found",eventNumber)
335 key = theMap[newT]
336 if key < 0 : continue # event time had already been used
337 found = True
338 if not board_id in otherEvents:
339 otherEvents[board_id]={}
340 otherEvents[board_id][boardx_id]=[newT,theMap[newT]]
341# problem if more than one board has links to another event.
342 if found and options.debug: print("+++",otherEvents)
343
344 if len(otherEvents)>1:
345 print("Houston we have a problem, more than one board match with other events",eventNumber,otherEvents)
346 for b in otherEvents:
347 rc = boards["board_"+str(b)].GetEvent(eventNumber)
348 txt = "mult "+str( boards["board_"+str(b)].n_hits )
349 for bx in otherEvents[b]:
350 rc = boards["board_"+str(bx)].GetEvent(otherEvents[b][bx][1])
351 txt+= " " +str( boards["board_"+str(bx)].n_hits )
352 print(txt)
353 continue
354
355 if len(otherEvents)==0:
356 if maxHits>mufi_hitThreshold:
357 otherEvents[maxBoard]={}
358 otherEvents[maxBoard][maxBoard] = [T,eventNumber]
359 else: continue
360 else:
361 thisBoard = list(otherEvents.keys())[0]
362 otherEvents[thisBoard][thisBoard] = [T,eventNumber]
363 listOfBoards = {}
364 for x in otherEvents:
365 for b in otherEvents[x]:
366 tmp = otherEvents[x][b]
367 listOfBoards[b]=tmp[1]
368 theMap[tmp[0]] = -1 # use event only once
369
370 if options.debug: print("---",listOfBoards)
371
372 header.SetEventTime(event.timestamp)
373 header.SetRunId(options.runNumber)
374 if options.debug: print('event:',eventNumber,event.timestamp)
375 indexSciFi=0
376 digiSciFi.Delete()
377 digiSciFiStore = {}
378 indexMuFilter=0
379 digiMuFilter.Delete()
380 digiMuFilterStore = {}
381# special part for synchronizing the MuFilter testbeam data
382 for board_id in listOfBoards:
383 board = "board_"+str(board_id)
384 scifi = True
385 if board in boardMaps['Scifi']:
386 station,mat = boardMaps['Scifi'][board]
387 elif board in boardMaps['MuFilter']:
388 scifi = False
389 else:
390 print(board+' not known. Serious error, stop')
391 1/0
392 bt = boards[board]
393 rc = bt.GetEvent(listOfBoards[board_id])
394 for n in range(bt.n_hits):
395 mask = False
396 if options.debug:
397 print(scifi,board_id,bt.tofpet_id[n],bt.tofpet_channel[n],bt.tac[n],bt.t_coarse[n],bt.t_fine[n],bt.v_coarse[n],bt.v_fine[n])
398 tofpet_id = bt.tofpet_id[n]
399 tofpet_channel = bt.tofpet_channel[n]
400 tac = bt.tac[n]
401 TDC,QDC,Chi2ndof,satur = comb_calibration(board_id,tofpet_id,tofpet_channel,tac,bt.v_coarse[n],bt.v_fine[n],bt.t_coarse[n],bt.t_fine[n])
402 if Chi2ndof > chi2Max:
403 if QDC>1E20: QDC = 997. # checking for inf
404 if QDC != QDC: QDC = 998. # checking for nan
405 if QDC>0: QDC = -QDC
406 mask = True
407 elif satur > saturationLimit or QDC>1E20 or QDC != QDC:
408 if QDC>1E20: QDC = 987. # checking for inf
409 if options.debug:
410 print('inf',board_id,bt.tofpet_id[n],bt.tofpet_channel[n],bt.tac[n],bt.v_coarse[n],bt.v_fine[n],TDC-bt.t_coarse[n],eventNumber,Chi2ndof)
411 if QDC != QDC: QDC = 988. # checking for nan
412 if options.debug:
413 print('nan',board_id,bt.tofpet_id[n],bt.tofpet_channel[n],bt.tac[n],bt.v_coarse[n],bt.v_fine[n],\
414 TDC-bt.t_coarse[n],TDC,bt.t_coarse[n],eventNumber,Chi2ndof)
415 A = int(min( QDC,1000))
416 B = min(satur,999)/1000.
417 QDC = A+B
418 mask = True
419 elif Chi2ndof > chi2Max:
420 if QDC>0: QDC = -QDC
421 mask = True
422 if options.debug:
423 print('calibrated: tdc = ',TDC,' qdc = ',QDC) # TDC clock cycle = 160 MHz or 6.25ns
424
425 if not scifi:
426# mufi encoding
427 slot = bt.tofpet_id[n]
428 tmp = boardMaps['MuFilter'][board][slots[slot]]
429 system = tmp.split('_')[0]
430 key = (slot%2)*1000 + bt.tofpet_channel[n]
431 if options.debug: print(system,key,board,bt.tofpet_id[n],bt.tofpet_id[n]%2,bt.tofpet_channel[n])
432 sipmChannel = 99
433 if not key in TofpetMap[system]:
434 print('key does not exist',key)
435 print(system, key, TofpetMap[system])
436 else:
437 sipmChannel = TofpetMap[system][key]-1
438 nSiPMs = abs(offMap[tmp][1])
439 nSides = abs(offMap[tmp][2])
440 direction = int(offMap[tmp][1]/nSiPMs)
441 detID = offMap[tmp][0] + direction*(sipmChannel//(nSiPMs))
442 sipm_number = sipmChannel%(nSiPMs)
443 if tmp.find('Right')>0:
444 sipm_number += nSiPMs
445 if not detID in digiMuFilterStore:
446 digiMuFilterStore[detID] = ROOT.MuFilterHit(detID,nSiPMs,nSides)
447 test = digiMuFilterStore[detID].GetSignal(sipm_number)
448 digiMuFilterStore[detID].SetDigi(QDC,TDC,sipm_number)
449 if mask: digiMuFilterStore[detID].SetMasked(sipm_number)
450
451 if options.debug:
452 ncreated +=1
453 print('create mu hit: ',detID,tmp,system,slot,offMap[tmp],sipmChannel,nSiPMs,nSides,test,slot)
454 print(' ',detID,sipm_number,QDC,TDC)
455 if test>0 or detID%1000>200 or sipm_number>15:
456 print('what goes wrong?',detID,sipm_number,system,key,board,bt.tofpet_id[n],bt.tofpet_channel[n],test)
457 else:
458# scifi encoding
459 chan = channel(bt.tofpet_id[n],bt.tofpet_channel[n],mat)
460 orientation = 1
461 if station[2]=="Y": orientation = 0
462 sipmLocal = (chan - mat*512)
463 sipmID = 1000000*int(station[1]) + 100000*orientation + 10000*mat + 1000*(sipmLocal//128) + chan%128
464 if not sipmID in digiSciFiStore: digiSciFiStore[sipmID] = ROOT.sndScifiHit(sipmID)
465 digiSciFiStore[sipmID].SetDigi(QDC,TDC)
466 if mask: digiSciFiStore[sipmID].setInvalid()
467 if options.debug:
468 print('create scifi hit: tdc = ',board,sipmID,QDC,TDC)
469 print('tofpet:', bt.tofpet_id[n],bt.tofpet_channel[n],mat,chan)
470 print(station[1],station[2],mat,chan,int(chan/128)%4,chan%128)
471
472 for sipmID in digiSciFiStore:
473 if digiSciFi.GetSize() == indexSciFi: digiSciFi.Expand(indexSciFi+100)
474 digiSciFi[indexSciFi]=digiSciFiStore[sipmID]
475 indexSciFi+=1
476 for detID in digiMuFilterStore:
477 if digiMuFilter.GetSize() == indexMuFilter: digiMuFilter.Expand(indexMuFilter+100)
478 digiMuFilter[indexMuFilter]=digiMuFilterStore[detID]
479 indexMuFilter+=1
480# make simple clustering for scifi, only works with geometry file. Don't think it is a good idea at the moment
481 if withGeoFile:
482 index = 0
483 hitDict = {}
484 for k in range(digiSciFi.GetEntries()):
485 d = digiSciFi[k]
486 if not d.isValid(): continue
487 hitDict[d.GetDetectorID()] = k
488 hitList = list(hitDict.keys())
489 if len(hitList)>0:
490 hitList.sort()
491 tmp = [ hitList[0] ]
492 cprev = hitList[0]
493 ncl = 0
494 last = len(hitList)-1
495 hitlist = ROOT.std.vector("sndScifiHit*")()
496 for i in range(len(hitList)):
497 if i==0 and len(hitList)>1: continue
498 c=hitList[i]
499 if (c-cprev)==1:
500 tmp.append(c)
501 if (c-cprev)!=1 or c==hitList[last]:
502 first = tmp[0]
503 N = len(tmp)
504 hitlist.clear()
505 for aHit in tmp:
506 hitlist.push_back( digiSciFi[hitDict[aHit]])
507 print(aHit,hitDict[aHit],digiSciFi[hitDict[aHit]].GetDetectorID())
508 print(hitlist.size())
509 aCluster = ROOT.sndCluster(first,N,hitlist,scifiDet)
510 print("cluster created")
511 if clusScifi.GetSize() == index: clusScifi.Expand(index+10)
512 clusScifi[index]=aCluster
513 index+=1
514 if c!=hitList[last]:
515 ncl+=1
516 tmp = [c]
517 cprev = c
518# fill TTree
519 sTree.Fill()
520 if options.debug:
521 print('====> number of created hits',ncreated)
522 if options.debug:
523 print('number of events processed',sTree.GetEntries(),f0.event.GetEntries())
524 sTree.Write()
525
526# https://gitlab.cern.ch/snd-scifi/software/-/wikis/Raw-data-format
527# tac: 0-3, identifies the Time-To-Analogue converter used for this hit (each channel has four of them and they require separate calibration).
528# t_coarse: Coarse timestamp of the hit, running on a 4 times the LHC clock
529# t_fine: 0-1023, fine timestamp of the hit. It contains the raw value of the charge digitized by the TDC and requires calibration.
530# v_coarse: 0-1023, QDC mode: it represents the number of clock cycles the charge integration lasted.
531# v_fine = 0-1023, QDC mode: represents the charge measured. Requires calibration.
532
533theMap = {}
535 k = 0
536 for event in f0.event:
537 theMap[event.timestamp]=k
538 k+=1
539 if k%10000000==0: print('key time map: now at ',k)
540
541def asynInfo(run):
542 server = os.environ['EOSSHIP']
543 with client.File() as f:
544 location = "/eos/experiment/sndlhc/raw_data/commissioning/TB_H8_october/run_logs/log_"+str(run)+".txt"
545 f.open(server+location)
546 status, L = f.read()
547 A = L.decode().split('\n')
548 f.close()
549 info = {}
550 for x in A:
551 X = x.replace('\n','')
552 if X=='':continue
553 if X.find('2021')==0:
554 tag = X
555 info[tag]={}
556 else:
557 if X.find('disc')>0: info[tag]['summary'] = eval(X)
558 else: info[tag]['detail'] = eval(X)
559# correction procedure
560 A = {41:{},43:{},59:{},60:{}}
561 C = {}
562 prev = {41:None,43:None,59:None,60:None}
563 errorCounter = 0
564 T = list(info.keys())
565 T.sort()
566 for tag in T:
567 test = info[tag]['summary']
568 lastT = test['last_timestamp']
569 if not 'desync_info' in test: continue
570 C[tag] = {41:{},43:{},59:{},60:{}}
571 for L in test['desync_info']:
572 board = L[0]
573 t = L[1][0]
574 c = L[1][1]
575 C[tag][board][c]=t
576 # check that desync is constant over the complete run
577 for c in C[tag][41]:
578 tref = C[tag][41][c]
579 break
580 for board in C[tag]:
581 if not c in C[tag][board]:
582 #print('different trigger counts, problematic',tag,C[tag])
583 errorCounter+=1
584 else:
585 if not prev[board] == None:
586 if not C[tag][board][c]-tref == prev[board]:
587 print('desync changed, problematic',tag,prev,C[tag])
588 prev[board] = C[tag][board][c]-tref
589
590 T = list(C.keys())
591 for b in C[T[0]]:
592 for c in C[T[0]][b]:
593 A[b]= C[T[0]][b][c]
594 return A
595
596import pickle
598 fout = open('map'+str(options.runNumber)+'.pkl','wb')
599 pickle.dump(theMap,fout)
600
601if not options.stop:
602# special for the MuFilter testbeam, need to synchronize the boards
603
604# map time stamp to event number
605 test = 'map'+str(options.runNumber)+'.pkl'
606 if os.path.exists(test):
607 print('map exists')
608 fin = open('map'+str(options.runNumber)+'.pkl','rb')
609 theMap = pickle.load(fin)
610 fin.close()
611 else:
613 dumpMap()
614 asyn = asynInfo(options.runNumber)
615 run(nEvent)
616 f0.Close()
617 fSink.Close()
618 print("File closed")
619
620
qdc_calibration(board_id, tofpet_id, channel, tac, v_coarse, v_fine, tf)
comb_calibration(board_id, tofpet_id, channel, tac, v_coarse, v_fine, t_coarse, t_fine, GQDC=1.0, TDC=0)
qdc_sat(board_id, tofpet_id, channel, tac, v_fine)
qdc_chi2(board_id, tofpet_id, channel, tac, TDC=0)
time_calibration(board_id, tofpet_id, channel, tac, t_coarse, t_fine, TDC=0)
configure(darkphoton=None)