SND@LHC Software
Loading...
Searching...
No Matches
2dEventDisplay.py
Go to the documentation of this file.
1import ROOT
2import os,sys,subprocess,atexit
3from array import array
4import shipunit as u
5import SndlhcMuonReco
6import rootUtils as ut
7from decorators import *
8from rootpyPickler import Unpickler
9import time
10from XRootD import client
11
12import numpy as np
13
14from datetime import datetime
15from pathlib import Path
16
17import logging
18logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING)
19logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.FATAL)
20
21ROOT.gStyle.SetPalette(ROOT.kViridis)
22ROOT.gInterpreter.ProcessLine('#include "'+os.environ['SNDSW_ROOT']+'/analysis/tools/sndSciFiTools.h"')
23
24def pyExit():
25 "unfortunately need as bypassing an issue related to use xrootd"
26 os.system('kill '+str(os.getpid()))
27atexit.register(pyExit)
28
29
30A,B = ROOT.TVector3(),ROOT.TVector3()
31
32eventComment = {} # possibility to add an event comment before moving to next event
33
34h={}
35from argparse import ArgumentParser
36parser = ArgumentParser()
37parser.add_argument("-r", "--runNumber", dest="runNumber", help="run number", type=int,required=False)
38parser.add_argument("-p", "--path", dest="path", help="path to data file",required=False,default=os.environ["EOSSHIP"]+"/eos/experiment/sndlhc/convertedData/physics/2022/")
39parser.add_argument("-f", "--inputFile", dest="inputFile", help="input file data and MC",default="",required=False)
40parser.add_argument("-g", "--geoFile", dest="geoFile", help="geofile", default=os.environ["EOSSHIP"]+"/eos/experiment/sndlhc/convertedData/physics/2022/geofile_sndlhc_TI18_V0_2022.root")
41parser.add_argument("-P", "--partition", dest="partition", help="partition of data", type=int,required=False,default=-1)
42parser.add_argument("--server", dest="server", help="xrootd server",default=os.environ["EOSSHIP"])
43parser.add_argument("--no-extraInfo", dest="extraInfo", action="store_false", help="Do not print extra information on the event.")
44
45parser.add_argument("--extension", help="Extension of file to save. E.g. png, pdf, root, etc.", default="png")
46parser.add_argument("--rootbatch", help="Run ROOT in batch mode.", action="store_true")
47
48parser.add_argument("--collision_axis", dest="drawCollAxis", help="Draw collision axis", action="store_true")
49
50parser.add_argument("-par", "--parFile", dest="parFile", help="parameter file", default=os.environ['SNDSW_ROOT']+"/python/TrackingParams.xml")
51parser.add_argument("-hf", "--HoughSpaceFormat", dest="HspaceFormat", help="Hough space representation. Should match the 'Hough_space_format' name in parFile, use quotes", default='linearSlopeIntercept')
52
53options = parser.parse_args()
54
55resolution_factor = 1
56if options.rootbatch:
57 ROOT.gROOT.SetBatch()
58 # Produce figures larger than the screen resolution. E.g., for printing.
59 resolution_factor = 2
60
61options.storePic = ''
62trans2local = False
63runInfo = False
64try:
65 fg = ROOT.TFile.Open(options.server+options.p+"RunInfodict.root")
66 pkl = Unpickler(fg)
67 runInfo = pkl.load('runInfo')
68 fg.Close()
69except: pass
70
71import SndlhcGeo
72geo = SndlhcGeo.GeoInterface(options.geoFile)
73
74lsOfGlobals = ROOT.gROOT.GetListOfGlobals()
75lsOfGlobals.Add(geo.modules['Scifi'])
76lsOfGlobals.Add(geo.modules['MuFilter'])
77
78detSize = {}
79em = geo.snd_geo.EmulsionDet
80si = geo.snd_geo.Scifi
81detSize[0] =[si.channel_width, si.channel_width, si.scifimat_z ]
82mi = geo.snd_geo.MuFilter
83if hasattr(mi, "Veto3BarX"): vetoXdim = mi.Veto3BarX/2
84else: vetoXdim = mi.VetoBarX/2
85detSize[1] =[vetoXdim, mi.VetoBarY/2, mi.VetoBarZ/2]
86detSize[2] =[mi.UpstreamBarX/2, mi.UpstreamBarY/2, mi.UpstreamBarZ/2]
87detSize[3] =[mi.DownstreamBarX_ver/2,mi.DownstreamBarY/2,mi.DownstreamBarZ/2]
88withDetector = True # False is useful when using zoom
89with2Points = False # plot start and end point of straw/bar
90mc = False
91
92firstScifi_z = 300 * u.cm
93# Initialize FairLogger: set severity and verbosity
94logger = ROOT.FairLogger.GetLogger()
95logger.SetColoredLog(True)
96logger.SetLogVerbosityLevel('low')
97logger.SetLogScreenLevel('WARNING')
98logger.SetLogToScreen(True)
99
100run = ROOT.FairRunAna()
101ioman = ROOT.FairRootManager.Instance()
102
103if options.inputFile=="":
104 f=ROOT.TFile.Open(options.path+'sndsw_raw_'+str(options.runNumber).zfill(6)+'.root')
105else:
106 f=ROOT.TFile.Open(options.path+options.inputFile)
107
108if f.FindKey('cbmsim'):
109 eventTree = f.cbmsim
110 runId = 'sim'
111 if eventTree.GetBranch('ScifiPoint'): mc = True
112else:
113 eventTree = f.rawConv
114 ioman.SetTreeName('rawConv')
115
116outFile = ROOT.TMemFile('dummy','CREATE')
117source = ROOT.FairFileSource(f)
118run.SetSource(source)
119sink = ROOT.FairRootFileSink(outFile)
120run.SetSink(sink)
121
122HT_tasks = {'muon_reco_task_Sf':SndlhcMuonReco.MuonReco(),
123 'muon_reco_task_DS':SndlhcMuonReco.MuonReco(),
124 'muon_reco_task_nuInt':SndlhcMuonReco.MuonReco()}
125for ht_task in HT_tasks.values():
126 run.AddTask(ht_task)
127
128import SndlhcTracking
130trackTask.SetName('simpleTracking')
131run.AddTask(trackTask)
132
133#avoiding some error messages
134xrdb = ROOT.FairRuntimeDb.instance()
135xrdb.getContainer("FairBaseParSet").setStatic()
136xrdb.getContainer("FairGeoParSet").setStatic()
137
138for ht_task in HT_tasks.values():
139 ht_task.SetParFile(options.parFile)
140 ht_task.SetHoughSpaceFormat(options.HspaceFormat)
141 # force the output of reco task to genfit::Track
142 # as the display code looks for such output
143 ht_task.ForceGenfitTrackFormat()
144HT_tasks['muon_reco_task_Sf'].SetTrackingCase('passing_mu_Sf')
145HT_tasks['muon_reco_task_DS'].SetTrackingCase('passing_mu_DS')
146HT_tasks['muon_reco_task_nuInt'].SetTrackingCase('nu_interaction_products')
147
148run.Init()
149OT = sink.GetOutTree()
150eventTree = ioman.GetInTree()
151eventTree.GetEvent(0)
152if eventTree.EventHeader.ClassName() == 'SNDLHCEventHeader':
153 geo.modules['Scifi'].InitEvent(eventTree.EventHeader)
154 geo.modules['MuFilter'].InitEvent(eventTree.EventHeader)
155# if faireventheader, rely on user to select correct geofile.
156
157if eventTree.GetBranch('Digi_MuFilterHit'):
158# backward compatbility for early converted events
159 eventTree.GetEvent(0)
160 eventTree.Digi_MuFilterHits = eventTree.Digi_MuFilterHit
161
162nav = ROOT.gGeoManager.GetCurrentNavigator()
163
164# get filling scheme
165try:
166 runNumber = eventTree.EventHeader.GetRunId()
167 fg = ROOT.TFile.Open(os.environ['EOSSHIP']+options.p+'FSdict.root')
168 pkl = Unpickler(fg)
169 FSdict = pkl.load('FSdict')
170 fg.Close()
171 if runNumber in FSdict: fsdict = FSdict[runNumber]
172 else: fsdict = False
173except:
174 print('continue without knowing filling scheme')
175 fsdict = False
176
177Nlimit = 4
178onlyScifi = False
179
180def goodEvent(event):
181# can be replaced by any user selection
182 stations = {'Scifi':{},'Mufi':{}}
183 if event.Digi_ScifiHits.GetEntries()>25: return False
184 for d in event.Digi_ScifiHits:
185 stations['Scifi'][d.GetDetectorID()//1000000] = 1
186 for d in event.Digi_MuFilterHits:
187 plane = d.GetDetectorID()//1000
188 stations['Mufi'][plane] = 1
189 totalN = len(stations['Mufi'])+len(stations['Scifi'])
190 if len(stations['Scifi'])>4 and len(stations['Mufi'])>6: return True
191 else: False
192 if onlyScifi and len(stations['Scifi'])>Nlimit: return True
193 elif not onlyScifi and totalN > Nlimit: return True
194 else: return False
195
196def userProcessing(event):
197 '''User hook to add action after event is plotted.
198
199 Useful for adding special objects to the display for example.
200 An example for display of 3-track events with external reco:
201
202 ```python
203 trackTask.multipleTrackCandidates(
204 nMaxCl=8, dGap=0.2, dMax=0.8, dMax3=0.8, ovMax=1, doublet=True, debug=False
205 )
206 n3D = [0, 0]
207 for p in range(2):
208 tc = h['simpleDisplay'].cd(-p + 2)
209 for trackId in trackTask.multipleTrackStore['trackCand'][p]:
210 if trackId < 100000 and not trackTask.multipleTrackStore['doublet']:
211 continue
212 if trackId in trackTask.multipleTrackStore['cloneCand'][p]:
213 continue
214 n3D[p] += 1
215 rc = trackTask.multipleTrackStore['trackCand'][p][trackId].Fit('pol1', 'SQ')
216 trackTask.multipleTrackStore['trackCand'][p][trackId].Draw('same')
217 tc.Update()
218 print('Number of full tracks', n3D)
219 return True
220 ```
221 '''
222 return
223
225# check for b1,b2,IP1,IP2
226 xing = {'all':True,'B1only':False,'B2noB1':False,'noBeam':False}
227 if fsdict:
228 T = eventTree.EventHeader.GetEventTime()
229 bunchNumber = int(T%(4*3564)/4+0.5)
230 nb1 = (3564 + bunchNumber - fsdict['phaseShift1'])%3564
231 nb2 = (3564 + bunchNumber - fsdict['phaseShift1']- fsdict['phaseShift2'])%3564
232 b1 = nb1 in fsdict['B1']
233 b2 = nb2 in fsdict['B2']
234 IP1 = False
235 IP2 = False
236 if b1:
237 IP1 = fsdict['B1'][nb1]['IP1']
238 if b2:
239 IP2 = fsdict['B2'][nb2]['IP2']
240 if b2 and not b1:
241 xing['B2noB1'] = True
242 if b1 and not b2 and not IP1:
243 xing['B1only'] = True
244 if not b1 and not b2: xing['noBeam'] = True
245 return xing
246
247def getSciFiHitDensity(g, x_range=0.5):
248 """Takes ROOT TGraph g and returns array with number of hits within x_range cm of each hit."""
249 ret = []
250 for i in range(g.GetN()):
251 x_i = g.GetPointX(i)
252 y_i = g.GetPointY(i)
253 density = 0
254 for j in range(g.GetN()):
255 x_j = g.GetPointX(j)
256 y_j = g.GetPointY(j)
257 if ((x_i - x_j)**2 + (y_i - y_j)**2) <= x_range**2:
258 density += 1
259 ret.append(density)
260 return ret
261
262def drawLegend(max_density, max_QDC, n_legend_points):
263 """Draws legend for hit colour"""
264 h['simpleDisplay'].cd(1)
265 n_legend_points = 5
266 padLegScifi = ROOT.TPad("legend","legend",0.4,0.15,0.4+0.27, 0.15+0.25)
267 padLegScifi.SetFillStyle(4000)
268 padLegScifi.Draw()
269 padLegScifi.cd()
270 text_scifi_legend = ROOT.TLatex()
271 text_scifi_legend.SetTextAlign(11)
272 text_scifi_legend.SetTextFont(42)
273 text_scifi_legend.SetTextSize(.15)
274 for i in range(n_legend_points) :
275 if i < (n_legend_points - 1) :
276 text_scifi_legend.DrawLatex((i+0.3)*(1./(n_legend_points+2)), 0.2, "{:d}".format(int(i*max_density/(n_legend_points-1))))
277 text_scifi_legend.DrawLatex((i+0.3)*(1./(n_legend_points+2)), 0., "{:.0f}".format(int(i*max_QDC/(n_legend_points-1))))
278 else :
279 text_scifi_legend.DrawLatex((i+0.3)*(1./(n_legend_points+2)), 0.2, "{:d} SciFi hits/cm".format(int(i*max_density/(n_legend_points-1))))
280 text_scifi_legend.DrawLatex((i+0.3)*(1./(n_legend_points+2)), 0., "{:.0f} QDC units".format(int(i*max_QDC/(n_legend_points-1))))
281
282 h["markerCollection"].append(ROOT.TEllipse((i+0.15)*(1./(n_legend_points+2)), 0.26, 0.05/4, 0.05))
283 h["markerCollection"][-1].SetFillColor(ROOT.TColor.GetPalette()[int(float(i*max_density/(n_legend_points-1))/max_density*(len(ROOT.TColor.GetPalette())-1))])
284 h["markerCollection"][-1].Draw("SAME")
285
286 h["markerCollection"].append(ROOT.TBox((i+0.15)*(1./(n_legend_points+2))-0.05/4 , 0.06 - 0.05, (i+0.15)*(1./(n_legend_points+2))+0.05/4, 0.06 + 0.05))
287 h["markerCollection"][-1].SetFillColor(ROOT.TColor.GetPalette()[int(float(i*max_QDC/(n_legend_points-1))/max_QDC*(len(ROOT.TColor.GetPalette())-1))])
288 h["markerCollection"][-1].Draw("SAME")
289
290def drawSciFiHits(g, colour):
291 """Takes TGraph g and draws the graphs markers with the TColor given in list colour."""
292 n = g.GetN()
293 # Draw highest density points last
294 sorted_indices = np.argsort(colour)
295 for i_unsorted in range(0, n):
296 i = int(sorted_indices[i_unsorted])
297
298 x = g.GetPointX(i)
299 y = g.GetPointY(i)
300
301 h["markerCollection"].append(ROOT.TEllipse(x, y, 1.5, 1.5))
302 h["markerCollection"][-1].SetLineWidth(0)
303 h["markerCollection"][-1].SetFillColor(colour[i])
304 h["markerCollection"][-1].Draw("SAME")
305
306def loopEvents(
307 start=0,
308 save=False,
309 goodEvents=False,
310 withTrack=-1,
311 withHoughTrack=-1,
312 nTracks=0,
313 minSipmMult=1,
314 withTiming=False,
315 option=None,
316 Setup='TI18',
317 verbose=0,
318 auto=False,
319 hitColour=None,
320 FilterScifiHits=None
321 ):
322
323 # check the format of FilterScifiHits if set
324 if FilterScifiHits:
325 important_keys = {"bins_x", "min_x", "max_x", "time_lower_range", "time_upper_range"}
326 all_keys = important_keys.copy()
327 all_keys.add("method")
328 filter_parameters = {"bins_x":52., "min_x":0., "max_x":26.,
329 "time_lower_range":1E9/(2*u.snd_freq/u.hertz),
330 "time_upper_range":2E9/(u.snd_freq/u.hertz),
331 "method":0}
332 if FilterScifiHits!="default" and not important_keys.issubset(FilterScifiHits):
333 logging.fatal("Invalid FilterScifiHits format. Two options are supported:\n"
334 "#1 FilterScifiHits = 'default'\nwhich sets the default parameters:\n"+
335 str(filter_parameters)+" or\n"
336 "#2 FilterScifiHits = filter_dictionary \nwhere filter_dictionary has all of the following keys\n"+
337 str(important_keys)+"\nAn additional key 'method' exists: its single supported value, also default, is 0.")
338 return
339 if FilterScifiHits!="default" and any(k not in all_keys for k in FilterScifiHits):
340 logging.warning("Ignoring provided keys other than "+str(all_keys))
341
342 if 'simpleDisplay' not in h:
343 ut.bookCanvas(h,key='simpleDisplay',title='simple event display',nx=1200,ny=1600,cx=1,cy=2)
344
345 h['simpleDisplay'].cd(1)
346 # TI18 coordinate system
347 zStart = 250.
348 zEnd = 600.
349 xStart = -100.
350 yStart = -30.
351 if Setup == 'H6': zStart = 60.
352 if Setup == 'TP': zStart = -50. # old coordinate system with origin in middle of target
353 if Setup == 'H4':
354 xStart = -110.
355 yStart = -10.
356 zStart = 300.
357 zEnd = 430.
358 if 'xz' in h:
359 h.pop('xz').Delete()
360 h.pop('yz').Delete()
361 else:
362 h['xmin'],h['xmax'] = xStart,xStart+110.
363 h['ymin'],h['ymax'] = yStart,yStart+110.
364 h['zmin'],h['zmax'] = zStart,zEnd
365 for d in ['xmin','xmax','ymin','ymax','zmin','zmax']: h['c'+d]=h[d]
366 ut.bookHist(h,'xz','; z [cm]; x [cm]',500,h['czmin'],h['czmax'],100,h['cxmin'],h['cxmax'])
367 ut.bookHist(h,'yz','; z [cm]; y [cm]',500,h['czmin'],h['czmax'],100,h['cymin'],h['cymax'])
368
369 proj = {1:'xz',2:'yz'}
370 h['xz'].SetStats(0)
371 h['yz'].SetStats(0)
372
373 N = -1
374 Tprev = -1
375 A,B = ROOT.TVector3(),ROOT.TVector3()
376 ptext={0:' Y projection',1:' X projection'}
377 text = ROOT.TLatex()
378 event = eventTree
379 OT = sink.GetOutTree()
380 if withTrack==0 or withHoughTrack==0: OT = eventTree
381 if type(start) == type(1):
382 s = start
383 e = event.GetEntries()
384 else:
385 s = 0
386 e = len(start)
387 for N in range(s,e):
388 if type(start) == type(1): rc = event.GetEvent(N)
389 else: rc = event.GetEvent(start[N])
390 if goodEvents and not goodEvent(event): continue
391 nHoughtracks = 0
392 OT.Reco_MuonTracks = ROOT.TObjArray(10)
393 if withHoughTrack > 0:
394 rc = source.GetInTree().GetEvent(N)
395 # Delete SndlhcMuonReco kalman tracks container
396 for ht_task in HT_tasks.values():
397 ht_task.kalman_tracks.Delete()
398 if withHoughTrack==1:
399 HT_tasks['muon_reco_task_Sf'].Exec(0)
400 HT_tasks['muon_reco_task_DS'].Exec(0)
401 elif withHoughTrack==2:
402 HT_tasks['muon_reco_task_Sf'].Exec(0)
403 elif withHoughTrack==3:
404 HT_tasks['muon_reco_task_DS'].Exec(0)
405 elif withHoughTrack==4:
406 HT_tasks['muon_reco_task_nuInt'].Exec(0)
407 # Save the tracks in OT.Reco_MuonTracks object
408 for ht_task in HT_tasks.values():
409 for trk in ht_task.kalman_tracks:
410 OT.Reco_MuonTracks.Add(trk)
411 nHoughtracks = OT.Reco_MuonTracks.GetEntries()
412 if nHoughtracks>0: print('number of tracks by HT:', nHoughtracks)
413
414 if withTrack > 0:
415 # Delete SndlhcTracking fitted tracks container
416 trackTask.fittedTracks.Delete()
417 if withTrack==1:
418 trackTask.ExecuteTask("ScifiDS")
419 elif withTrack==2:
420 trackTask.ExecuteTask("Scifi")
421 elif withTrack==3:
422 trackTask.ExecuteTask("DS")
423 # Save found tracks
424 for trk in trackTask.fittedTracks:
425 OT.Reco_MuonTracks.Add(trk)
426 ntracks = len(OT.Reco_MuonTracks) - nHoughtracks
427 if ntracks>0: print('number of tracks by ST:', ntracks)
428 nAlltracks = len(OT.Reco_MuonTracks)
429 if nAlltracks<nTracks: continue
430
431 if verbose>0:
432 for aTrack in OT.Reco_MuonTracks:
433 print(aTrack.__repr__())
434 mom = aTrack.getFittedState().getMom()
435 pos = aTrack.getFittedState().getPos()
436 mom.Print()
437 pos.Print()
438 T,dT = 0,0
439 T = event.EventHeader.GetEventTime()
440 runId = eventTree.EventHeader.GetRunId()
441 if Tprev >0: dT = T-Tprev
442 Tprev = T
443 if nAlltracks > 0: print('total number of tracks: ', nAlltracks)
444
445 digis = []
446 if event.FindBranch("Digi_ScifiHits"):
447 method = 0
448 if FilterScifiHits!=None and FilterScifiHits!="default":
449 filter_parameters = {k: FilterScifiHits[k] for k in important_keys if k in FilterScifiHits}
450 method = FilterScifiHits.get("method", 0) # set to the default 0, if item is not provided
451 if FilterScifiHits and (Setup=="TI18" or Setup=="H8" or Setup=="H4"):
452 setup = Setup
453 # Only H8 is explicitly supported in the SciFi tools. However, the same baby SciFi
454 # system was reused in H4. It is then safe to use the SciFi tools for H4 as well.
455 if Setup =="H4":
456 setup ="H8"
457 # Convert the filter_parameters to the needed std.map format
458 selection_parameters = ROOT.std.map('string', 'float')()
459 selection_parameters["bins_x"] = float(filter_parameters["bins_x"])
460 selection_parameters["min_x"] = float(filter_parameters["min_x"])
461 selection_parameters["max_x"] = float(filter_parameters["max_x"])
462 selection_parameters["time_lower_range"] = float(filter_parameters["time_lower_range"])
463 selection_parameters["time_upper_range"] = float(filter_parameters["time_upper_range"])
464 digis.append(ROOT.snd.analysis_tools.filterScifiHits(event.Digi_ScifiHits,selection_parameters,method,setup,mc))
465 else:
466 if FilterScifiHits:
467 logging.warning(Setup+" is not supported for the time-filtering of SciFi hits, using all hits instead.")
468 digis.append(event.Digi_ScifiHits)
469 if event.FindBranch("Digi_MuFilterHits"): digis.append(event.Digi_MuFilterHits)
470 if event.FindBranch("Digi_MuFilterHit"): digis.append(event.Digi_MuFilterHit)
471 empty = True
472 for x in digis:
473 if x.GetEntries()>0:
474 if empty: print( "event -> %i"%N)
475 empty = False
476 if empty: continue
477 h['hitCollectionX']= {'Veto':[0,ROOT.TGraphErrors()],'Scifi':[0,ROOT.TGraphErrors()],'DS':[0,ROOT.TGraphErrors()]}
478 h['hitCollectionY']= {'Veto':[0,ROOT.TGraphErrors()],'Scifi':[0,ROOT.TGraphErrors()],'US':[0,ROOT.TGraphErrors()],'DS':[0,ROOT.TGraphErrors()]}
479 if hitColour:
480 h['hitColourX'] = {'Veto': [], 'Scifi': [], 'DS' : []}
481 h['hitColourY'] = {'Veto': [], 'Scifi' : [], 'US' : [], 'DS' : []}
482 h["markerCollection"] = []
483
484 h['firedChannelsX']= {'Veto':[0,0,0,0],'Scifi':[0,0,0],'DS':[0,0,0]}
485 h['firedChannelsY']= {'Veto':[0,0,0,0],'Scifi':[0,0,0],'US':[0,0,0,0],'DS':[0,0,0,0]}
486 systems = {1:'Veto',2:'US',3:'DS',0:'Scifi'}
487 for collection in ['hitCollectionX','hitCollectionY']:
488 for c in h[collection]:
489 rc=h[collection][c][1].SetName(c)
490 rc=h[collection][c][1].Set(0)
491
492 if hitColour:
493 h["markerCollection"] = []
494
495 #Do we still use these lines? Seems no.
496 #And for events having all negative QDCs minT[1] is returned empty and the display crashes.
497 #dTs = "%5.2Fns"%(dT/u.snd_freq*1E9)
498 # find detector which triggered
499 #minT = firstTimeStamp(event)
500 #dTs+= " " + str(minT[1].GetDetectorID())
501 for p in proj:
502 rc = h[ 'simpleDisplay'].cd(p)
503 h[proj[p]].Draw('b')
504
505 if options.drawCollAxis:
506 for k in proj:
507 drawCollisionAxis(h['simpleDisplay'], k)
508
509 if withDetector:
510 drawDetectors()
511 for D in digis:
512 for digi in D:
513 detID = digi.GetDetectorID()
514 sipmMult = 1
515 if digi.GetName() == 'MuFilterHit':
516 system = digi.GetSystem()
517 geo.modules['MuFilter'].GetPosition(detID,A,B)
518 sipmMult = len(digi.GetAllSignals(False,False))
519 if sipmMult<minSipmMult and (system==1 or system==2): continue
520 else:
521 geo.modules['Scifi'].GetSiPMPosition(detID,A,B)
522 system = 0
523 curPath = nav.GetPath()
524 tmp = curPath.rfind('/')
525 nav.cd(curPath[:tmp])
526 first = True
527 for X in [A, B]:
528 if not first and not with2Points:
529 continue
530 first = False
531 globA, locA = array('d', [X[0], X[1], X[2]]), array('d', [X[0], X[1], X[2]])
532 if trans2local:
533 nav.MasterToLocal(globA, locA)
534 Z = X[2]
535 if digi.isVertical():
536 collection = 'hitCollectionX'
537 Y = locA[0]
538 sY = detSize[system][0]
539 else:
540 collection = 'hitCollectionY'
541 Y = locA[1]
542 sY = detSize[system][1]
543 c = h[collection][systems[system]]
544 rc = c[1].SetPoint(c[0], Z, Y)
545 rc = c[1].SetPointError(c[0], detSize[system][2], sY)
546 c[0] += 1
547 if hitColour == "q" :
548 max_QDC = 200 * 16
549 this_qdc = 0
550 ns = max(1,digi.GetnSides())
551 for side in range(ns):
552 for m in range(digi.GetnSiPMs()):
553 qdc = digi.GetSignal(m+side*digi.GetnSiPMs())
554 if not qdc < 0 :
555 this_qdc += qdc
556 if this_qdc > max_QDC :
557 this_qdc = max_QDC
558 fillNode(curPath, ROOT.TColor.GetPalette()[int(this_qdc/max_QDC*(len(ROOT.TColor.GetPalette())-1))])
559 else :
560 fillNode(curPath)
561
562 if digi.isVertical(): F = 'firedChannelsX'
563 else: F = 'firedChannelsY'
564 ns = max(1,digi.GetnSides())
565 for side in range(ns):
566 for m in range(digi.GetnSiPMs()):
567 qdc = digi.GetSignal(m+side*digi.GetnSiPMs())
568 if qdc < 0 and qdc > -900: h[F][systems[system]][1]+=1
569 elif not qdc<0:
570 h[F][systems[system]][0]+=1
571 if len(h[F][systems[system]]) < 2+side: continue
572 h[F][systems[system]][2+side]+=qdc
573 h['hitCollectionY']['Scifi'][1].SetMarkerColor(ROOT.kBlue+2)
574 h['hitCollectionX']['Scifi'][1].SetMarkerColor(ROOT.kBlue+2)
575
576 if hitColour == "q" :
577 for orientation in ['X', 'Y']:
578 max_density = 40
579 density = np.clip(0, max_density, getSciFiHitDensity(h['hitCollection'+orientation]['Scifi'][1]))
580 for i in range(h['hitCollection'+orientation]['Scifi'][1].GetN()) :
581 h['hitColour'+orientation]['Scifi'].append(ROOT.TColor.GetPalette()[int(float(density[i])/max_density*(len(ROOT.TColor.GetPalette())-1))])
582
583 drawLegend(max_density, max_QDC, 5)
584
585 k = 1
586 moreEventInfo = []
587
588
589 for collection in ['hitCollectionX','hitCollectionY']:
590 h['simpleDisplay'].cd(k)
591 drawInfo(h['simpleDisplay'], k, runId, N, T)
592 k+=1
593 for c in h[collection]:
594 F = collection.replace('hitCollection','firedChannels')
595 pj = collection.split('ion')[1]
596 if pj =="X" or c=="Scifi":
597 atext = "%1s %5s %3i +:%3i -:%3i qdc :%5.1F"%(pj,c,h[collection][c][1].GetN(),h[F][c][0],h[F][c][1],h[F][c][2])
598 else:
599 atext = "%1s %5s %3i +:%3i -:%3i qdcL:%5.1F qdcR:%5.1F"%(pj,c,h[collection][c][1].GetN(),h[F][c][0],h[F][c][1],h[F][c][2],h[F][c][3])
600 moreEventInfo.append(atext)
601 print(atext)
602 if h[collection][c][1].GetN()<1: continue
603 if c=='Scifi':
604 if hitColour not in ["q"] :
605 h[collection][c][1].SetMarkerStyle(20)
606 h[collection][c][1].SetMarkerSize(1.5)
607 rc=h[collection][c][1].Draw('sameP')
608 h['display:'+c]=h[collection][c][1]
609 elif hitColour == "q" :
610 drawSciFiHits(h[collection][c][1], h['hitColour'+collection[-1]][c])
611
612 T0 = eventTree.EventHeader.GetEventTime()
613 if type(start) == type(1): rc = event.GetEvent(N-1)
614 else: rc = event.GetEvent(start[N]-1)
615 delTM1 = eventTree.EventHeader.GetEventTime() - T0
616 if type(start) == type(1): rc = event.GetEvent(N+1)
617 else: rc = event.GetEvent(start[N]+1)
618 delTP1 = eventTree.EventHeader.GetEventTime() - T0
619 atext = "timing info, prev event: %6i cc next event: %6i cc"%(delTM1,delTP1)
620 moreEventInfo.append(atext)
621 if type(start) == type(1): rc = event.GetEvent(N)
622 else: rc = event.GetEvent(start[N])
623
624 k = 1
625 for collection in ['hitCollectionX','hitCollectionY']:
626 h['simpleDisplay'].cd(k)
627 drawInfo(h['simpleDisplay'], k, runId, N, T,moreEventInfo)
628 k+=1
629
630 h['simpleDisplay'].Update()
631 if withTiming: timingOfEvent()
632 addTrack(OT)
633
634 if option == "2tracks":
635 rc = twoTrackEvent(sMin=10,dClMin=7,minDistance=0.5,sepDistance=0.5)
636 if not rc: rc = twoTrackEvent(sMin=10,dClMin=7,minDistance=0.5,sepDistance=0.75)
637 if not rc: rc = twoTrackEvent(sMin=10,dClMin=7,minDistance=0.5,sepDistance=1.0)
638 if not rc: rc = twoTrackEvent(sMin=10,dClMin=7,minDistance=0.5,sepDistance=1.75)
639 if not rc: rc = twoTrackEvent(sMin=10,dClMin=7,minDistance=0.5,sepDistance=2.5)
640 if not rc: rc = twoTrackEvent(sMin=10,dClMin=7,minDistance=0.5,sepDistance=3.0)
641
642 if verbose>0: dumpChannels()
643 userProcessing(event)
644
645 if save:
646 h['simpleDisplay'].Print('{:0>2d}-event_{:04d}'.format(runId, N) + '.' + options.extension)
647 if auto:
648 h['simpleDisplay'].Print(options.storePic + str(runId) + '-event_' + str(event.EventHeader.GetEventNumber()) + '.' + options.extension)
649 if not auto:
650 rc = input("hit return for next event or p for print or q for quit: ")
651 if rc=='p':
652 h['simpleDisplay'].Print(options.storePic + str(runId) + '-event_' + str(event.EventHeader.GetEventNumber()) + '.' + options.extension)
653 elif rc == 'q':
654 break
655 else:
656 eventComment[f"{runId}-event_{event.EventHeader.GetEventNumber()}"] = rc
657 if save:
658 os.system("convert -delay 60 -loop 0 event*." + options.extension + " animated.gif")
659
660def addTrack(OT,scifi=False):
661 xax = h['xz'].GetXaxis()
662 nTrack = 0
663 for aTrack in OT.Reco_MuonTracks:
664 trackColor = ROOT.kRed
665 if aTrack.GetUniqueID()==1:
666 trackColor = ROOT.kBlue+2
667 flightDir = trackTask.trackDir(aTrack)
668 print('flight direction: %5.3F significance: %5.3F'%(flightDir[0],flightDir[1]))
669 if aTrack.GetUniqueID()==3: trackColor = ROOT.kBlack
670 if aTrack.GetUniqueID()==11: trackColor = ROOT.kAzure-2 # HT scifi track
671 if aTrack.GetUniqueID()==13: trackColor = ROOT.kGray+2 # HT ds track
672 # HT cross-system track fit
673 if aTrack.GetUniqueID()==15: trackColor = ROOT.kOrange+7
674 S = aTrack.getFitStatus()
675 if not S.isFitConverged() and (scifi or (aTrack.GetUniqueID()==1 or aTrack.GetUniqueID()==11) ):# scifi trk object ids are 1 or 11(Hough tracking)
676 print('not converge')
677 continue
678 for p in [0,1]:
679 h['aLine'+str(nTrack*10+p)] = ROOT.TGraph()
680
681 zEx = xax.GetBinCenter(1)
682 mom = aTrack.getFittedState().getMom()
683 pos = aTrack.getFittedState().getPos()
684 lam = (zEx-pos.z())/mom.z()
685 Ex = [pos.x()+lam*mom.x(),pos.y()+lam*mom.y()]
686 for p in [0,1]: h['aLine'+str(nTrack*10+p)].SetPoint(0,zEx,Ex[p])
687
688 for i in range(aTrack.getNumPointsWithMeasurement()):
689 state = aTrack.getFittedState(i)
690 pos = state.getPos()
691 for p in [0,1]:
692 h['aLine'+str(nTrack*10+p)].SetPoint(i+1,pos[2],pos[p])
693
694 zEx = xax.GetBinCenter(xax.GetLast())
695 mom = aTrack.getFittedState().getMom()
696 pos = aTrack.getFittedState().getPos()
697 lam = (zEx-pos.z())/mom.z()
698 Ex = [pos.x()+lam*mom.x(),pos.y()+lam*mom.y()]
699 for p in [0,1]: h['aLine'+str(nTrack*10+p)].SetPoint(i+2,zEx,Ex[p])
700
701 for p in [0,1]:
702 tc = h[ 'simpleDisplay'].cd(p+1)
703 h['aLine'+str(nTrack*10+p)].SetLineColor(trackColor)
704 h['aLine'+str(nTrack*10+p)].SetLineWidth(2)
705 h['aLine'+str(nTrack*10+p)].Draw('same')
706 tc.Update()
707 h[ 'simpleDisplay'].Update()
708 nTrack+=1
709
710def twoTrackEvent(sMin=10,dClMin=7,minDistance=1.5,sepDistance=0.5):
711 trackTask.clusScifi.Clear()
712 trackTask.scifiCluster()
713 clusters = trackTask.clusScifi
714 sortedClusters={}
715 for aCl in clusters:
716 so = aCl.GetFirst()//100000
717 if not so in sortedClusters: sortedClusters[so]=[]
718 sortedClusters[so].append(aCl)
719 if len(sortedClusters)<sMin: return False
720 M=0
721 for x in sortedClusters:
722 if len(sortedClusters[x]) == 2: M+=1
723 if M < dClMin: return False
724 seeds = {}
725 S = [-1,-1]
726 for o in range(0,2):
727# same procedure for both projections
728# take seeds from from first station with 2 clusters
729 for s in range(1,6):
730 x = 10*s+o
731 if x in sortedClusters:
732 if len(sortedClusters[x])==2:
733 sortedClusters[x][0].GetPosition(A,B)
734 if o%2==1: pos0 = (A[0]+B[0])/2
735 else: pos0 = (A[1]+B[1])/2
736 sortedClusters[x][1].GetPosition(A,B)
737 if o%2==1: pos1 = (A[0]+B[0])/2
738 else: pos1 = (A[1]+B[1])/2
739 if abs(pos0-pos1) > minDistance:
740 S[o] = s
741 break
742 if S[o]<0: break # no seed found
743 seeds[o]={}
744 k = -1
745 for c in sortedClusters[S[o]*10+o]:
746 k += 1
747 c.GetPosition(A,B)
748 if o%2==1: pos = (A[0]+B[0])/2
749 else: pos = (A[1]+B[1])/2
750 seeds[o][k] = [[c,pos]]
751 if k!=1: continue
752 if abs(seeds[o][0][0][1] - seeds[o][1][0][1]) < sepDistance: continue
753 for s in range(1,6):
754 if s==S[o]: continue
755 for c in sortedClusters[s*10+o]:
756 c.GetPosition(A,B)
757 if o%2==1: pos = (A[0]+B[0])/2
758 else: pos = (A[1]+B[1])/2
759 for k in range(2):
760 if abs(seeds[o][k][0][1] - pos) < sepDistance:
761 seeds[o][k].append([c,pos])
762 if S[0]<0 or S[1]<0:
763 passed = False
764 else:
765 passed = True
766 for o in range(0,2):
767 for k in range(2):
768 if len(seeds[o][k])<3:
769 passed = False
770 break
771 print(passed)
772 if passed:
773 tracks = []
774 for k in range(2):
775 # arbitrarly combine X and Y of combination 0
776 n = 0
777 hitlist = {}
778 for o in range(0,2):
779 for X in seeds[o][k]:
780 hitlist[n] = X[0]
781 n+=1
782 theTrack = trackTask.fitTrack(hitlist)
783 if not hasattr(theTrack,"getFittedState"):
784 validTrack = False
785 continue
786 fitStatus = theTrack.getFitStatus()
787 if not fitStatus.isFitConverged():
788 theTrack.Delete()
789 else:
790 tracks.append(theTrack)
791 if len(tracks)==2:
792 OT = sink.GetOutTree()
793 OT.Reco_MuonTracks = tracks
794 addTrack(OT,True)
795 return passed
796
797def drawDetectors():
798 nodes = {'volMuFilter_1/volFeBlockEnd_1':ROOT.kGreen-6}
799 for i in range(mi.NVetoPlanes):
800 nodes['volVeto_1/volVetoPlane_{}_{}'.format(i, i)]=ROOT.kRed
801 for j in range(mi.NVetoBars):
802 if i<2: nodes['volVeto_1/volVetoPlane_{}_{}/volVetoBar_1{}{:0>3d}'.format(i, i, i, j)]=ROOT.kRed
803 if i==2: nodes['volVeto_1/volVetoPlane_{}_{}/volVetoBar_ver_1{}{:0>3d}'.format(i, i, i, j)]=ROOT.kRed
804 if i<2: nodes['volVeto_1/subVetoBox_{}'.format(i)]=ROOT.kGray+1
805 if i==2: nodes['volVeto_1/subVeto3Box_{}'.format(i)]=ROOT.kGray+1
806 for i in range(si.nscifi): # number of scifi stations
807 nodes['volTarget_1/ScifiVolume{}_{}000000'.format(i+1, i+1)]=ROOT.kBlue+1
808 # iron blocks btw SciFi planes in the testbeam 2023-2024 det layout
809 nodes['volTarget_1/volFeTarget{}_1'.format(i+1)]=ROOT.kGreen-6
810 for i in range(em.wall): # number of target walls
811 nodes['volTarget_1/volWallborder_{}'.format(i)]=ROOT.kGray
812 for i in range(mi.NDownstreamPlanes):
813 nodes['volMuFilter_1/volMuDownstreamDet_{}_{}'.format(i, i+mi.NVetoPlanes+mi.NUpstreamPlanes)]=ROOT.kBlue+1
814 for j in range(mi.NDownstreamBars):
815 nodes['volMuFilter_1/volMuDownstreamDet_{}_{}/volMuDownstreamBar_ver_3{}{:0>3d}'.format(i, i+mi.NVetoPlanes+mi.NUpstreamPlanes, i, j+mi.NDownstreamBars)]=ROOT.kBlue+1
816 if i < 3:
817 nodes['volMuFilter_1/volMuDownstreamDet_{}_{}/volMuDownstreamBar_hor_3{}{:0>3d}'.format(i, i+mi.NVetoPlanes+mi.NUpstreamPlanes, i, j)]=ROOT.kBlue+1
818 for i in range(mi.NDownstreamPlanes):
819 nodes['volMuFilter_1/subDSBox_{}'.format(i+mi.NVetoPlanes+mi.NUpstreamPlanes)]=ROOT.kGray+1
820 for i in range(mi.NUpstreamPlanes):
821 nodes['volMuFilter_1/subUSBox_{}'.format(i+mi.NVetoPlanes)]=ROOT.kGray+1
822 nodes['volMuFilter_1/volMuUpstreamDet_{}_{}'.format(i, i+mi.NVetoPlanes)]=ROOT.kBlue+1
823 for j in range(mi.NUpstreamBars):
824 nodes['volMuFilter_1/volMuUpstreamDet_{}_{}/volMuUpstreamBar_2{}00{}'.format(i, i+mi.NVetoPlanes, i, j)]=ROOT.kBlue+1
825 nodes['volMuFilter_1/volFeBlock_{}'.format(i)]=ROOT.kGreen-6
826 for i in range(mi.NVetoPlanes+mi.NUpstreamPlanes,mi.NVetoPlanes+mi.NUpstreamPlanes+mi.NDownstreamPlanes):
827 nodes['volMuFilter_1/volFeBlock_{}'.format(i)]=ROOT.kGreen-6
828 passNodes = {'Block', 'Wall', 'FeTarget'}
829 xNodes = {'UpstreamBar', 'VetoBar', 'hor'}
830 proj = {'X':0,'Y':1}
831 for node_ in nodes:
832 node = '/cave_1/Detector_0/'+node_
833 for p in proj:
834 if node+p in h and any(passNode in node for passNode in passNodes):
835 X = h[node+p]
836 c = proj[p]
837 h['simpleDisplay'].cd(c+1)
838 X.Draw('f&&same')
839 X.Draw('same')
840 else:
841 # check if node exists
842 if not nav.CheckPath(node): continue
843 nav.cd(node)
844 N = nav.GetCurrentNode()
845 S = N.GetVolume().GetShape()
846 dx,dy,dz = S.GetDX(),S.GetDY(),S.GetDZ()
847 ox,oy,oz = S.GetOrigin()[0],S.GetOrigin()[1],S.GetOrigin()[2]
848 P = {}
849 M = {}
850 if p=='X' and (not any(xNode in node for xNode in xNodes) or 'VetoBar_ver' in node):
851 P['LeftBottom'] = array('d',[-dx+ox,oy,-dz+oz])
852 P['LeftTop'] = array('d',[dx+ox,oy,-dz+oz])
853 P['RightBottom'] = array('d',[-dx+ox,oy,dz+oz])
854 P['RightTop'] = array('d',[dx+ox,oy,dz+oz])
855 elif p=='Y' and 'ver' not in node:
856 P['LeftBottom'] = array('d',[ox,-dy+oy,-dz+oz])
857 P['LeftTop'] = array('d',[ox,dy+oy,-dz+oz])
858 P['RightBottom'] = array('d',[ox,-dy+oy,dz+oz])
859 P['RightTop'] = array('d',[ox,dy+oy,dz+oz])
860 else: continue
861 for C in P:
862 M[C] = array('d',[0,0,0])
863 nav.LocalToMaster(P[C],M[C])
864 h[node+p] = ROOT.TPolyLine()
865 X = h[node+p]
866 c = proj[p]
867 X.SetPoint(0,M['LeftBottom'][2],M['LeftBottom'][c])
868 X.SetPoint(1,M['LeftTop'][2],M['LeftTop'][c])
869 X.SetPoint(2,M['RightTop'][2],M['RightTop'][c])
870 X.SetPoint(3,M['RightBottom'][2],M['RightBottom'][c])
871 X.SetPoint(4,M['LeftBottom'][2],M['LeftBottom'][c])
872 X.SetLineColor(nodes[node_])
873 X.SetLineWidth(1)
874 h['simpleDisplay'].cd(c+1)
875 if any(passNode in node for passNode in passNodes):
876 X.SetFillColorAlpha(nodes[node_], 0.5)
877 X.Draw('f&&same')
878 X.Draw('same')
879def zoom(xmin=None,xmax=None,ymin=None,ymax=None,zmin=None,zmax=None):
880# zoom() will reset to default setting
881 for d in ['xmin','xmax','ymin','ymax','zmin','zmax']:
882 if eval(d): h['c'+d]=eval(d)
883 else: h['c'+d]=h[d]
884 h['xz'].GetXaxis().SetRangeUser(h['czmin'],h['czmax'])
885 h['yz'].GetXaxis().SetRangeUser(h['czmin'],h['czmax'])
886 h['xz'].GetYaxis().SetRangeUser(h['cxmin'],h['cxmax'])
887 h['yz'].GetYaxis().SetRangeUser(h['cymin'],h['cymax'])
888 tc = h['simpleDisplay'].cd(1)
889 tc.Update()
890 tc = h['simpleDisplay'].cd(2)
891 tc.Update()
892 h['simpleDisplay'].Update()
893
894def dumpVeto():
895 muHits = {10:[],11:[]}
896 for aHit in eventTree.Digi_MuFilterHits:
897 if not aHit.isValid(): continue
898 s = aHit.GetDetectorID()//10000
899 if s>1: continue
900 p = (aHit.GetDetectorID()//1000)%10
901 bar = (aHit.GetDetectorID()%1000)%60
902 plane = s*10+p
903 muHits[plane].append(aHit)
904 for plane in [10,11]:
905 for aHit in muHits[plane]:
906 S =aHit.GetAllSignals(False,False)
907 txt = ""
908 for x in S:
909 if x[1]>0: txt+=str(x[1])+" "
910 print(plane, (aHit.GetDetectorID()%1000)%60, txt)
911
912# decode MuFilter detID
913def MuFilter_PlaneBars(detID):
914 s = detID//10000
915 l = (detID%10000)//1000 # plane number
916 bar = (detID%1000)
917 if s>2:
918 l=2*l
919 if bar>59:
920 bar=bar-60
921 if l<6: l+=1
922 return {'station':s,'plane':l,'bar':bar}
923
924def checkOtherTriggers(event,deadTime = 100,debug=False):
925 T0 = event.EventHeader.GetEventTime()
926 N = event.EventHeader.GetEventNumber()
927 Nprev = 1
928 rc = event.GetEvent(N-Nprev)
929 dt = T0 - event.EventHeader.GetEventTime()
930 otherFastTrigger = False
931 otherAdvTrigger = False
932 tightNoiseFilter = False
933 while dt < deadTime:
934 otherFastTrigger = False
935 for x in event.EventHeader.GetFastNoiseFilters():
936 if debug: print('fast:', x.first, x.second )
937 if x.second and not x.first == 'Veto_Total': otherFastTrigger = True
938 otherAdvTrigger = False
939 for x in event.EventHeader.GetAdvNoiseFilters():
940 if debug: print('adv:', x.first, x.second )
941 if x.second and not x.first == 'VETO_Planes': otherAdvTrigger = True
942 if debug: print('pre event ',Nprev,dt,otherFastTrigger,otherAdvTrigger)
943 if otherFastTrigger and otherAdvTrigger:
944 rc = event.GetEvent(N)
945 return otherFastTrigger, otherAdvTrigger, tightNoiseFilter, Nprev, dt
946 Nprev+=1
947 rc = event.GetEvent(N-Nprev)
948 dt = T0 - event.EventHeader.GetEventTime()
949 Nprev = 1
950 rc = event.GetEvent(N-Nprev)
951 dt = T0 - event.EventHeader.GetEventTime()
952 while dt < deadTime:
953 hits = {1:0,0:0}
954 for aHit in event.Digi_MuFilterHits:
955 Minfo = MuFilter_PlaneBars(aHit.GetDetectorID())
956 s,l,bar = Minfo['station'],Minfo['plane'],Minfo['bar']
957 if s>1: continue
958 allChannels = aHit.GetAllSignals(False,False)
959 hits[l]+=len(allChannels)
960 noiseFilter0 = (hits[0]+hits[1])>4.5
961 noiseFilter1 = hits[0]>0 and hits[1]>0
962 if debug: print('veto hits:',hits)
963 if noiseFilter0 and noiseFilter1:
964 tightNoiseFilter = True
965 rc = event.GetEvent(N)
966 return otherFastTrigger, otherAdvTrigger, tightNoiseFilter, Nprev-1, dt
967 Nprev+=1
968 rc = event.GetEvent(N-Nprev)
969 dt = T0 - event.EventHeader.GetEventTime()
970 if Nprev>1:
971 rc = event.GetEvent(N-Nprev+1)
972 dt = T0 - event.EventHeader.GetEventTime()
973 rc = event.GetEvent(N)
974 return otherFastTrigger, otherAdvTrigger, tightNoiseFilter, Nprev-1, dt
975
976def cleanTracks():
977 OT = sink.GetOutTree()
978 listOfDetIDs = {}
979 n = 0
980 for aTrack in OT.Reco_MuonTracks:
981 listOfDetIDs[n] = []
982 for i in range(aTrack.getNumPointsWithMeasurement()):
983 M = aTrack.getPointWithMeasurement(i)
984 R = M.getRawMeasurement()
985 listOfDetIDs[n].append(R.getDetId())
986 if R.getDetId()>0: listOfDetIDs[n].append(R.getDetId()-1)
987 listOfDetIDs[n].append(R.getDetId()+1)
988 n+=1
989 uniqueTracks = []
990 for n1 in range( len(listOfDetIDs) ):
991 unique = True
992 for n2 in range( len(listOfDetIDs) ):
993 if n1==n2: continue
994 I = set(listOfDetIDs[n1]).intersection(listOfDetIDs[n2])
995 if len(I)>0: unique = False
996 if unique: uniqueTracks.append(n1)
997 if len(uniqueTracks)>1:
998 for n1 in range( len(listOfDetIDs) ): print(listOfDetIDs[n1])
999 return uniqueTracks
1000
1001def timingOfEvent(makeCluster=False,debug=False):
1002 ut.bookHist(h,'evTimeDS','cor time of hits;[ns]',70,-5.,30)
1003 ut.bookHist(h,'evTimeScifi','cor time of hits blue DS red Scifi;[ns]',70,-5.,30)
1004 ut.bookCanvas(h,'tevTime','cor time of hits',1024,768,1,1)
1005 h['evTimeScifi'].SetLineColor(ROOT.kRed)
1006 h['evTimeDS'].SetLineColor(ROOT.kBlue)
1007 h['evTimeScifi'].SetStats(0)
1008 h['evTimeDS'].SetStats(0)
1009 h['evTimeScifi'].SetLineWidth(2)
1010 h['evTimeDS'].SetLineWidth(2)
1011 if makeCluster: trackTask.scifiCluster()
1012 meanXY = {}
1013 for siCl in trackTask.clusScifi:
1014 detID = siCl.GetFirst()
1015 s = detID//1000000
1016 isVertical = detID%1000000//100000
1017 siCl.GetPosition(A,B)
1018 z=(A[2]+B[2])/2.
1019 pos = (A[1]+B[1])/2.
1020 L = abs(A[0]-B[0])/2.
1021 if isVertical:
1022 pos = (A[0]+B[0])/2.
1023 L = abs(A[1]-B[1])/2.
1024 corTime = geo.modules['Scifi'].GetCorrectedTime(detID, siCl.GetTime(), 0) - (z-firstScifi_z)/u.speedOfLight
1025 h['evTimeScifi'].Fill(corTime)
1026 if debug: print(detID,corTime,pos)
1027 for aHit in eventTree.Digi_MuFilterHits:
1028 detID = aHit.GetDetectorID()
1029 if not detID//10000==3: continue
1030 if aHit.isVertical(): nmax = 1
1031 else: nmax=2
1032 geo.modules['MuFilter'].GetPosition(detID,A,B)
1033 z=(A[2]+B[2])/2.
1034 pos = (A[1]+B[1])/2.
1035 L = abs(A[0]-B[0])/2.
1036 if isVertical:
1037 pos = (A[0]+B[0])/2.
1038 L = abs(A[1]-B[1])/2.
1039 for i in range(nmax):
1040 corTime = geo.modules['MuFilter'].GetCorrectedTime(detID, i, aHit.GetTime(i)*u.snd_TDC2ns, 0)- (z-firstScifi_z)/u.speedOfLight
1041 h['evTimeDS'].Fill(corTime)
1042 if debug: print(detID,i,corTime,pos)
1043 tc=h['tevTime'].cd()
1044 h['evTimeScifi'].Draw()
1045 h['evTimeDS'].Draw('same')
1046 tc.Update()
1047def mufiNoise():
1048 for s in range(1,4):
1049 ut.bookHist(h,'mult'+str(s),'hit mult for system '+str(s),100,-0.5,99.5)
1050 ut.bookHist(h,'multb'+str(s),'hit mult per bar for system '+str(s),20,-0.5,19.5)
1051 ut.bookHist(h,'res'+str(s),'residual system '+str(s),20,-10.,10.)
1052 OT = sink.GetOutTree()
1053 N=0
1054 for event in eventTree:
1055 N+=1
1056 if N%1000==0: print(N)
1057 OT.Reco_MuonTracks.Delete()
1058 rc = trackTask.ExecuteTask("Scifi")
1059 for aTrack in OT.Reco_MuonTracks:
1060 mom = aTrack.getFittedState().getMom()
1061 pos = aTrack.getFittedState().getPos()
1062 if not aTrack.getFitStatus().isFitConverged(): continue
1063 mult = {1:0,2:0,3:0}
1064 for aHit in eventTree.Digi_MuFilterHits:
1065 if not aHit.isValid(): continue
1066 s = aHit.GetDetectorID()//10000
1067 S = aHit.GetAllSignals(False,False)
1068 rc = h['multb'+str(s)].Fill(len(S))
1069 mult[s]+=len(S)
1070 if s==2 or s==1:
1071 geo.modules['MuFilter'].GetPosition(aHit.GetDetectorID(),A,B)
1072 y = (A[1]+B[1])/2.
1073 zEx = (A[2]+B[2])/2.
1074 lam = (zEx-pos.z())/mom.z()
1075 Ey = pos.y()+lam*mom.y()
1076 rc = h['res'+str(s)].Fill(Ey-y)
1077 for s in mult: rc = h['mult'+str(s)].Fill(mult[s])
1078 ut.bookCanvas(h,'noise','',1200,1200,2,3)
1079 for s in range(1,4):
1080 tc = h['noise'].cd(s*2-1)
1081 tc.SetLogy(1)
1082 h['mult'+str(s)].Draw()
1083 h['noise'].cd(s*2)
1084 h['multb'+str(s)].Draw()
1085 ut.bookCanvas(h,'res','',600,1200,1,3)
1086 for s in range(1,4):
1087 tc = h['res'].cd(s)
1088 h['res'+str(s)].Draw()
1089
1090def firstTimeStamp(event):
1091 tmin = [1E9,'']
1092 digis = [event.Digi_MuFilterHits,event.Digi_ScifiHits]
1093 for digi in event.Digi_ScifiHits:
1094 dt = digi.GetTime()
1095 if dt<tmin[0]:
1096 tmin[0]=dt
1097 tmin[1]=digi
1098 for digi in event.Digi_MuFilterHits:
1099 for t in digi.GetAllTimes(): # will not give time if QDC<0!
1100 dt = t.second
1101 if dt<tmin[0]:
1102 tmin[0]=dt
1103 tmin[1]=digi
1104 return tmin
1105
1106def dumpChannels(D='Digi_MuFilterHits'):
1107 X = eval("eventTree."+D)
1108 text = {}
1109 for aHit in X:
1110 side = 'L'
1111 txt = "%8i"%(aHit.GetDetectorID())
1112 for k in range(aHit.GetnSiPMs()*aHit.GetnSides()):
1113 qdc = aHit.GetSignal(k)
1114 if qdc < -900: continue
1115 i = k
1116 if not k<aHit.GetnSiPMs():
1117 i = k-aHit.GetnSiPMs()
1118 if side == 'L':
1119 txt += " | "
1120 side = 'R'
1121 txt+= " %2i:%4.1F "%(i,qdc)
1122 text[aHit.GetDetectorID()] = txt
1123 keys = list(text.keys())
1124 keys.sort()
1125 for k in keys: print(text[k])
1126
1127def fillNode(node, color=None):
1128 xNodes = {'UpstreamBar', 'VetoBar', 'hor'}
1129 proj = {'X':0,'Y':1}
1130 if color == None :
1131 hcal_color = ROOT.kBlack
1132 veto_color = ROOT.kRed+1
1133 else :
1134 hcal_color = color
1135 veto_color = color
1136 thick = 5
1137 for p in proj:
1138 if node+p in h:
1139 X = h[node+p]
1140 if 'Veto' in node:
1141 color = veto_color
1142 else :
1143 color = hcal_color
1144
1145 if 'Downstream' in node:
1146 thick = 5
1147 c = proj[p]
1148 h[ 'simpleDisplay'].cd(c+1)
1149 X.SetFillColor(color)
1150 X.SetLineColor(color)
1151 X.SetLineWidth(thick)
1152 X.Draw('f&&same')
1153 X.Draw('same')
1154
1155def drawInfo(pad, k, run, event, timestamp,moreEventInfo=[]):
1156 drawLogo = True
1157 drawText = True
1158 if drawLogo:
1159 padLogo = ROOT.TPad("logo","logo",0.1,0.1,0.2,0.3)
1160 padLogo.SetFillStyle(4000)
1161 padLogo.SetFillColorAlpha(0, 0)
1162 padLogo.Draw()
1163 logo = ROOT.TImage.Open('$SNDSW_ROOT/shipLHC/Large__SND_Logo_black_cut.png')
1164 logo.SetConstRatio(True)
1165 padLogo.cd()
1166 logo.Draw()
1167 pad.cd(k)
1168
1169 if drawText:
1170 if k==1 or len(moreEventInfo)<5:
1171 runNumber = eventTree.EventHeader.GetRunId()
1172 timestamp_print = False
1173 if not mc and hasattr(eventTree.EventHeader, "GetUTCtimestamp"):
1174 timestamp_print = True
1175 time_event= datetime.utcfromtimestamp(eventTree.EventHeader.GetUTCtimestamp())
1176 padText = ROOT.TPad("info","info",0.19,0.1,0.6,0.3)
1177 padText.SetFillStyle(4000)
1178 padText.Draw()
1179 padText.cd()
1180 textInfo = ROOT.TLatex()
1181 textInfo.SetTextAlign(11)
1182 textInfo.SetTextFont(42)
1183 textInfo.SetTextSize(.15)
1184 textInfo.DrawLatex(0, 0.6, 'SND@LHC Experiment, CERN')
1185 if hasattr(eventTree.EventHeader,'GetEventNumber'): N = eventTree.EventHeader.GetEventNumber()
1186 else: N = event
1187 textInfo.DrawLatex(0, 0.4, 'Run / Event: '+str(run)+' / '+str(N))
1188 if timestamp_print:
1189 textInfo.DrawLatex(0, 0.2, 'Time (GMT): {}'.format(time_event))
1190 pad.cd(k)
1191 elif options.extraInfo:
1192 padText = ROOT.TPad("info","info",0.29,0.12,0.9,0.35)
1193 padText.SetFillStyle(4000)
1194 padText.Draw()
1195 padText.cd()
1196 textInfo = ROOT.TLatex()
1197 textInfo.SetTextAlign(11)
1198 textInfo.SetTextFont(42)
1199 textInfo.SetTextSize(.1)
1200 textInfo.SetTextColor(ROOT.kMagenta+2)
1201 dely = 0.12
1202 ystart = 0.85
1203 for i in range(7):
1204 textInfo.DrawLatex(0.4, 0.9-dely*i, moreEventInfo[i])
1205 pad.cd(k)
1206
1207def drawCollisionAxis(pad, k):
1208 line_name = "collision_axis_line_" + str(k)
1209 h[line_name] = ROOT.TLine(h["zmin"], 0, h["zmax"], 0)
1210 h[line_name].SetLineColor(ROOT.kRed)
1211 h[line_name].SetLineStyle(2)
1212
1213 text_name = "collision_axis_text_" + str(k)
1214 h[text_name] = ROOT.TText(h["zmin"] + 8, 0 + 2, "Collision axis")
1215 h[text_name].SetTextAlign(12)
1216 h[text_name].SetTextFont(43)
1217 h[text_name].SetTextSize(13 * resolution_factor)
1218 h[text_name].SetTextColor(ROOT.kRed)
1219
1220 pad.cd(k)
1221 h[line_name].Draw()
1222 h[text_name].Draw()
1223
1224
1225
getSciFiHitDensity(g, x_range=0.5)
drawLegend(max_density, max_QDC, n_legend_points)