ATLAS Offline Software
Loading...
Searching...
No Matches
module_driven_slicing.py
Go to the documentation of this file.
1#----------------------------------------------------------------------
2# Imports with Arg Parsing before ROOT import because of help conflict
3#----------------------------------------------------------------------
4import argparse
5
6parser = argparse.ArgumentParser(description='Flattens Wrapper Files')
7parser.add_argument('inname', metavar='inputfile', type=str, nargs='+',
8 help='input file name (should be FPGATrackSim Wrapper File)')
9parser.add_argument('--evts', action='store', type=int,
10 help='number of events to process', default=(1<<30)) # default is large integer
11parser.add_argument('--trim', action='store', type=float,
12 help='trim modules with less than given fraction of tracks', default=None) # default is large integer
13parser.add_argument('--nslices', action='store', type=int,
14 help='number of slices to build', default=6)
15parser.add_argument('--keylayer', action='store', type=str,
16 help='keylayer as det,bec,layer', default="strip,barrel,2")
17parser.add_argument('--keylayer2', action='store', type=str,
18 help='second keylayer subdivides slices', default=None)
19parser.add_argument('--outfilelabel', action='store', type=str,
20 help='label to start outfile with', default="Unlabled")
21parser.add_argument('--etarange', action='store', type=str,
22 help='range of eta for slice', default="-100,100")
23parser.add_argument('--fullgran', action='store_true')
24parser.add_argument('--test1slice', action='store_true')
25
26args = parser.parse_args()
27
28
29# imports
30import ROOT
31import time
32import glob
33import os
34from collections import defaultdict
35import bisect
36
37# Setup core logging here
38from PyJobTransforms.trfLogger import msg
39
40
41
42#----------------------------------------------------------------------
43# Handy tree of dictionary tools
44#----------------------------------------------------------------------
45defaultdictlambda=lambda : defaultdict(defaultdictlambda) # amazing self referential lambda
46
47def transformNodes(tree,func):
48 retv={}
49 for key,val in tree.items():
50 if 'dict' in type(val).__name__:
51 retv[key]=transformNodes(val,func)
52 else:
53 if 'list' in type(val).__name__:
54 retv[key]=[func(subval) for subval in val]
55 else:
56 retv[key]=func(val)
57 return retv
58
59
60#----------------------------------------------------------------------
61# Constants
62#----------------------------------------------------------------------
63dets=["pixel","strip"]
64regs=["barrel","endcap"]
65dirs=["phi","eta"]
66
67int2det = {1:"pixel", 0:"strip"}
68det2int = {v:k for k,v in int2det.items()}
69int2reg = {0:"barrel", 2:"endcap"}
70reg2int = {v:k for k,v in int2reg.items()}
71
72# Number of rows per module
73# diction levels: bec, layer, etamod
74striprows={ 'barrel' : {0:[None]+[4]*14,
75 1:[None]+[4]*14,
76 2:[None]+[4]*14,
77 3:[None]+[4]*14,
78 4:[None]+[2]*14,
79 5:[None]+[2]*14,
80 6:[None]+[2]*14,
81 7:[None]+[2]*14},
82 'endcap' : {i:[4,4,2,4,2,2] for i in range(12)}
83}
84
85# Number of chips per row
86# diction levels: bec, etamod, row
87abcchipsperrow={ 'barrel' : {i+1:[10,10,10,10] for i in range(14)}, # actually 2 rows for some but doesn't matter
88 'endcap' : {0:[8,8,9,9],
89 1:[10,10,11,11],
90 2:[12,12],
91 3:[14,14],
92 4:[8,8],
93 5:[9,9]} }
94
95stripsperabc=128
96stripsperrow=transformNodes(abcchipsperrow, lambda x: x * stripsperabc)
97
98rowbounds={}
99for reg in stripsperrow:
100 rowbounds[reg]={}
101 for mod in stripsperrow[reg]:
102 rowbounds[reg][mod]=[sum(stripsperrow[reg][mod][0:i+1]) for i in range(len(stripsperrow[reg][mod]))]
103
104
105#guess geom from input file name
106geom="Unknown"
107if "ITK-22" in args.inname:
108 geom="ITK-22"
109elif "ITK-23" in args.inname:
110 geom="ITK-23"
111
112# this is weird, number of layers in pixel endcaps?
113layers={ "pixel": { "barrel":5, "endcap": 8 if geom=="ITK-22" else 8 }, "strip" : { "barrel":8, "endcap":12}}
114
115
116#histograms
117hists={}
118
119#easy hist booking
120def getHist(name,makehist):
121 if name not in hists:
122 hists[name]=makehist(name)
123 return hists[name]
124
125
126#----------------------------------------------------------------------
127# Open file(s) for reading
128#----------------------------------------------------------------------
129# get list of files
130fileList=args.inname
131if len(args.inname)==1 and os.path.isdir(args.inname[0]):
132 fileList = glob.glob("%s/*.root" % args.inname)
133
134# make TChain
135Data = ROOT.TChain("ExtrapolationEngineTest")
136# add files to TChain
137for file in fileList:
138 msg.info("Adding file %s" %(file))
139 Data.AddFile(file)
140
141num_entries = min(args.evts,Data.GetEntries())
142msg.info("reading track input: %d entries\n" % (num_entries))
143t0 = time.clock()
144
145#----------------------------------------------------------------------
146# Parse keylayer description from input args
147#----------------------------------------------------------------------
148
149def parseKeyLayer(keystring):
150 key={}
151 key_det,key_reg,key_lyr = keystring.split(",")
152 key["lyr"]=int(key_lyr)
153 key["det"]=det2int[key_det]
154 key["reg"]=reg2int[key_reg]
155 return key
156
157key1 = parseKeyLayer(args.keylayer)
158key2 = None
159if args.keylayer2:
160 key2 = parseKeyLayer(args.keylayer2)
161
162#----------------------------------------------------------------------
163# Parse eta range description from input args
164#----------------------------------------------------------------------
165min_eta,max_eta = [float(s) for s in args.etarange.split(",")]
166
167
168#----------------------------------------------------------------------
169# Functions for geometry conversion
170#----------------------------------------------------------------------
171def getLayer(trk,hit_idx):
172 if trk.SensitiveIsPixel[hit_idx] == 0: #strip
173 layer = 2*trk.SensitiveLayerDisc[hit_idx]+trk.SensitiveSide[hit_idx]
174 else: #pixel
175 layer = trk.SensitiveLayerDisc[hit_idx]
176 return layer
177
178def getRow(trk,hit_idx): # returns localrow,globalrow
179
180 strip = trk.SensitivePhiIndex[hit_idx]
181 bec=int2reg[abs(trk.SensitiveBarrelEndcap[hit_idx])]
182 layer=getLayer(trk,hit_idx)
183 etamod=trk.SensitiveEtaModule[hit_idx]
184 localrow,globalrow=None,None
185 r=trk.SensitivePosR[hit_idx]
186 z=trk.SensitivePosZ[hit_idx]
187
188 # calculate row from strip
189 if trk.SensitiveIsPixel[hit_idx] == 0:
190
191 if "strip_number" not in hists:
192 hists["strip_number"]=ROOT.TH2D("strip_number_hist",";module;strip",500,0,500,800,0,8000)
193 hists["strip_number"].Fill(reg2int[bec]*100+layer*10+etamod,strip)
194
195 # this is a binned lookup to get the row number
196 localrow = bisect.bisect_left(rowbounds[bec][abs(etamod)],strip)
197
198 rows_in_module=striprows[bec][layer][abs(etamod)]
199
200 if localrow > rows_in_module:
201 msg.error("Error row(%d) greater than number of rows in module %d" %(localrow,rows_in_module))
202 globalrow=rows_in_module*etamod+localrow
203
204
205 if globalrow==6:
206 if "z_mod6" not in hists:
207 hists["z_mod6"]=ROOT.TH2D("z_mod6",";z;lyr",2500,0,500,10,0,10)
208 hists["z_mod6"].Fill(z,layer)
209
210 else:
211 localrow=trk.SensitiveEtaModule[hit_idx]
212 globalrow=localrow
213 getHist("pixel_rz_layer"+str(layer),
214 lambda n: ROOT.TH2D(n,";z[mm]; r[mm]",3000,0,+3000,1000,0,1000)).Fill(z,r)
215
216 return localrow,globalrow
217
218#--------------------------------------------------------------------------------
219# Find module of track in key layer
220#--------------------------------------------------------------------------------
221
222def isKeyLayer(trk,hit_idx,key):
223 if key["det"]!=trk.SensitiveIsPixel[hit_idx]:
224 return False
225 if key["reg"]!=abs(trk.SensitiveBarrelEndcap[hit_idx]):
226 return False
227 if getLayer(trk,hit_idx)!=key["lyr"]:
228 return False
229 return True
230
231
232def findKeyLayerMod(trk,key):
233 # return None for events with two hits in keylayer
234 mixedrows=False
235 row=None
236 for hit_idx in range(len(trk.SensitivePosX)):
237 if isKeyLayer(trk,hit_idx,key):
238 rownew= getRow(trk,hit_idx)[1]
239 if row and (rownew!=row):
240 mixedrows=True
241 row = rownew
242 return row if not mixedrows else None
243
244
245
246
247def trackToModules(trk):
248 modules = defaultdict(defaultdictlambda) # indexed on layer
249
250 for hit_idx in range(len(trk.SensitivePosX)):
251 det = trk.SensitiveIsPixel[hit_idx]
252 reg = abs(trk.SensitiveBarrelEndcap[hit_idx])
253 lyr = getLayer(trk,hit_idx)
254 row = getRow(trk,hit_idx)[1]
255 phimod = trk.SensitivePhiModule[hit_idx]
256 r=trk.SensitivePosR[hit_idx]
257 z=trk.SensitivePosZ[hit_idx]
258 if reg==reg2int['barrel']:
259 if lyr not in modules[det][reg] or r < modules[det][reg][lyr][3]:
260 modules[det][reg][lyr]=(row,phimod,hit_idx,r,z)
261 else:
262 if lyr not in modules[det][reg] or z < modules[det][reg][lyr][4]:
263 modules[det][reg][lyr]=(row,phimod,hit_idx,r,z)
264
265 for reg in modules[det2int['strip']]:
266 if reg==reg2int['barrel']:
267 varidx=3
268 else:
269 varidx=4
270
271 varlast=10000 # large value
272 lastlyr=10000 # large value
273 for lyr in sorted(modules[det][reg].keys(),reverse=True):
274 if varlast < modules[det][reg][lyr][varidx]:
275 del modules[det][reg][lyr]
276 elif lyr+1==lastlyr and lyr%2==0 and (varlast-modules[det][reg][lyr][varidx]) > 10.0:
277 del modules[det][reg][lyr+1] # remove outer hit
278 else:
279 lastlyr=lyr
280 varlast=modules[det][reg][lyr][varidx]
281
282
283 return modules
284
285
286#--------------------------------------------------------------------------------
287# Parse Geometry
288#--------------------------------------------------------------------------------
289
290
291def parseGeometry():
292 eta_vals_for_key_layer=set()
293 events=0
294 tracks_used=0
295 for trk in Data:
296 events = events + 1
297 if events>args.evts:
298 break
299
300 # only process tracks in region
301 if trk.StartEta > max_eta or trk.StartEta < min_eta:
302 continue
303
304 modules = trackToModules(trk)
305 if not key1["lyr"] in modules[key1["det"]][key1["reg"]]:
306 # no hit in layer
307 continue
308
309 eta_vals_for_key_layer.add(modules[key1["det"]][key1["reg"]][key1["lyr"]][0])
310
311 tracks_used+=1
312
313 msg.info("%d eta rows:",len(eta_vals_for_key_layer))
314 msg.info(sorted(eta_vals_for_key_layer))
315 msg.info("Tracks Used = %d", tracks_used)
316 return eta_vals_for_key_layer
317
318
319
320#--------------------------------------------------------------------------------
321# Define key layer in terms of modules
322#--------------------------------------------------------------------------------
323def divideKeyLayerModulesIntoSlices(eta_vals_for_key_layer):
324 key_modules_per_slice = float(len(eta_vals_for_key_layer))/nslices
325 key_modules_for_slices=[[]]
326
327 for i,row in enumerate(sorted(eta_vals_for_key_layer)):
328 if i >= len(key_modules_for_slices)*key_modules_per_slice:
329 key_modules_for_slices.append([])
330 key_modules_for_slices[-1].append(row)
331
332 msg.info("Modules in slices %d", key_modules_for_slices)
333
334
335
336 # make a map of modules to slices
337 return {m:i for i,s in enumerate(key_modules_for_slices) for m in s }
338
339
340
341#--------------------------------------------------------------------------------
342# Build List of Modules in Slices
343#--------------------------------------------------------------------------------
344
345def getModuleToSliceMap(mod_slice_map):
346 slice_modules=defaultdict(lambda :
347 { det:{
348 reg:{
349 lyr:{
350 d:defaultdict(lambda:0) for d in dirs}
351 for lyr in range(layers[det][reg]) }
352 for reg in regs }
353 for det in dets })
354
355 slice_hists={}
356 slice_tracks=defaultdict(lambda:0)
357 sliceid2int={}
358
359 events=0
360 tracks_used=0
361 missing_keylayer_hit=0
362 for trk in Data:
363 events = events + 1
364 if events>args.evts:
365 break
366
367 # only process tracks in region
368 if trk.StartEta > max_eta or trk.StartEta < min_eta:
369 continue
370
371 modules = trackToModules(trk)
372
373 if not key1["lyr"] in modules[key1["det"]][key1["reg"]]:
374 missing_keylayer_hit+=1
375 continue
376 mod1 = modules[key1["det"]][key1["reg"]][key1["lyr"]][0]
377 slicenum = mod_slice_map[mod1]
378 if args.test1slice and slicenum!=0:
379 continue
380
381 if key2:
382 if not key2["lyr"] in modules[key2["det"]][key2["reg"]]:
383 missing_keylayer_hit+=1
384 continue
385 mod2 = modules[key2["det"]][key2["reg"]][key2["lyr"]][0]
386 slicenum=(slicenum,mod2)
387
388
389
390 # add other modules to slice
391 for det in modules:
392 for reg in modules[det]:
393 for lyr in modules[det][reg]:
394 modidxs=modules[det][reg][lyr]
395 slice_modules[slicenum][int2det[det]][int2reg[reg]][lyr]["eta"][modidxs[0]]+=1
396 slice_modules[slicenum][int2det[det]][int2reg[reg]][lyr]["phi"][modidxs[1]]+=1
397
398 hit_idx = modidxs[2]
399
400 if slicenum not in slice_hists:
401 sliceid2int[slicenum]=len(slice_modules)-1
402 slice_hists[slicenum]=ROOT.TH2D("rz"+str(sliceid2int[slicenum]),"rz"+str(slicenum)+"; z[mm]; r[mm]",800,-200,+600,1000,0,1000)
403 slice_hists[slicenum].Fill(trk.SensitivePosZ[hit_idx],trk.SensitivePosR[hit_idx])
404
405 hname=int2det[det]+"_"+int2reg[reg]+"_"+str(lyr)+"_"+str(modidxs[0])
406 if hname not in slice_hists:
407 slice_hists[hname]=ROOT.TH1D(hname,hname+"; z[mm]",800,-200,+600)
408 slice_hists[hname].Fill(trk.SensitivePosZ[hit_idx])
409
410
411 tracks_used+=1
412 slice_tracks[slicenum]+=1
413
414 msg.info("Tracks Used=%d" %(tracks_used))
415 msg.info("%d tracks with no keylayer hit found or multiple hits in keylayer" %(int(str(missing_keylayer_hit))))
416
417 for hist in slice_hists.values():
418 hist.Write()
419
420 return slice_modules,sliceid2int,slice_tracks
421
422
423
424#--------------------------------------------------------------------------------
425# Trimming
426#--------------------------------------------------------------------------------
427
428def trimSlice(slice_modules,slice_tracks):
429
430 for sliceid in slice_modules:
431 for det in dets:
432 for reg in regs:
433 for lyr in slice_modules[sliceid][det][reg]:
434 for mod in list(slice_modules[sliceid][det][reg][lyr]["eta"]):
435 if slice_modules[sliceid][det][reg][lyr]["eta"][mod]/float(slice_tracks[sliceid]) < args.trim:
436 del slice_modules[sliceid][det][reg][lyr]["eta"][mod]
437
438
439#--------------------------------------------------------------------------------
440# Write RMap File
441#--------------------------------------------------------------------------------
442def writeRMap(slice_modules,sliceid2int):
443 nslices=len(sliceid2int)
444 rmap = open(args.outfilelabel+'_KeyLayer-%s%s%s_NSlices-%d.rmap' % (
445 args.keylayer.replace(",","_"),
446 "_KeyLayer2-"+args.keylayer2.replace(",","_") if args.keylayer2 else "",
447 ("_trim_%1.3f" % (args.trim,)).replace(".","_") if args.trim else "",
448 nslices), 'w')
449
450 rmap.write("towers "+str(nslices)+" phi 16\n\n")
451
452 int2sliceid={v:k for k,v in sliceid2int.items()}
453 for i in range(len(slice_modules)):
454 rmap.write("\n%d \n" % i)
455 sliceid=int2sliceid[i]
456
457 mindefault = lambda x,default=0: min(x) if len(x) else default
458 maxdefault = lambda x,default=0: max(x) if len(x) else default
459
460 for det in dets:
461 for reg in regs:
462 for lyr in range(layers[det][reg]):
463 rmap.write("%d %d %d %d %d %d %d %d %d\n" % (
464 1 if det=="pixel" else 0,
465 1 if reg=="endcap" else 0,
466 lyr,
467 mindefault(slice_modules[sliceid][det][reg][lyr]["phi"].keys(),default=0),
468 maxdefault(slice_modules[sliceid][det][reg][lyr]["phi"].keys(),default=0),
469 len(slice_modules[sliceid][det][reg][lyr]["phi"]),
470 mindefault(slice_modules[sliceid][det][reg][lyr]["eta"].keys(),default=0),
471 maxdefault(slice_modules[sliceid][det][reg][lyr]["eta"].keys(),default=0),
472 len(slice_modules[sliceid][det][reg][lyr]["eta"])))
473
474
475 rmap.close()
476
477#--------------------------------------------------------------------------------
478# Estimate duplication
479#--------------------------------------------------------------------------------
480def printOccupancies(slice_modules):
481
482 duplication_count={
483 det:{
484 reg:{
485 lyr:defaultdict(lambda: 0) for lyr in range(layers[det][reg]) }
486 for reg in regs }
487 for det in dets }
488
489 for sliceid in slice_modules:
490 for det in slice_modules[sliceid].keys():
491 for reg in slice_modules[sliceid][det].keys():
492 for lyr in slice_modules[sliceid][det][reg].keys():
493 for etamod in slice_modules[sliceid][det][reg][lyr]["eta"].keys():
494 duplication_count[det][reg][lyr][etamod]+=1
495
496
497 barrel_occupancies_4mrad_100mm={"pixel": [2.5,1.2,0.9,0.75,0.6],
498 "strip": [0.4,0.4,0.3,0.3,0.2,0.2,0.2,0.2]}
499 barrel_lengths={"pixel": [20,40,40,40,40],
500 "strip": [25,25,25,25,50,50,50,50]}
501 occupancies_per_module = {det:{reg: [] for reg in regs} for det in dets}
502 for det in dets:
503 for i in range(len(barrel_lengths[det])):
504 occupancies_per_module[det]['barrel'].append(barrel_occupancies_4mrad_100mm[det][i]*barrel_lengths[det][i]/float(100))
505
506 occupancies_per_module[det]['endcap']=[0 for i in range(layers[det][reg])]
507
508 layer_options = { "FPGATrackSimlike" : { "pixel" : [4], "strip":[0,2,3,4,5,6,7]},
509 "Outer5" : { "pixel" : [4], "strip":[0,2,4,6]},
510 "Inner5" : { "pixel" : [0,1,2,4,5], "strip":[]},
511 "Mid5" : { "pixel" : [2,4,5], "strip":[0,2]}}
512
513 layer_options_occ = defaultdict(lambda:1)
514
515 msg.info("%-5s %-6s %-5s %-12s %-10s %-10s" % ("","","","","min/max","min/max",))
516 msg.info("%-5s %-6s %-5s %-12s %-10s %-10s" % ("det","reg","lyr","duplication","modules","occupancy",))
517 for det in dets:
518 for reg in regs:
519 for lyr in range(layers[det][reg]):
520 dup=-1
521 if len(duplication_count[det][reg][lyr])!=0:
522 dup = sum(duplication_count[det][reg][lyr].values())/float(len(duplication_count[det][reg][lyr]))
523 occs = [occupancies_per_module[det][reg][lyr]*len(slice_modules[sliceid][det][reg][lyr]["eta"]) for sliceid in slice_modules]
524 lens = [len(slice_modules[sliceid][det][reg][lyr]["eta"]) for sliceid in slice_modules]
525
526 for opt,config in layer_options.items():
527 if lyr in config[det]:
528 layer_options_occ[opt]*=sum(occs)/float(len(occs))
529
530 msg.info("%5s %5s %-5d %2.2f [%2d,%2d] [%2.2f,%2.2f]" % (det,reg,lyr,dup,min(lens),max(lens),min(occs),max(occs)))
531
532 msg.info("\nOccupancies:\n")
533 for opt,occ in layer_options_occ.items():
534 msg.info(opt,occ)
535
536
537
538#--------------------------------------------------------------------------------
539# Plot Slices
540#--------------------------------------------------------------------------------
541def plotSlices(sliceid2int,slice_modules):
542
543 events=0
544 for trk in Data:
545 events = events + 1
546 if events>args.evts:
547 break
548
549 for hit_idx in range(len(trk.SensitivePosX)):
550 det = trk.SensitiveIsPixel[hit_idx]
551 reg = abs(trk.SensitiveBarrelEndcap[hit_idx])
552 lyr = getLayer(trk,hit_idx)
553 row = getRow(trk,hit_idx)[1]
554 r=trk.SensitivePosR[hit_idx]
555 z=trk.SensitivePosZ[hit_idx]
556
557 for sliceid,modules in slice_modules.items():
558 hist = getHist("slice_{}_rz".format(sliceid2int[sliceid]),
559 lambda n: ROOT.TH2D(n,"; z[mm]; r[mm]",3500,-500,+3000,1000,0,1000))
560
561 if row in modules[int2det[det]][int2reg[reg]][lyr]["eta"]:
562 hist.Fill(z,r)
563
564
565
566#--------------------------------------------------------------------------------
567# Main
568#--------------------------------------------------------------------------------
569
570histfile = ROOT.TFile("test.root",'recreate')
571
572eta_vals_for_key_layer=parseGeometry()
573
574nslices=args.nslices
575
576if args.fullgran:
577 nslices=len(eta_vals_for_key_layer)
578
579mod_slice_map = divideKeyLayerModulesIntoSlices(eta_vals_for_key_layer)
580
581slice_modules,sliceid2int,slice_tracks= getModuleToSliceMap(mod_slice_map)
582
583if key2:
584 msg.info("%d, two layers slices found"%(len(slice_modules)))
585 for x in slice_modules.keys():
586 msg.info(x)
587
588if args.trim: trimSlice(slice_modules,slice_tracks)
589
590writeRMap(slice_modules,sliceid2int)
591
592printOccupancies(slice_modules)
593
594plotSlices(sliceid2int,slice_modules)
595
596for hist in hists.values():
597 hist.Write()
598histfile.Close()
599
600
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
STL class.
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
Logging configuration for ATLAS job transforms.