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