Belle II Software development
TOPFE_qualityPlots.py
1#!/usr/bin/env python
2
3
10
11import basf2 as b2
12from ROOT import Belle2, gROOT
13from ROOT import TNtuple, TFile, TH1F, TCanvas, TGraph, gStyle
14import numpy as np
15import argparse
16parser = argparse.ArgumentParser(description='Extracts information about the FE parameters',
17 usage='%(prog)s [options]')
18parser.add_argument('filename', help='name of data file')
19parser.add_argument(
20 '--plotWaveforms',
21 action='store_true',
22 help='whether to print out suspicious waveforms'
23)
24parser.add_argument(
25 '--output',
26 help='name of the ntuple file',
27 default="TOPFE.root"
28)
29
30args = parser.parse_args()
31
32b2.set_log_level(b2.LogLevel.INFO)
33gROOT.SetBatch()
34
35
36def wf_display(waveform, run, event, suffix=""):
37
38 # Some of the following code was taken from top/tools/showFEWaveforms.py
39 # TODO: Think about re-using this code in the two scripts
40 '''
41 Simple event display of waveforms with feature extraction points
42 '''
43
44 hist = TH1F('h', 'wf', 64 * 4, 0.0, 64.0 * 4)
45
46 c1 = TCanvas('c1', 'WF event display', 800, 800)
47
48 # plot aesthetics
49 hist.SetXTitle("sample number")
50 hist.SetYTitle("sample value [ADC counts]")
51 hist.SetLabelSize(0.06, "XY") # readable labels
52 hist.SetTitleSize(0.07, "XY") # readable axis titles
53 gStyle.SetTitleSize(0.07, "t") # readable plot title
54 c1.SetLeftMargin(0.2) #
55 c1.SetBottomMargin(0.16) # move margins to make space for axis titles
56 c1.SetRightMargin(0.04) #
57 hist.SetTitleOffset(1.3, "Y") # readable axis offset
58 hist.SetTitleOffset(1.0, "X") # readable axis offset
59
60
61 graph = TGraph(10)
62
63 fname = 'waveforms_run' + str(run) + '_event' + str(event) + '_chan'
64 pdfFile = fname
65 chan = waveform.getChannel()
66 asic = waveform.getASICNumber()
67 carr = waveform.getCarrierNumber()
68 bstk = (chan // 8 // 4 // 4) % 4
69 pdfFile = pdfFile + '-' + str(chan)
70 # nHits = 0
71 wf = waveform.getWaveform()
72 hist.Reset()
73 numSamples = waveform.getSize()
74 hist.SetBins(numSamples, 0.0, float(numSamples))
75 title = 'channel: ' + str(chan % 8) + ' asic: ' + str(asic) \
76 + ' carrier: ' + str(carr) + ' BS: ' + str(bstk) + ' win:'
77 for window in waveform.getStorageWindows():
78 title += ' ' + str(window)
79 hist.SetTitle(title)
80 hist.SetStats(False)
81 hist.SetLineColor(4)
82 if not waveform.areWindowsInOrder():
83 hist.SetLineColor(3)
84 i = 0
85 for sample in wf:
86 i = i + 1
87 hist.SetBinContent(i, sample)
88
89 rawDigits = waveform.getRelationsWith("TOPRawDigits")
90 i = 0
91 for raw in rawDigits:
92 graph.SetPoint(i, raw.getSampleRise() + 0.5, raw.getValueRise0())
93 i += 1
94 graph.SetPoint(i, raw.getSampleRise() + 1.5, raw.getValueRise1())
95 i += 1
96 graph.SetPoint(i, raw.getSamplePeak() + 0.5, raw.getValuePeak())
97 i += 1
98 graph.SetPoint(i, raw.getSampleFall() + 0.5, raw.getValueFall0())
99 i += 1
100 graph.SetPoint(i, raw.getSampleFall() + 1.5, raw.getValueFall1())
101 i += 1
102 if raw.isFEValid(): # works properly only for single rawDigit!
103 graph.SetMarkerColor(2)
104 if raw.isPedestalJump():
105 graph.SetMarkerColor(3)
106 else:
107 graph.SetMarkerColor(4)
108 graph.Set(i)
109 c1.Clear()
110 title = 'WF event display:' + ' run ' + str(run) + ' event ' \
111 + str(event)
112 c1.SetTitle(title)
113 hist.Draw()
114 graph.SetMarkerStyle(24)
115 graph.Draw("sameP")
116 c1.Update()
117 c1.SaveAs(pdfFile + suffix + '.pdf')
118
119
120class WaveformAnalyzer(b2.Module):
121 '''
122 Analyzes waveform and FE data
123 '''
124
125 def initialize(self):
126 ''' Initialize the Module: open the canvas. '''
127
128
129 self.feProps = TNtuple(
130 "feProps",
131 "feProps",
132 "event:run"
133 ":fePeak1Ht:fePeak1TDC:fePeak1Wd"
134 ":fePeakHt:fePeakTDC:fePeakWd:fePeakIntegral"
135 ":nTOPRawDigits:ch:nNarrowPeaks:nInFirstWindow:nHeight150:nOscillations")
136
137
138 self.nWaveForms = 0
139
140
142
143
144 self.f = TFile.Open(args.output, "RECREATE")
145
146
147 self.plotCounter = 0
148
149 def event(self):
150 '''
151 Event processor: get data and print to screen
152 '''
153 evtMetaData = Belle2.PyStoreObj('EventMetaData')
154 event = evtMetaData.obj().getEvent()
155 run = evtMetaData.obj().getRun()
156 waveforms = Belle2.PyStoreArray('TOPRawWaveforms')
157 for waveform in waveforms:
158 chan = waveform.getChannel()
159 self.nWaveForms += 1
160 # declare some counters for our ntuple
161 nInFirstWindow, nNarrowPeaks, nHeight150, nOscillations = 0, 0, 0, 0
162
163 # waveform.areWindowsInOrder is a bit too strict at the moment
164 wins = np.array(waveform.getStorageWindows())
165 if not np.all(wins[:-1] <= wins[1:]): # change false for pics
166 self.nWaveFormsOutOfOrder += 1
167 if False and args.plotWaveforms:
168 wf_display(waveform, run, event, "windowOrder")
169 self.plotCounter += 1
170
171 wf = np.array(waveform.getWaveform())
172 if False and args.plotWaveforms:
173 wf_display(waveform, run, event, "general")
174 self.plotCounter += 1
175
176 # If TOPWaveformFeatureExtractor has been run then there are extra
177 # TOPRawDigits related to this waveform
178 rawDigits = waveform.getRelationsWith("TOPRawDigits")
179 nTOPRawDigits = len(rawDigits)
180
181 if False and args.plotWaveforms and nTOPRawDigits > 2:
182 # There are at least 3 Top raw digits
183 wf_display(waveform, run, event, "manyPeaks")
184 self.plotCounter += 1
185 if False and args.plotWaveforms and nTOPRawDigits > 3:
186 # There are at least 4 TOPRawDigits
187 wf_display(waveform, run, event, "tooManyPeaks")
188 self.plotCounter += 1
189 raw = rawDigits[0]
190 fePeakHt = raw.getValuePeak()
191 fePeakTDC = raw.getSamplePeak()
192 fePeakWd = raw.getSampleFall() - raw.getSampleRise()
193 fePeakIntegral = raw.getIntegral()
194 # we are sorting the peaks. The FE should always point to the highest one
195
196 # the channel we get from the waveform encodes the asic, carrier, and the actual channel
197 if 0 < fePeakTDC < 65 and chan % 8 == 0:
198 # To see if cal pulse is in first window
199 nInFirstWindow += 1
200 if False and args.plotWaveforms:
201 wf_display(waveform, run, event, "calPuls_firstWin")
202 self.plotCounter += 1
203
204 # there are strange bumps in the ADC distribtion of the cal channels
205 if (140 < fePeakHt < 220) and chan % 8 == 0:
206 if False and args.plotWaveforms:
207 wf_display(waveform, run, event, "strangeADCBump_1")
208 self.plotCounter += 1
209 if (300 < fePeakHt < 410) and chan % 8 == 0:
210 if False and args.plotWaveforms:
211 wf_display(waveform, run, event, "strangeADCBump_2")
212 self.plotCounter += 1
213
214 fePeak1Ht = -1
215 fePeak1TDC = -1
216 fePeak1Wd = -1
217 # fePeak1Integral = -1
218 if nTOPRawDigits > 1:
219 # if there is a second TOPRawDigit then get it for our ntuple
220 fePeak1Ht = rawDigits[1].getValuePeak()
221 fePeak1TDC = rawDigits[1].getSamplePeak()
222 fePeak1Wd = rawDigits[1].getSampleFall() - rawDigits[1].getSampleRise()
223 # fePeak1Integral = rawDigits[1].getIntegral()
224
225 if nTOPRawDigits > 1 and fePeak1TDC < 64:
226 # counting the times that the second digit is found in the first window
227 if False and args.plotWaveforms:
228 wf_display(waveform, run, event, "secondPeakInFirstWindow")
229 self.plotCounter += 1
230
231 if fePeakWd < 5 or nTOPRawDigits > 1 and fePeak1Wd < 5:
232 # counting thin peaks
233 nNarrowPeaks += 1
234 if False and args.plotWaveforms:
235 wf_display(waveform, run, event, "thinpeak")
236 self.plotCounter += 1
237
238 if 145 < fePeak1Ht < 155 and chan % 8 == 0:
239 # Jan needs to write a comment about why we're doing this test
240 nHeight150 += 1
241 if False and args.plotWaveforms:
242 wf_display(waveform, run, event, "peak1Ht_is_150")
243 self.plotCounter += 1
244
245 if nTOPRawDigits > 5 and (fePeakHt - fePeak1Ht) < 5:
246 if np.mean(wf) < 10:
247 # want to count the portion of times we see this oscillation behavior
248 # guard the call to numpy.mean by the previous if statements
249 nOscillations += 1
250 if False and args.plotWaveforms:
251 wf_display(waveform, run, event, "oscillations")
252 self.plotCounter += 1
253
254 self.feProps.Fill(
255 event,
256 run,
257 fePeak1Ht,
258 fePeak1TDC,
259 fePeak1Wd,
260 fePeakHt,
261 fePeakTDC,
262 fePeakWd,
263 fePeakIntegral,
264 nTOPRawDigits,
265 chan,
266 nNarrowPeaks,
267 nInFirstWindow,
268 nHeight150,
269 nOscillations,
270 )
271
272 # only plot the first 10 figures.
273 if args.plotWaveforms and self.plotCounter >= 10:
274 evtMetaData.obj().setEndOfData()
275
276 def terminate(self):
277 '''End of run'''
278 self.f.WriteTObject(self.feProps)
279 self.f.Close()
280 print("# Waveforms:", self.nWaveForms)
281 print("out of order:", self.nWaveFormsOutOfOrder)
282
283
284# Set the log level to show only error and fatal messages
285# b2.set_log_level(b2.LogLevel.ERROR)
286
287# Database
288b2.conditions.override_globaltags()
289b2.conditions.append_globaltag('online')
290
291# Create path
292main = b2.create_path()
293# reader = b2.register_module('SeqRootInput') # sroot file
294reader = b2.register_module('RootInput') # root file
295# file to read
296reader.param('inputFileName', args.filename)
297main.add_module(reader)
298
299# conversion from RawCOPPER or RawDataBlock to RawTOP
300converter = b2.register_module('Convert2RawDet')
301main.add_module(converter)
302
303# Initialize TOP geometry parameters (creation of Geant geometry is not needed)
304main.add_module('TOPGeometryParInitializer')
305
306# Unpacking (format auto detection works now)
307unpack = b2.register_module('TOPUnpacker')
308main.add_module(unpack)
309
310
311topfe = b2.register_module('TOPWaveformFeatureExtractor')
312# topfe.param('threshold', 20)
313main.add_module(topfe)
314
315
316drdh = b2.register_module(WaveformAnalyzer())
317main.add_module(drdh)
318
319# Process all events
320b2.process(main)
A (simplified) python wrapper for StoreArray.
Definition: PyStoreArray.h:72
a (simplified) python wrapper for StoreObjPtr.
Definition: PyStoreObj.h:67
plotCounter
counts how many plots were created.
nWaveForms
number of waveforms processed
nWaveFormsOutOfOrder
number of waveforms out of order