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