SND@LHC Software
Loading...
Searching...
No Matches
shipStrawTracking.py
Go to the documentation of this file.
1from __future__ import print_function
2from __future__ import division
3# Mikhail Hushchyn, mikhail.hushchyn@cern.ch
4
5from past.builtins import cmp
6from builtins import range
7import ROOT
8import numpy
9
10import getopt
11import sys
12
13# For ShipGeo
14from ShipGeoConfig import ConfigRegistry
15from rootpyPickler import Unpickler
16
17# For modules
18import shipDet_conf
19import global_variables
20
21# For track pattern recognition
22
23
24def get_n_hits(hits):
25 return len(hits)
26
27
28
29
30def run_track_pattern_recognition(input_file, geo_file, output_file, method):
31 """
32 Runs all steps of track pattern recognition.
33 Parameters
34 ----------
35 input_file : string
36 Path to an input .root file with events.
37 geo_file : string
38 Path to a file with SHiP geometry.
39 output_file : string
40 Path to an output .root file with quality plots.
41 method : string
42 Name of a track pattern recognition method.
43 """
44
45
46
47
48 # Check geo file
49 try:
50 fgeo = ROOT.TFile(geo_file)
51 except:
52 print("An error with opening the ship geo file.")
53 raise
54
55 sGeo = fgeo.FAIRGeom
56
57 # Prepare ShipGeo dictionary
58 if not fgeo.FindKey('ShipGeo'):
59
60 if sGeo.GetVolume('EcalModule3') :
61 ecalGeoFile = "ecal_ellipse6x12m2.geo"
62 else:
63 ecalGeoFile = "ecal_ellipse5x10m2.geo"
64
65 if dy:
66 ShipGeo = ConfigRegistry.loadpy("$FAIRSHIP/geometry/geometry_config.py", Yheight = dy, EcalGeoFile = ecalGeoFile)
67 else:
68 ShipGeo = ConfigRegistry.loadpy("$FAIRSHIP/geometry/geometry_config.py", EcalGeoFile = ecalGeoFile)
69
70 else:
71 upkl = Unpickler(fgeo)
72 ShipGeo = upkl.load('ShipGeo')
73
74 # Globals
75 global_variables.ShipGeo = ShipGeo
76
77
78
79 import shipDet_conf
80 run = ROOT.FairRunSim()
81 run.SetName("TGeant4") # Transport engine
82 run.SetOutputFile("dummy") # Output file
83 run.SetUserConfig("g4Config_basic.C") # geant4 transport not used, only needed for the mag field
84 rtdb = run.GetRuntimeDb()
85
86 modules = shipDet_conf.configure(run,ShipGeo)
87 run.Init()
88
89 #run = ROOT.FairRunSim()
90 #modules = shipDet_conf.configure(run,ShipGeo)
91
92
93
94
95
96 import geomGeant4
97 if hasattr(ShipGeo.Bfield,"fieldMap"):
98 fieldMaker = geomGeant4.addVMCFields(ShipGeo, '', True, withVirtualMC = False)
99 else:
100 print("no fieldmap given, geofile too old, not anymore support")
101 exit(-1)
102 sGeo = fgeo.FAIRGeom
103 geoMat = ROOT.genfit.TGeoMaterialInterface()
104 ROOT.genfit.MaterialEffects.getInstance().init(geoMat)
105 bfield = ROOT.genfit.FairShipFields()
106 bfield.setField(fieldMaker.getGlobalField())
107 fM = ROOT.genfit.FieldManager.getInstance()
108 fM.init(bfield)
109
110
111
112
113 # Check input file
114 try:
115 fn = ROOT.TFile(input_file,'update')
116 except:
117 print("An error with opening the input data file.")
118 raise
119
120 sTree = fn.cbmsim
121 sTree.Write()
122
123
124
125 h = init_book_hist()
126
127
128 import shipPatRec
129
130 # Init book of hists for the quality measurements
131 metrics = {'n_hits': [],
132 'reconstructible': 0,
133 'passed_y12': 0, 'passed_stereo12': 0, 'passed_12': 0,
134 'passed_y34': 0, 'passed_stereo34': 0, 'passed_34': 0,
135 'passed_combined': 0, 'reco_passed': 0, 'reco_passed_no_clones': 0,
136 'frac_y12': [], 'frac_stereo12': [], 'frac_12': [],
137 'frac_y34': [], 'frac_stereo34': [], 'frac_34': [],
138 'reco_frac_tot': [],
139 'reco_mc_p': [], 'reco_mc_theta': [],
140 'fitted_p': [], 'fitted_pval': [], 'fitted_chi': [],
141 'fitted_x': [], 'fitted_y': [], 'fitted_z': [], 'fitted_mass': []}
142
143 # Start event loop
144 nEvents = sTree.GetEntries()
145
146
147 for iEvent in range(nEvents):
148
149 if iEvent%1000 == 0:
150 print('Event ', iEvent)
151
152
153
154 rc = sTree.GetEvent(iEvent)
155
156
157
158 reconstructible_tracks = getReconstructibleTracks(iEvent, sTree, sGeo, ShipGeo)
159
160 metrics['reconstructible'] += len(reconstructible_tracks)
161 for i_reco in reconstructible_tracks:
162 h['TracksPassed'].Fill("Reconstructible tracks", 1)
163 h['TracksPassedU'].Fill("Reconstructible tracks", 1)
164
165 in_y12 = []
166 in_stereo12 = []
167 in_12 = []
168 in_y34 = []
169 in_stereo34 = []
170 in_34 = []
171 in_combo = []
172
173 found_track_ids = []
174 n_tracks = len(reconstructible_tracks)
175 n_recognized = 0
176 n_clones = 0
177 n_ghosts = 0
178 n_others = 0
179
180 min_eff = 0.
181
182
183
184 nTracklets = sTree.Tracklets.GetEntriesFast()
185
186 for i_track in range(nTracklets):
187
188 atracklet = sTree.Tracklets[i_track]
189
190 if atracklet.getType() != 1: # this is a not full track (tracklet)
191 continue
192
193 atrack = atracklet.getList()
194
195 if atrack.size() == 0:
196 continue
197
198 hits = {'X': [], 'Y': [], 'Z': [],
199 'DetID': [], 'TrackID': [],
200 'Pz': [], 'Px': [], 'Py': [],
201 'dist2Wire': [], 'Pdg': []}
202
203 for ihit in atrack:
204 ahit = sTree.strawtubesPoint[ihit]
205 hits['X'] += [ahit.GetX()]
206 hits['Y'] += [ahit.GetY()]
207 hits['Z'] += [ahit.GetZ()]
208 hits['DetID'] += [ahit.GetDetectorID()]
209 hits['TrackID'] += [ahit.GetTrackID()]
210 hits['Pz'] += [ahit.GetPz()]
211 hits['Px'] += [ahit.GetPx()]
212 hits['Py'] += [ahit.GetPy()]
213 hits['dist2Wire'] += [ahit.dist2Wire()]
214 hits['Pdg'] += [ahit.PdgCode()]
215
216 # List to numpy arrays
217 for key in hits.keys():
218 hits[key] = numpy.array(hits[key])
219
220 # Decoding
221 statnb, vnb, pnb, lnb, snb = decodeDetectorID(hits['DetID'])
222 is_stereo = ((vnb == 1) + (vnb == 2))
223 is_y = ((vnb == 0) + (vnb == 3))
224 is_before = ((statnb == 1) + (statnb == 2))
225 is_after = ((statnb == 3) + (statnb == 4))
226
227
228 # Metrics
229 metrics['n_hits'] += [get_n_hits(hits['TrackID'])]
230
231 # Tracks passed
232 frac_y12, tmax_y12 = fracMCsame(hits['TrackID'][is_before * is_y])
233 n_hits_y12 = get_n_hits(hits['TrackID'][is_before * is_y])
234 frac_stereo12, tmax_stereo12 = fracMCsame(hits['TrackID'][is_before * is_stereo])
235 n_hits_stereo12 = get_n_hits(hits['TrackID'][is_before * is_stereo])
236 frac_12, tmax_12 = fracMCsame(hits['TrackID'][is_before])
237 n_hits_12 = get_n_hits(hits['TrackID'][is_before])
238
239 frac_y34, tmax_y34 = fracMCsame(hits['TrackID'][is_after * is_y])
240 n_hits_y34 = get_n_hits(hits['TrackID'][is_after * is_y])
241 frac_stereo34, tmax_stereo34 = fracMCsame(hits['TrackID'][is_after * is_stereo])
242 n_hits_stereo34 = get_n_hits(hits['TrackID'][is_after * is_stereo])
243 frac_34, tmax_34 = fracMCsame(hits['TrackID'][is_after])
244 n_hits_34 = get_n_hits(hits['TrackID'][is_after])
245 frac_tot, tmax_tot = fracMCsame(hits['TrackID'])
246 n_hits_tot = get_n_hits(hits['TrackID'])
247
248 if tmax_y12 == tmax_stereo12 and tmax_y12 == tmax_y34 and tmax_y12 == tmax_stereo34:
249 if frac_y12 >= min_eff and frac_stereo12 >= min_eff and frac_y34 >= min_eff and frac_stereo34 >= min_eff:
250
251 if tmax_y12 in reconstructible_tracks and tmax_y12 not in found_track_ids:
252 n_recognized += 1
253 found_track_ids.append(tmax_y12)
254 elif tmax_y12 in reconstructible_tracks and tmax_y12 in found_track_ids:
255 n_clones += 1
256 elif tmax_y12 not in reconstructible_tracks:
257 n_others += 1
258
259 else:
260 n_ghosts += 1
261 else:
262 n_ghosts += 1
263
264 is_reconstructed = 0
265 is_reconstructed_no_clones = 0
266
267
268 if tmax_y12 in reconstructible_tracks:
269 metrics['passed_y12'] += 1
270 metrics['frac_y12'] += [frac_y12]
271 h['TracksPassed'].Fill("Y view station 1&2", 1)
272 if tmax_y12 not in in_y12:
273 h['TracksPassedU'].Fill("Y view station 1&2", 1)
274 in_y12.append(tmax_y12)
275
276 if tmax_stereo12 == tmax_y12:
277 metrics['passed_stereo12'] += 1
278 metrics['frac_stereo12'] += [frac_stereo12]
279 h['TracksPassed'].Fill("Stereo station 1&2", 1)
280 if tmax_stereo12 not in in_stereo12:
281 h['TracksPassedU'].Fill("Stereo station 1&2", 1)
282 in_stereo12.append(tmax_stereo12)
283
284 if tmax_12 == tmax_y12:
285 metrics['passed_12'] += 1
286 metrics['frac_12'] += [frac_12]
287 h['TracksPassed'].Fill("station 1&2", 1)
288 if tmax_12 not in in_12:
289 h['TracksPassedU'].Fill("station 1&2", 1)
290 in_12.append(tmax_12)
291
292 if tmax_y34 in reconstructible_tracks:
293 metrics['passed_y34'] += 1
294 metrics['frac_y34'] += [frac_y34]
295 h['TracksPassed'].Fill("Y view station 3&4", 1)
296 if tmax_y34 not in in_y34:
297 h['TracksPassedU'].Fill("Y view station 3&4", 1)
298 in_y34.append(tmax_y34)
299
300 if tmax_stereo34 == tmax_y34:
301 metrics['passed_stereo34'] += 1
302 metrics['frac_stereo34'] += [frac_stereo34]
303 h['TracksPassed'].Fill("Stereo station 3&4", 1)
304 if tmax_stereo34 not in in_stereo34:
305 h['TracksPassedU'].Fill("Stereo station 3&4", 1)
306 in_stereo34.append(tmax_stereo34)
307
308 if tmax_34 == tmax_y34:
309 metrics['passed_34'] += 1
310 metrics['frac_34'] += [frac_34]
311 h['TracksPassed'].Fill("station 3&4", 1)
312 if tmax_34 not in in_34:
313 h['TracksPassedU'].Fill("station 3&4", 1)
314 in_34.append(tmax_34)
315
316 if tmax_12 == tmax_34:
317 metrics['passed_combined'] += 1
318 h['TracksPassed'].Fill("Combined stations 1&2/3&4", 1)
319 metrics['reco_passed'] += 1
320 is_reconstructed = 1
321 if tmax_34 not in in_combo:
322 h['TracksPassedU'].Fill("Combined stations 1&2/3&4", 1)
323 metrics['reco_passed_no_clones'] += 1
324 in_combo.append(tmax_34)
325 is_reconstructed_no_clones = 1
326
327 # For reconstructed tracks
328 if is_reconstructed == 0:
329 continue
330
331 metrics['reco_frac_tot'] += [frac_tot]
332
333 # Momentum
334 Pz = hits['Pz']
335 Px = hits['Px']
336 Py = hits['Py']
337
338 p, px, py, pz = getPtruthFirst(sTree, tmax_tot)
339 pt = math.sqrt(px**2 + py**2)
340
341 Z_true = []
342 X_true = []
343 Y_true = []
344 for ahit in sTree.strawtubesPoint:
345 if ahit.GetTrackID() == tmax_tot:
346 az, ax, ay = ahit.GetZ(),ahit.GetX(),ahit.GetY()
347 Z_true.append(az)
348 X_true.append(ax)
349 Y_true.append(ay)
350
351
352 metrics['reco_mc_p'] += [p]
353 h['TracksPassed_p'].Fill(p, 1)
354
355 # Direction
356 Z = hits['Z'][(hits['TrackID'] == tmax_tot) * is_before]
357 X = hits['X'][(hits['TrackID'] == tmax_tot) * is_before]
358 Y = hits['Y'][(hits['TrackID'] == tmax_tot) * is_before]
359 Z = Z - Z[0]
360 X = X - X[0]
361 Y = Y - Y[0]
362 R = numpy.sqrt(X**2 + Y**2 + Z**2)
363 Theta = numpy.arccos(Z[1:] / R[1:])
364 theta = numpy.mean(Theta)
365
366 metrics['reco_mc_theta'] += [theta]
367
368 h['n_hits_reco_y12'].Fill(n_hits_y12)
369 h['n_hits_reco_stereo12'].Fill(n_hits_stereo12)
370 h['n_hits_reco_12'].Fill(n_hits_12)
371 h['n_hits_reco_y34'].Fill(n_hits_y34)
372 h['n_hits_reco_stereo34'].Fill(n_hits_stereo34)
373 h['n_hits_reco_34'].Fill(n_hits_34)
374 h['n_hits_reco'].Fill(n_hits_tot)
375
376 h['n_hits_y12'].Fill(p, n_hits_y12)
377 h['n_hits_stereo12'].Fill(p, n_hits_stereo12)
378 h['n_hits_12'].Fill(p, n_hits_12)
379 h['n_hits_y34'].Fill(p, n_hits_y34)
380 h['n_hits_stereo34'].Fill(p, n_hits_stereo34)
381 h['n_hits_34'].Fill(p, n_hits_34)
382 h['n_hits_total'].Fill(p, n_hits_tot)
383
384 h['frac_y12'].Fill(p, frac_y12)
385 h['frac_stereo12'].Fill(p, frac_stereo12)
386 h['frac_12'].Fill(p, frac_12)
387 h['frac_y34'].Fill(p, frac_y34)
388 h['frac_stereo34'].Fill(p, frac_stereo34)
389 h['frac_34'].Fill(p, frac_34)
390 h['frac_total'].Fill(p, frac_tot)
391
392 h['frac_y12_dist'].Fill(frac_y12)
393 h['frac_stereo12_dist'].Fill(frac_stereo12)
394 h['frac_12_dist'].Fill(frac_12)
395 h['frac_y34_dist'].Fill(frac_y34)
396 h['frac_stereo34_dist'].Fill(frac_stereo34)
397 h['frac_34_dist'].Fill(frac_34)
398 h['frac_total_dist'].Fill(frac_tot)
399
400 # Fitted track
401
402 thetrack = sTree.FitTracks[i_track]
403
404 fitStatus = thetrack.getFitStatus()
405 thetrack.prune("CFL") # http://sourceforge.net/p/genfit/code/HEAD/tree/trunk/core/include/Track.h#l280
406
407 nmeas = fitStatus.getNdf()
408 pval = fitStatus.getPVal()
409 chi2 = fitStatus.getChi2() / nmeas
410
411 metrics['fitted_pval'] += [pval]
412 metrics['fitted_chi'] += [chi2]
413
414 h['chi2fittedtracks'].Fill(chi2)
415 h['pvalfittedtracks'].Fill(pval)
416
417
418 try:
419
420 fittedState = thetrack.getFittedState()
421 fittedMom = fittedState.getMomMag()
422 fittedMom = fittedMom #*int(charge)
423
424 px_fit,py_fit,pz_fit = fittedState.getMom().x(),fittedState.getMom().y(),fittedState.getMom().z()
425 p_fit = fittedMom
426 pt_fit = math.sqrt(px_fit**2 + py_fit**2)
427
428
429 metrics['fitted_p'] += [p_fit]
430 perr = (p - p_fit) / p
431 h['ptrue-p/ptrue'].Fill(perr)
432 h['perr'].Fill(p, perr)
433 h['perr_direction'].Fill(numpy.rad2deg(theta), perr)
434
435 pterr = (pt - pt_fit) / pt
436 h['pttrue-pt/pttrue'].Fill(pterr)
437
438 pxerr = (px - px_fit) / px
439 h['pxtrue-px/pxtrue'].Fill(pxerr)
440
441 pyerr = (py - py_fit) / py
442 h['pytrue-py/pytrue'].Fill(pyerr)
443
444 pzerr = (pz - pz_fit) / pz
445 h['pztrue-pz/pztrue'].Fill(pzerr)
446
447 if math.fabs(p) > 0.0 :
448 h['pvspfitted'].Fill(p, fittedMom)
449 fittedtrackDir = fittedState.getDir()
450 fittedx=math.degrees(math.acos(fittedtrackDir[0]))
451 fittedy=math.degrees(math.acos(fittedtrackDir[1]))
452 fittedz=math.degrees(math.acos(fittedtrackDir[2]))
453 fittedmass = fittedState.getMass()
454 h['momentumfittedtracks'].Fill(fittedMom)
455 h['xdirectionfittedtracks'].Fill(fittedx)
456 h['ydirectionfittedtracks'].Fill(fittedy)
457 h['zdirectionfittedtracks'].Fill(fittedz)
458 h['massfittedtracks'].Fill(fittedmass)
459
460 metrics['fitted_x'] += [fittedx]
461 metrics['fitted_y'] += [fittedy]
462 metrics['fitted_z'] += [fittedz]
463 metrics['fitted_mass'] += [fittedmass]
464
465
466 Z_fit = []
467 X_fit = []
468 Y_fit = []
469 for az in Z_true:
470 rc,pos,mom = extrapolateToPlane(thetrack, az)
471 Z_fit.append(pos.Z())
472 X_fit.append(pos.X())
473 Y_fit.append(pos.Y())
474
475 for i in range(len(Z_true)):
476 xerr = abs(X_fit[i] - X_true[i])
477 yerr = abs(Y_fit[i] - Y_true[i])
478 h['abs(x - x-true)'].Fill(xerr)
479 h['abs(y - y-true)'].Fill(yerr)
480
481 rmse_x = numpy.sqrt(numpy.mean((numpy.array(X_fit) - numpy.array(X_true))**2))
482 rmse_y = numpy.sqrt(numpy.mean((numpy.array(Y_fit) - numpy.array(Y_true))**2))
483 h['rmse_x'].Fill(rmse_x)
484 h['rmse_y'].Fill(rmse_y)
485
486
487
488 except:
489 print("Problem with fitted state.")
490
491
492 h['Reco_tracks'].Fill("N total", n_tracks)
493 h['Reco_tracks'].Fill("N recognized tracks", n_recognized)
494 h['Reco_tracks'].Fill("N clones", n_clones)
495 h['Reco_tracks'].Fill("N ghosts", n_ghosts)
496 h['Reco_tracks'].Fill("N others", n_others)
497
498
499
500 save_hists(h, output_file)
501
502 return metrics
503
504
505
506
507
509
510
511
513 # etrapolate to a plane perpendicular to beam direction (z)
514 rc,pos,mom = False,None,None
515 parallelToZ = ROOT.TVector3(0., 0., 1.)
516 fst = fT.getFitStatus()
517 if fst.isFitConverged():
518 # test for fit status for each point
519 if fT.getPoint(0).getFitterInfo() and fT.getPoint(1).getFitterInfo():
520 fstate0,fstate1 = fT.getFittedState(0),fT.getFittedState(1)
521 fPos0,fPos1 = fstate0.getPos(),fstate1.getPos()
522 if abs(z-fPos0.z()) < abs(z-fPos1.z()): fstate = fstate0
523 else: fstate = fstate1
524 zs = z
525 NewPosition = ROOT.TVector3(0., 0., zs)
526 rep = ROOT.genfit.RKTrackRep(13*cmp(fstate.getPDG(),0) )
527 state = ROOT.genfit.StateOnPlane(rep)
528 pos,mom = fstate.getPos(),fstate.getMom()
529 rep.setPosMom(state,pos,mom)
530 try:
531 rep.extrapolateToPlane(state, NewPosition, parallelToZ )
532 pos,mom = state.getPos(),state.getMom()
533 rc = True
534 except:
535 print('error with extrapolation')
536 pass
537 if not rc:
538 # use linear extrapolation
539 px,py,pz = mom.X(),mom.Y(),mom.Z()
540 lam = (z-pos.Z())/pz
541 pos = ROOT.TVector3( pos.X()+lam*px, pos.Y()+lam*py, z )
542 return rc,pos,mom
543
544
545
546
547
549 """
550 Decodes detector ID.
551 Parameters
552 ----------
553 detID : int or array-like
554 Detector ID values.
555 Returns
556 -------
557 statnb : int or array-like
558 Station numbers.
559 vnb : int or array-like
560 View numbers.
561 pnb : int or array-like
562 Plane numbers.
563 lnb : int or array-like
564 Layer numbers.
565 snb : int or array-like
566 Straw tube numbers.
567 """
568
569 statnb = detID // 10000000
570 vnb = (detID - statnb * 10000000) // 1000000
571 pnb = (detID - statnb * 10000000 - vnb * 1000000) // 100000
572 lnb = (detID - statnb * 10000000 - vnb * 1000000 - pnb * 100000) // 10000
573 snb = detID - statnb * 10000000 - vnb * 1000000 - pnb * 100000 - lnb * 10000 - 2000
574
575 return statnb, vnb, pnb, lnb, snb
576
577
578
579def fracMCsame(trackids):
580 """
581 Estimates max fraction of true hit labels for a recognized track.
582 trackids : array_like
583 hit indexes of a recognized track
584 Retunrs
585 -------
586 frac : float
587 Max fraction of true hit labels.
588 tmax : int
589 True hit label with max fraction in a recognized track.
590 """
591
592 track={}
593 nh=len(trackids)
594
595 for tid in trackids:
596 if tid in track:
597 track[tid] += 1
598 else:
599 track[tid] = 1
600
601 #now get track with largest number of hits
602 if track != {}:
603 tmax = max(track, key=track.get)
604 else:
605 track = {-999: 0}
606 tmax = -999
607
608 frac=0.0
609 if nh > 0:
610 frac = float(track[tmax]) / float(nh)
611
612 return frac, tmax
613
614
615
616
617def getReconstructibleTracks(iEvent, sTree, sGeo, ShipGeo):
618 """
619 Estimates reconstructible tracks of an event.
620 Parameters
621 ----------
622 iEvent : int
623 Event id.
624 stree : root file
625 Events in raw format.
626 fGeo : object
627 Contains SHiP detector geometry.
628 ShipGeo : object
629 Contains SHiP detector geometry.
630 Returns
631 -------
632 MCTrackIDs : array-like
633 List of reconstructible track ids.
634 """
635
636 VetoStationZ = ShipGeo.vetoStation.z
637 VetoStationEndZ = VetoStationZ + (ShipGeo.strawtubes.DeltazView + ShipGeo.strawtubes.OuterStrawDiameter) / 2
638
639 TStationz = ShipGeo.TrackStation1.z
640 Zpos = TStationz - 3. /2. * ShipGeo.strawtubes.DeltazView - 1. / 2. * ShipGeo.strawtubes.DeltazPlane - 1. / 2. * ShipGeo.strawtubes.DeltazLayer
641 TStation1StartZ = Zpos - ShipGeo.strawtubes.OuterStrawDiameter / 2
642
643 Zpos = TStationz + 3. /2. * ShipGeo.strawtubes.DeltazView + 1. / 2. * ShipGeo.strawtubes.DeltazPlane + 1. / 2. * ShipGeo.strawtubes.DeltazLayer
644 TStation4EndZ = Zpos + ShipGeo.strawtubes.OuterStrawDiameter / 2
645
646
647 PDG=ROOT.TDatabasePDG.Instance()
648
649 #returns a list of reconstructible tracks for this event
650 #call this routine once for each event before smearing
651 MCTrackIDs=[]
652 rc = sTree.GetEvent(iEvent)
653 nMCTracks = sTree.MCTrack.GetEntriesFast()
654
655
656 #1. MCTrackIDs: list of tracks decaying after the last tstation and originating before the first
657 for i in reversed(range(nMCTracks)):
658 atrack = sTree.MCTrack.At(i)
659 #track endpoint after tstations?
660 if atrack.GetStartZ() > TStation4EndZ :
661 motherId = atrack.GetMotherId()
662 if motherId > -1 :
663 mothertrack = sTree.MCTrack.At(motherId)
664 mothertrackZ = mothertrack.GetStartZ()
665 #this mother track is a HNL decay
666 #track starts inside the decay volume? (after veto, before 1 st tstation)
667 if mothertrackZ < TStation1StartZ and mothertrackZ > VetoStationEndZ:
668 if motherId not in MCTrackIDs:
669 MCTrackIDs.append(motherId)
670
671 if len(MCTrackIDs)==0:
672 return MCTrackIDs
673
674
675
676 #2. hitsinTimeDet: list of tracks with hits in TimeDet
677 #nVetoHits = sTree.vetoPoint.GetEntriesFast()
678 #hitsinTimeDet=[]
679 #for i in range(nVetoHits):
680 # avetohit = sTree.vetoPoint.At(i)
681 # #hit in TimeDet?
682 # if sGeo.FindNode(avetohit.GetX(), avetohit.GetY(), avetohit.GetZ()).GetName() == 'TimeDet_1':
683 # if avetohit.GetTrackID() not in hitsinTimeDet:
684 # hitsinTimeDet.append(avetohit.GetTrackID())
685
686
687
688 #3. Remove tracks from MCTrackIDs that are not in hitsinTimeDet
689 #itemstoremove = []
690 #for item in MCTrackIDs:
691 # if item not in hitsinTimeDet:
692 # itemstoremove.append(item)
693 #for item in itemstoremove:
694 # MCTrackIDs.remove(item)
695
696 #if len(MCTrackIDs)==0:
697 # return MCTrackIDs
698
699
700
701 #4. Find straws that have multiple hits
702 nHits = sTree.strawtubesPoint.GetEntriesFast()
703 hitstraws = {}
704 duplicatestrawhit = []
705
706 for i in range(nHits):
707 ahit = sTree.strawtubesPoint[i]
708 if (str(ahit.GetDetectorID())[:1]=="5") :
709 continue
710 strawname = str(ahit.GetDetectorID())
711
712 if strawname in hitstraws:
713 #straw was already hit
714 if ahit.GetX() > hitstraws[strawname][1]:
715 #this hit has higher x, discard it
716 duplicatestrawhit.append(i)
717 else:
718 #del hitstraws[strawname]
719 duplicatestrawhit.append(hitstraws[strawname][0])
720 hitstraws[strawname] = [i,ahit.GetX()]
721 else:
722 hitstraws[strawname] = [i,ahit.GetX()]
723
724
725
726 #5. Split hits up by station and outside stations
727 hits1={}
728 hits2={}
729 hits3={}
730 hits4={}
731 trackoutsidestations=[]
732
733 for i in range(nHits):
734
735 if i in duplicatestrawhit:
736 continue
737
738 ahit = sTree.strawtubesPoint[i]
739
740 # is hit inside acceptance? if not mark the track as bad
741 if (((ahit.GetX()/245.)**2 + (ahit.GetY()/495.)**2) >= 1.):
742 if ahit.GetTrackID() not in trackoutsidestations:
743 trackoutsidestations.append(ahit.GetTrackID())
744
745 if ahit.GetTrackID() not in MCTrackIDs:
746 #hit on not reconstructible track
747 continue
748
749 #group hits per tracking station, key = trackid
750 if str(ahit.GetDetectorID())[:1]=="1" :
751 if ahit.GetTrackID() in hits1:
752 hits1[ahit.GetTrackID()] = [hits1[ahit.GetTrackID()][0], i]
753 else:
754 hits1[ahit.GetTrackID()] = [i]
755
756 if str(ahit.GetDetectorID())[:1]=="2" :
757 if ahit.GetTrackID() in hits2:
758 hits2[ahit.GetTrackID()] = [hits2[ahit.GetTrackID()][0], i]
759 else:
760 hits2[ahit.GetTrackID()] = [i]
761
762 if str(ahit.GetDetectorID())[:1]=="3" :
763 if ahit.GetTrackID() in hits3:
764 hits3[ahit.GetTrackID()] = [hits3[ahit.GetTrackID()][0], i]
765 else:
766 hits3[ahit.GetTrackID()] = [i]
767
768 if str(ahit.GetDetectorID())[:1]=="4" :
769 if ahit.GetTrackID() in hits4:
770 hits4[ahit.GetTrackID()] = [hits4[ahit.GetTrackID()][0], i]
771 else:
772 hits4[ahit.GetTrackID()] = [i]
773
774
775
776 #6. Make list of tracks with hits in in station 1,2,3 & 4
777 tracks_with_hits_in_all_stations = []
778
779 for key in hits1.keys():
780 if (key in hits2 and key in hits3 ) and key in hits4:
781 if key not in tracks_with_hits_in_all_stations and key not in trackoutsidestations:
782 tracks_with_hits_in_all_stations.append(key)
783
784 for key in hits2.keys():
785 if (key in hits1 and key in hits3 ) and key in hits4:
786 if key not in tracks_with_hits_in_all_stations and key not in trackoutsidestations:
787 tracks_with_hits_in_all_stations.append(key)
788
789 for key in hits3.keys():
790 if ( key in hits2 and key in hits1 ) and key in hits4:
791 if key not in tracks_with_hits_in_all_stations and key not in trackoutsidestations:
792 tracks_with_hits_in_all_stations.append(key)
793
794 for key in hits4.keys():
795 if (key in hits2 and key in hits3) and key in hits1:
796 if key not in tracks_with_hits_in_all_stations and key not in trackoutsidestations:
797 tracks_with_hits_in_all_stations.append(key)
798
799
800
801 #7. Remove tracks from MCTrackIDs with hits outside acceptance or doesn't have hits in all stations
802 itemstoremove = []
803
804 for item in MCTrackIDs:
805 if item not in tracks_with_hits_in_all_stations:
806 itemstoremove.append(item)
807
808 for item in itemstoremove:
809 MCTrackIDs.remove(item)
810
811 if len(MCTrackIDs)==0:
812 return MCTrackIDs
813
814 itemstoremove = []
815
816 for item in MCTrackIDs:
817 atrack = sTree.MCTrack.At(item)
818 motherId=atrack.GetMotherId()
819 if motherId != 2: #!!!!
820 itemstoremove.append(item)
821
822 for item in itemstoremove:
823 MCTrackIDs.remove(item)
824
825
826
827 return MCTrackIDs
828
829
830def getPtruthFirst(sTree, mcPartKey):
831 Ptruth,Ptruthx,Ptruthy,Ptruthz = -1.,-1.,-1.,-1.
832 for ahit in sTree.strawtubesPoint:
833 if ahit.GetTrackID() == mcPartKey:
834 Ptruthx,Ptruthy,Ptruthz = ahit.GetPx(),ahit.GetPy(),ahit.GetPz()
835 Ptruth = ROOT.TMath.Sqrt(Ptruthx**2+Ptruthy**2+Ptruthz**2)
836 break
837 return Ptruth,Ptruthx,Ptruthy,Ptruthz
838
839
840
842
843import ROOT
844import numpy
845import rootUtils as ut
846import math
847
848
849
850
851
852
853def save_hists(h, path):
854 """
855 Save book of plots.
856 Parameters
857 ----------
858 h : dict
859 Dictionary of plots.
860 path : string
861 Path where the plots will be saved.
862 """
863 ut.writeHists(h, path)
864
866 """
867 Creates empty plots.
868 Returns
869 -------
870 h : dict
871 Dictionary of plots.
872 """
873
874 h={} #dictionary of histograms
875
876 ut.bookHist(h,'TracksPassed','Tracks passing the pattern recognition', 8, -0.5, 7.5)
877 h['TracksPassed'].GetXaxis().SetBinLabel(1,"Reconstructible tracks")
878 h['TracksPassed'].GetXaxis().SetBinLabel(2,"Y view station 1&2")
879 h['TracksPassed'].GetXaxis().SetBinLabel(3,"Stereo station 1&2")
880 h['TracksPassed'].GetXaxis().SetBinLabel(4,"station 1&2")
881 h['TracksPassed'].GetXaxis().SetBinLabel(5,"Y view station 3&4")
882 h['TracksPassed'].GetXaxis().SetBinLabel(6,"Stereo station 3&4")
883 h['TracksPassed'].GetXaxis().SetBinLabel(7,"station 3&4")
884 h['TracksPassed'].GetXaxis().SetBinLabel(8,"Combined stations 1&2/3&4")
885
886 ut.bookHist(h,'TracksPassedU','Tracks passing the pattern recognition. No clones.', 8, -0.5, 7.5)
887 h['TracksPassedU'].GetXaxis().SetBinLabel(1,"Reconstructible tracks")
888 h['TracksPassedU'].GetXaxis().SetBinLabel(2,"Y view station 1&2")
889 h['TracksPassedU'].GetXaxis().SetBinLabel(3,"Stereo station 1&2")
890 h['TracksPassedU'].GetXaxis().SetBinLabel(4,"station 1&2")
891 h['TracksPassedU'].GetXaxis().SetBinLabel(5,"Y view station 3&4")
892 h['TracksPassedU'].GetXaxis().SetBinLabel(6,"Stereo station 3&4")
893 h['TracksPassedU'].GetXaxis().SetBinLabel(7,"station 3&4")
894 h['TracksPassedU'].GetXaxis().SetBinLabel(8,"Combined stations 1&2/3&4")
895
896 ut.bookProf(h, 'TracksPassed_p', 'Tracks passing the pattern recognition from momentum', 30, 0, 150)
897 h['TracksPassed_p'].GetXaxis().SetTitle('Momentum')
898 h['TracksPassed_p'].GetYaxis().SetTitle('N')
899
900 ut.bookHist(h,'ptrue-p/ptrue','(p - p-true)/p',200,-0.25,0.25)
901 ut.bookHist(h,'pttrue-pt/pttrue','(pt - pt-true)/pt',200,-0.25,0.25)
902 ut.bookHist(h,'pxtrue-px/pxtrue','(px - px-true)/px',200,-0.25,0.25)
903 ut.bookHist(h,'pytrue-py/pytrue','(py - py-true)/py',200,-0.25,0.25)
904 ut.bookHist(h,'pztrue-pz/pztrue','(pz - pz-true)/pz',200,-0.25,0.25)
905
906
907 ut.bookHist(h,'n_hits_reco','Number of recognized hits per track, total',64,0.,64.01)
908 ut.bookHist(h,'n_hits_reco_12','Number of recognized hits per track, station 1&2',32,0.,32.01)
909 ut.bookHist(h,'n_hits_reco_y12','Number of recognized hits per track, Y view station 1&2',32,0.,32.01)
910 ut.bookHist(h,'n_hits_reco_stereo12','Number of recognized hits per track, Stereo view station 1&2',32,0.,32.01)
911 ut.bookHist(h,'n_hits_reco_34','Number of recognized hits per track, station 3&4',32,0.,32.01)
912 ut.bookHist(h,'n_hits_reco_y34','Number of recognized hits per track, Y view station 3&4',32,0.,32.01)
913 ut.bookHist(h,'n_hits_reco_stereo34','Number of recognized hits per track, Stereo view station 3&4',32,0.,32.01)
914
915 # Momentum dependences
916 ut.bookProf(h, 'n_hits_total', 'Number of recognized hits per track, total', 30, 0, 150)
917 h['n_hits_total'].GetXaxis().SetTitle('Momentum')
918 h['n_hits_total'].GetYaxis().SetTitle('N')
919
920 ut.bookProf(h, 'n_hits_y12', 'Number of recognized hits per track, Y view station 1&2', 30, 0, 150)
921 h['n_hits_y12'].GetXaxis().SetTitle('Momentum')
922 h['n_hits_y12'].GetYaxis().SetTitle('N')
923
924 ut.bookProf(h, 'n_hits_stereo12', 'Number of recognized hits per track, Stereo view station 1&2', 30, 0, 150)
925 h['n_hits_stereo12'].GetXaxis().SetTitle('Momentum')
926 h['n_hits_stereo12'].GetYaxis().SetTitle('N')
927
928 ut.bookProf(h, 'n_hits_12', 'Number of recognized hits per track, station 1&2', 30, 0, 150)
929 h['n_hits_12'].GetXaxis().SetTitle('Momentum')
930 h['n_hits_12'].GetYaxis().SetTitle('N')
931
932 ut.bookProf(h, 'n_hits_y34', 'Number of recognized hits per track, Y view station 3&4', 30, 0, 150)
933 h['n_hits_y34'].GetXaxis().SetTitle('Momentum')
934 h['n_hits_y34'].GetYaxis().SetTitle('N')
935
936 ut.bookProf(h, 'n_hits_stereo34', 'Number of recognized hits per track, Stereo view station 3&4', 30, 0, 150)
937 h['n_hits_stereo34'].GetXaxis().SetTitle('Momentum')
938 h['n_hits_stereo34'].GetYaxis().SetTitle('N')
939
940 ut.bookProf(h, 'n_hits_34', 'Number of recognized hits per track, station 3&4', 30, 0, 150)
941 h['n_hits_34'].GetXaxis().SetTitle('Momentum')
942 h['n_hits_34'].GetYaxis().SetTitle('N')
943
944 ut.bookProf(h,'perr','(p - p-true)/p',30, 0, 150)
945 h['perr'].GetXaxis().SetTitle('Momentum')
946 h['perr'].GetYaxis().SetTitle('(p - p-true)/p')
947
948 ut.bookProf(h,'perr_direction','(p - p-true)/p from track direction in YZ plane',20, 0, 10.01)
949 h['perr_direction'].GetXaxis().SetTitle('Degree')
950 h['perr_direction'].GetYaxis().SetTitle('(p - p-true)/p')
951
952
953 ut.bookProf(h, 'frac_total', 'Fraction of hits the same as MC hits, total', 30, 0, 150)
954 h['frac_total'].GetXaxis().SetTitle('Momentum')
955 h['frac_total'].GetYaxis().SetTitle('Fraction')
956
957 ut.bookProf(h, 'frac_y12', 'Fraction of hits the same as MC hits, Y view station 1&2', 30, 0, 150)
958 h['frac_y12'].GetXaxis().SetTitle('Momentum')
959 h['frac_y12'].GetYaxis().SetTitle('Fraction')
960
961 ut.bookProf(h, 'frac_stereo12', 'Fraction of hits the same as MC hits, Stereo view station 1&2', 30, 0, 150)
962 h['frac_stereo12'].GetXaxis().SetTitle('Momentum')
963 h['frac_stereo12'].GetYaxis().SetTitle('Fraction')
964
965 ut.bookProf(h, 'frac_12', 'Fraction of hits the same as MC hits, station 1&2', 30, 0, 150)
966 h['frac_12'].GetXaxis().SetTitle('Momentum')
967 h['frac_12'].GetYaxis().SetTitle('Fraction')
968
969 ut.bookProf(h, 'frac_y34', 'Fraction of hits the same as MC hits, Y view station 3&4', 30, 0, 150)
970 h['frac_y34'].GetXaxis().SetTitle('Momentum')
971 h['frac_y34'].GetYaxis().SetTitle('Fraction')
972
973 ut.bookProf(h, 'frac_stereo34', 'Fraction of hits the same as MC hits, Stereo view station 3&4', 30, 0, 150)
974 h['frac_stereo34'].GetXaxis().SetTitle('Momentum')
975 h['frac_stereo34'].GetYaxis().SetTitle('Fraction')
976
977 ut.bookProf(h, 'frac_34', 'Fraction of hits the same as MC hits, station 3&4', 30, 0, 150)
978 h['frac_34'].GetXaxis().SetTitle('Momentum')
979 h['frac_34'].GetYaxis().SetTitle('Fraction')
980
981 ut.bookHist(h,'frac_y12_dist','Fraction of hits the same as MC hits, Y view station 1&2',50,0.5,1.001)
982 ut.bookHist(h,'frac_stereo12_dist','Fraction of hits the same as MC hits, Stereo view station 1&2',50,0.5,1.001)
983 ut.bookHist(h,'frac_12_dist','Fraction of hits the same as MC hits, station 1&2',50,0.5,1.001)
984 ut.bookHist(h,'frac_y34_dist','Fraction of hits the same as MC hits, Y view station 3&4',50,0.5,1.001)
985 ut.bookHist(h,'frac_stereo34_dist','Fraction of hits the same as MC hits, Stereo view station 3&4',50,0.5,1.001)
986 ut.bookHist(h,'frac_34_dist','Fraction of hits the same as MC hits, station 3&4',50,0.5,1.001)
987 ut.bookHist(h,'frac_total_dist','Fraction of hits the same as MC hits, total',50,0.5,1.001)
988
989
990 ut.bookHist(h,'Reco_tracks','Number of recognized tracks, clones and ghosts for reconstructible tracks.', 5, -0.5, 4.5)
991 h['Reco_tracks'].GetXaxis().SetBinLabel(1,"N total")
992 h['Reco_tracks'].GetXaxis().SetBinLabel(2,"N recognized tracks")
993 h['Reco_tracks'].GetXaxis().SetBinLabel(3,"N clones")
994 h['Reco_tracks'].GetXaxis().SetBinLabel(4,"N ghosts")
995 h['Reco_tracks'].GetXaxis().SetBinLabel(5,"N others")
996
997
998 # Fitted values
999 ut.bookHist(h,'chi2fittedtracks','Chi^2 per NDOF for fitted tracks',210,-0.05,20.05)
1000 ut.bookHist(h,'pvalfittedtracks','pval for fitted tracks',110,-0.05,1.05)
1001 ut.bookHist(h,'momentumfittedtracks','momentum for fitted tracks',251,-0.05,250.05)
1002 ut.bookHist(h,'xdirectionfittedtracks','x-direction for fitted tracks',91,-0.5,90.5)
1003 ut.bookHist(h,'ydirectionfittedtracks','y-direction for fitted tracks',91,-0.5,90.5)
1004 ut.bookHist(h,'zdirectionfittedtracks','z-direction for fitted tracks',91,-0.5,90.5)
1005 ut.bookHist(h,'massfittedtracks','mass fitted tracks',210,-0.005,0.205)
1006 ut.bookHist(h,'pvspfitted','p-patrec vs p-fitted',401,-200.5,200.5,401,-200.5,200.5)
1007
1008
1009 ut.bookHist(h,'abs(x - x-true)','Hits abs(x - x-true)',260,-0.05,5.05)
1010 ut.bookHist(h,'abs(y - y-true)','Hits abs(y - y-true)',260,-0.05,5.05)
1011
1012 ut.bookHist(h,'rmse_x','Hits x fit rmse',260,-0.05,5.05)
1013 ut.bookHist(h,'rmse_y','Hits y fit rmse',260,-0.05,5.05)
1014
1015
1016
1017 return h
1018
1019
1020
1022
1023
1024#if __name__ == "__main__":
1025
1026input_file = None
1027geo_file = None
1028output_file = 'hists.root'
1029method = 'Baseline'
1030
1031
1032argv = sys.argv[1:]
1033
1034msg = '''Runs ship track pattern recognition.\n\
1035 Usage:\n\
1036 python RunPR.py [options] \n\
1037 Example: \n\
1038 python RunPR.py -f "ship.conical.Pythia8-TGeant4.root" -g "geofile_full.conical.Pythia8-TGeant4.root"
1039 Options:
1040 -f --input : Input file path
1041 -g --geo : Path to geo file
1042 -o --output : Output .root file path. Default is hists.root
1043 -m --method : Name of a track pattern recognition method: 'Baseline', 'FH', 'AR', 'R'
1044 : Default is 'Baseline'
1045 -h --help : Shows this help
1046 '''
1047
1048try:
1049 opts, args = getopt.getopt(argv, "hm:f:g:o:",
1050 ["help", "method=", "input=", "geo=", "output="])
1051except getopt.GetoptError:
1052 print("Wrong options were used. Please, read the following help:\n")
1053 print(msg)
1054 sys.exit(2)
1055if len(argv) == 0:
1056 print(msg)
1057 sys.exit(2)
1058for opt, arg in opts:
1059 if opt in ('-h', "--help"):
1060 print(msg)
1061 sys.exit()
1062 elif opt in ("-m", "--method"):
1063 method = arg
1064 elif opt in ("-f", "--input"):
1065 input_file = arg
1066 elif opt in ("-g", "--geo"):
1067 geo_file = arg
1068 elif opt in ("-o", "--output"):
1069 output_file = arg
1070
1071
1072metrics = run_track_pattern_recognition(input_file, geo_file, output_file, method)
addVMCFields(shipGeo, controlFile='', verbose=False, withVirtualMC=True)
configure(run, ship_geo)
getReconstructibleTracks(iEvent, sTree, sGeo, ShipGeo)
run_track_pattern_recognition(input_file, geo_file, output_file, method)
save_hists(h, path)
Helping functions #####################################################.
getPtruthFirst(sTree, mcPartKey)