Belle II Software  release-08-01-10
plotDeadPixelMasks.py
1 #!/usr/bin/env python3
2 
3 
10 
11 # Creates overview plots for deadpixel calibrations
12 #
13 # At first, you can extract the deadpixel calibration payloads from a localdb/centraldb using the tool
14 #
15 # b2conditionsdb-extract --exp 3 --runs 0-5614 --tag Calibration_Offline_Development --output dead_payloads.root PXDDeadPixelPar
16 #
17 # Secondly, execute the script as
18 #
19 # basf2 plotDeadPixelMasks.py
20 #
21 # basf2 plotDeadPixelMasks.py -- --maps
22 
23 
24 import basf2 as b2
25 import ROOT
26 from ROOT import Belle2
27 from array import array
28 
29 import argparse
30 parser = argparse.ArgumentParser(description="Plot dead pixel maps")
31 parser.add_argument('--maps', dest='maps', action="store_true", help='Create maps from payloads. This can be slow!')
32 args = parser.parse_args()
33 
34 
35 sensor_list = [
36  Belle2.VxdID("1.1.1"), Belle2.VxdID("1.1.2"),
37  Belle2.VxdID("1.2.1"), Belle2.VxdID("1.2.2"),
38  Belle2.VxdID("1.3.1"), Belle2.VxdID("1.3.2"),
39  Belle2.VxdID("1.4.1"), Belle2.VxdID("1.4.2"),
40  Belle2.VxdID("1.5.1"), Belle2.VxdID("1.5.2"),
41  Belle2.VxdID("1.6.1"), Belle2.VxdID("1.6.2"),
42  Belle2.VxdID("1.7.1"), Belle2.VxdID("1.7.2"),
43  Belle2.VxdID("1.8.1"), Belle2.VxdID("1.8.2"),
44  Belle2.VxdID("2.4.1"), Belle2.VxdID("2.4.2"),
45  Belle2.VxdID("2.5.1"), Belle2.VxdID("2.5.2")]
46 
47 # Create output file wíth histos and plots
48 histofile = ROOT.TFile('deadpixel_histos.root', 'RECREATE')
49 histofile.cd()
50 histofile.mkdir("maps")
51 
52 # Open file with extracted payloads
53 rfile = ROOT.TFile("dead_payloads.root", "READ")
54 b2.conditions = rfile.Get("conditions")
55 
56 deadpixel_table = dict()
57 for sensorID in sensor_list:
58  deadpixel_table[sensorID.getID()] = list()
59 run_list = list()
60 
61 for condition in b2.conditions:
62  if condition.PXDDeadPixelPar_valid:
63  print(f"Starting on run {condition.run}")
64  run_list.append(condition.run)
65 
66  for sensorID in sensor_list:
67 
68  nUCells = 250
69  nVCells = 768
70 
71  deadsensormap = condition.PXDDeadPixelPar.getDeadSensorMap()
72  deaddrainmap = condition.PXDDeadPixelPar.getDeadDrainMap()
73  deadrowmap = condition.PXDDeadPixelPar.getDeadRowMap()
74  deadsinglesmap = condition.PXDDeadPixelPar.getDeadSinglePixelMap()
75 
76  layer = sensorID.getLayerNumber()
77  ladder = sensorID.getLadderNumber()
78  sensor = sensorID.getSensorNumber()
79 
80  # Every dead drain counts for 192 dead pixels
81  counter = len(deaddrainmap[sensorID.getID()]) * 192
82 
83  # Every dead row counts for 250 dead pixels
84  # This can lead to double counting of dead pixel from dead drains
85  # The double counting can be avoided using --maps option.
86  counter += len(deadrowmap[sensorID.getID()]) * 250
87 
88  # Every dead row counts for 250 dead pixels
89  counter += len(deadsinglesmap[sensorID.getID()])
90 
91  if args.maps:
92  counter = 0
93 
94  name = f"DeadPixels_{layer:d}_{ladder:d}_{sensor:d}_run_{condition.run:d}"
95  title = f"Dead Pixels Sensor={layer:d}.{ladder:d}.{sensor:d} run={condition.run:d}"
96  dead_map = ROOT.TH2F(name, title, nUCells, 0, nUCells, nVCells, 0, nVCells)
97  dead_map.GetXaxis().SetTitle("uCell")
98  dead_map.GetYaxis().SetTitle("vCell")
99  dead_map.GetZaxis().SetTitle("isDead")
100  dead_map.SetStats(0)
101 
102  for uCell in range(nUCells):
103  for vCell in range(nVCells):
104  pixID = uCell * nVCells + vCell
105  isDeadSinglePixel = condition.PXDDeadPixelPar.isDeadSinglePixel(sensorID.getID(), pixID)
106  isDeadRow = condition.PXDDeadPixelPar.isDeadRow(sensorID.getID(), vCell)
107  isDeadDrain = condition.PXDDeadPixelPar.isDeadDrain(sensorID.getID(), uCell * 4 + vCell % 4)
108  isDead = isDeadSinglePixel or isDeadRow or isDeadDrain
109 
110  if isDead:
111  counter += 1.0
112  dead_map.SetBinContent(int(uCell + 1), int(vCell + 1), isDead)
113 
114  histofile.cd("maps")
115  dead_map.Write()
116 
117  deadfraction = counter / (nUCells * nVCells)
118  deadpixel_table[sensorID.getID()].append(deadfraction)
119 
120 
121 histofile.cd()
122 c = ROOT.TCanvas('dead_vs_runno', 'Deadpixel evolution vs. run number', 200, 10, 700, 500)
123 c.SetGrid()
124 
125 for sensorID in sensor_list:
126 
127  n = len(run_list)
128  x, y = array('d'), array('d')
129  for value in deadpixel_table[sensorID.getID()]:
130  y.append(value)
131  for run in run_list:
132  x.append(run)
133 
134  gr = ROOT.TGraph(n, x, y)
135  gr.SetLineColor(ROOT.kBlue)
136  gr.SetLineWidth(4)
137  gr.SetName(f"graph_{sensorID.getID()}")
138  gr.SetMarkerColor(ROOT.kBlue)
139  gr.SetMarkerStyle(21)
140  gr.SetTitle(f'Deadpixel evolution Sensor={sensorID}')
141  gr.GetXaxis().SetTitle('run number')
142  gr.GetYaxis().SetTitle('dead fraction')
143  gr.GetYaxis().SetRangeUser(0.0, 1.0)
144  gr.Draw('AP')
145 
146  c.Update()
147  c.Modified()
148  c.Print(f'deadpixels_vs_runno_{sensorID.getID()}.png')
149  c.Write()
150 
151 
152 rfile.Close()
153 histofile.Close()
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33