Belle II Software development
monitor_module.py
1# !/usr/bin/env python3
2
3
10
11import os
12import basf2 as b2
13from ROOT import Belle2, TCanvas, TColor, TH1F, TH2F, gStyle
14import numpy
15from math import pi
16
17
18# make the monitoring plots
19file_type = 'png'
20
21color1501 = TColor(1501, 35 / 255., 55 / 255., 59 / 255.)
22color1502 = TColor(1502, 99 / 255., 120 / 255., 173 / 255.)
23color1503 = TColor(1503, 235 / 255., 129 / 255., 27 / 255.)
24color1504 = TColor(1504, 99 / 255., 173 / 255., 132 / 255.)
25color1505 = TColor(1505, 123 / 255., 111 / 255., 37 / 255.)
26
27nWiresInLayer = [160, 192, 256, 320, 384]
28
29
30def set_style(hist, color=1503, marker=20):
31 hist.SetLineColor(color)
32 hist.SetLineWidth(2)
33 hist.SetFillStyle(0)
34 hist.SetMarkerStyle(marker)
35 hist.SetMarkerSize(2)
36 hist.SetMarkerColor(color)
37
38
39hall = TH2F('all', 'all', 5, 0, 5, 384, 0, 384)
40hhit = TH2F('hit', 'hit', 5, 0, 5, 384, 0, 384)
41hno_ghost = TH2F('ng', 'hit', 5, 0, 5, 384, 0, 384)
42hghost = TH2F('ghost', 'hit', 5, 0, 5, 384, 0, 384)
43
44hlr = TH1F('lr', 'left right', 4, 0, 4)
45hpri = TH1F('pri', 'priority position', 4, 0, 4)
46hpritime = TH1F('pritime', 'priority time', 512, 0, 512)
47hftime = TH1F('found time', 'found time', 48, -35, 13)
48
49used = numpy.zeros(2336, numpy.int32)
50in_tsim = numpy.zeros(2336, numpy.int32)
51
52
53class Monitor(b2.Module):
54 """
55 Module to make some monitor plots for TSF
56 """
57
58 def initialize(self):
59 """
60 Initilization
61 """
62
63 self.event_info = Belle2.PyStoreObj('EventMetaData')
64
65 self.tshits = Belle2.PyStoreArray('CDCTriggerSegmentHits')
66
67 self.simhits = Belle2.PyStoreArray('TSimSegmentHits')
68
69 self.first_run = self.event_info.getRun()
70
71 self.nevents = 0
72
73 def event(self):
74 """
75 event function
76 """
77 self.nevents += 1
78 used.fill(0)
79 in_tsim.fill(0)
80 for simhit in self.simhits:
81 if simhit.getISuperLayer() % 2 == 0:
82 iax, iw = simhit.getISuperLayer() // 2, simhit.getIWire()
83 if simhit.getPriorityPosition() == 1:
84 iw += 1
85 if iw == nWiresInLayer[iax]:
86 iw = 0
87 hall.Fill(iax, iw)
88 in_tsim[simhit.getSegmentID()] = 1
89 for hit in self.tshits:
90 ind = hit.getSegmentID()
91 # only fill the histogram if the same ID is not found in the event
92 # In other words, it can't be the same hit from another 2D
93 # even if the unpacker does not eliminate repeated hits.
94 iax, iw = hit.getISuperLayer() // 2, hit.getIWire()
95 if hit.getPriorityPosition() == 1:
96 iw += 1
97 if iw == nWiresInLayer[iax]:
98 iw = 0
99 if not used[ind]:
100 used[ind] = 1
101 hhit.Fill(iax, iw)
102 if in_tsim[ind]:
103 hno_ghost.Fill(iax, iw)
104 if not in_tsim[ind]:
105 hghost.Fill(iax, iw)
106 hlr.Fill(hit.getLeftRight())
107 hpri.Fill(hit.getPriorityPosition())
108 hpritime.Fill(hit.priorityTime())
109 hftime.Fill(hit.foundTime())
110
111 def terminate(self):
112 """
113 termination
114 """
115 if self.nevents == 0:
116 b2.B2WARNING("The monitor module is never called.\n" +
117 "There seems to be no CDC Trigger data at all!")
118 return
119 elif hhit.GetEntries() == 0:
120 b2.B2WARNING("No recorded TS hits at all!")
121 return
122 elif hall.GetEntries() == 0:
123 b2.B2ERROR("No simulated TS hits at all!")
124 return
125 if not os.path.exists('monitor_plots'):
126 os.mkdir('monitor_plots')
127 can = TCanvas('can2', 'can2', 800, 700)
128 gStyle.SetOptStat(0)
129
130 nts = [160, 192, 256, 320, 384]
131
132 slall = [[]] * 5
133 slhit = [[]] * 5
134 slghost = [[]] * 5
135 quos = [[]] * 5
136 slng = [[]] * 5
137 quong = [[]] * 5
138
139 # 1 bin corresponds to 8 TS (2 bins for a merger unit)
140 width = 8
141 for iax in range(5):
142 ibin = iax + 1
143 p = hall.ProjectionY(f'all{iax}', ibin, ibin)
144 p.SetBins(nts[iax], 0, 2 * pi)
145 p.Rebin(width)
146 slall[iax] = p
147
148 q = hhit.ProjectionY(f'hit{iax}', ibin, ibin)
149 q.SetBins(nts[iax], 0, 2 * pi)
150 q.Rebin(width)
151 slhit[iax] = q
152
153 g = hghost.ProjectionY(f'ghost{iax}', ibin, ibin)
154 g.SetBins(nts[iax], 0, 2 * pi)
155 g.Rebin(width)
156 slghost[iax] = g
157
158 s = hno_ghost.ProjectionY(f'ng{iax}', ibin, ibin)
159 s.SetBins(nts[iax], 0, 2 * pi)
160 s.Rebin(width)
161 slng[iax] = s
162
163 r = g.Clone(f'ghost{iax}')
164 r2 = s.Clone(f'quong{iax}')
165 g.Sumw2()
166 p.Sumw2()
167 s.Sumw2()
168 # get the ratio of (found hit / simulated hit) with binomial error
169 r.Divide(g, p, 1.0, 1.0, 'B')
170 quos[iax] = r
171 r2.Divide(s, p, 1.0, 1.0, 'B')
172 quong[iax] = r2
173
174 for hits, name in [(slhit, 'data TS'),
175 (slall, 'TSIM')]:
176 for i in range(5):
177 h = hits[i]
178 h.SetTitle(f'SL{i * 2}')
179 set_style(h, 1501 + i, 20 + i)
180 if name in ['data TS', 'TSIM']:
181 try:
182 h.Scale(1 / h.Integral('width'))
183 except ZeroDivisionError:
184 b2.B2WARNING(f'Not a single hit in SL{i * 2}!')
185 continue
186 height = max([g.GetMaximum() for g in hits])
187 for h in hits:
188 h.SetMaximum(1.1 * height)
189 h.SetMinimum(0)
190 options = 'L M E0'
191 if h.GetTitle() != 'SL0':
192 options += ' same'
193 h.Draw(options)
194 can.BuildLegend(.85, .76, .95, .95)
195 hits[0].SetTitle(name + f' hit distribution in run {self.first_run}; #phi (rad)')
196 can.SaveAs('monitor_plots/' + name.split()[0] + f'_ts_hits_{self.first_run:05d}.{file_type}')
197
198 for ratio, name in [(quos, 'ghost rate'), (quong, 'efficiency (w.r.t. fast TSIM)')]:
199 upp = max([g.GetMaximum() for g in ratio])
200 low = min([g.GetMinimum() for g in ratio])
201 for i in range(5):
202 h = ratio[i]
203 h.SetTitle(f'SL{2 * i}')
204 h.SetMaximum(1.1 * upp)
205 h.SetMinimum(0.9 * low)
206 set_style(h, 1501 + i, 20 + i)
207 options = 'e0'
208 if i != 0:
209 options += ' same'
210 h.Draw(options)
211 can.BuildLegend(.91, .76, .98, .95)
212 ratio[0].SetTitle('TSF ' + name + f' in run {self.first_run};#phi (rad)')
213 file_name = name.split()[0]
214 can.SaveAs(f'monitor_plots/ts_{file_name}_{self.first_run:05d}.{file_type}')
215
216 # ghost distribution
217 for h in [hlr, hpri, hpritime, hftime]:
218 set_style(h, 1503)
219 h.Draw()
220 name = h.GetTitle().replace(' ', '_')
221 can.SaveAs(f'monitor_plots/ghost_{name}_{self.first_run:05d}.{file_type}')
A (simplified) python wrapper for StoreArray.
Definition: PyStoreArray.h:72
a (simplified) python wrapper for StoreObjPtr.
Definition: PyStoreObj.h:67
nevents
Number of events.