Belle II Software  release-05-01-25
EventInspectorLookback.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 # Purpose:
5 # basf module to histogram useful values in RawKLM and BKLMHit2d data-objects in an SROOT file.
6 #
7 
8 import basf2
9 import bklmDB
10 import math
11 import array
12 import ctypes
13 import ROOT
14 from ROOT import Belle2, TH1F, TH2F, TCanvas, THistPainter, TPad
15 
16 
17 class EventInspectorLookback(basf2.Module):
18  """Analyze RPC lookback-window parameter settings, fill histograms"""
19 
20 
21  BKLM_ID = 0x07000000
22 
23  EKLM_ID = 0x08000000
24 
25  BKLM_STRIP_BIT = 0
26 
27  BKLM_PLANE_BIT = 6
28 
29  BKLM_LAYER_BIT = 7
30 
31  BKLM_SECTOR_BIT = 11
32 
33  BKLM_SECTION_BIT = 14
34 
35  BKLM_MAXSTRIP_BIT = 15
36 
37  BKLM_STRIP_MASK = 0x3f
38 
39  BKLM_PLANE_MASK = (1 << BKLM_PLANE_BIT)
40 
41  BKLM_LAYER_MASK = (15 << BKLM_LAYER_BIT)
42 
43  BKLM_SECTOR_MASK = (7 << BKLM_SECTOR_BIT)
44 
45  BKLM_SECTION_MASK = (1 << BKLM_SECTION_BIT)
46 
47  BKLM_MAXSTRIP_MASK = (63 << BKLM_MAXSTRIP_BIT)
48 
49  BKLM_MODULEID_MASK = (BKLM_SECTION_MASK | BKLM_SECTOR_MASK | BKLM_LAYER_MASK)
50 
51  def __init__(self, exp, run, histName, pdfName, mode, window):
52  """Constructor
53 
54  Arguments:
55  exp (str): formatted experiment number
56  run (str): formatter run number
57  histName (str): path name of the output histogram ROOT file
58  pdfName (str): path name of the output histogram PDF file
59  mode (int): specifies the lookback-window mode
60  0: coarse window start values
61  1: coarse window width values
62  2: fine window start values
63  3: fine window width values
64  window (int, int, int): specifies the lookback-window min, max and step values
65  """
66  super().__init__()
67 
68  self.exp = exp
69 
70  self.run = run
71 
72  self.histName = histName
73 
74  self.pdfName = pdfName
75 
76  windowModes = {0: "coarse start", 1: "coarse width", 2: "fine start", 3: "fine width"}
77 
78  self.windowMode = windowModes[mode]
79 
80  self.windowMinValue = window[0]
81 
82  self.windowMaxValue = window[1]
83 
84  self.windowStepValue = window[2]
85  print("Mode = {0} start = {1} end = {2} step = {3}".format(mode, window[0], window[1], window[2]))
86 
87  def initialize(self):
88  """Handle job initialization: fill the mapping database, create histograms"""
89 
90  expRun = 'e{0:02d}r{1}: '.format(int(self.exp), int(self.run))
91 
92 
94 
95  self.sectorFBToDC = [11, 15, 2, 6, 10, 14, 3, 7, 9, 13, 0, 4, 8, 12, 1, 5]
96 
97  self.dcToSectorFB = [10, 14, 2, 6, 11, 15, 3, 7, 12, 8, 4, 0, 13, 9, 5, 1]
98 
99  self.histogramFile = ROOT.TFile.Open(self.histName, "RECREATE")
100  # All histograms/scatterplots in the output file will show '# of events' only
101  ROOT.gStyle.SetOptStat(10)
102 
103  # create the rawKLM histograms
104 
105 
106  self.hist_mappedRPCTimeCal = ROOT.TH1F(
107  'mappedRPCTimeCal', expRun + 'RPC time distribution;t - t(trigger) (ns)', 256, -0.5, 1023.5)
108 
110 
111  self.dict_nRawKLMs = {}
112  for window in range(self.windowMinValue, self.windowMaxValue+1, self.windowStepValue):
113  label = "mappedRPCTimeCalByWindow{0:04x}".format(window)
114  title = "{0}RPC time distribution for lookback-window {1} = {2:04x}".format(
115  expRun, self.windowMode, window) + ";t - t(trigger) (ns)"
116  self.dict_mappedRPCTimeCalByWindow[window] = ROOT.TH1F(label, title, 256, -0.5, 1023.5)
117  self.dict_nRawKLMs[window] = 0
118 
120 
121  # Create the BKLMHit2d-related histograms
122 
123 
124  self.hist_occupancyForwardXY = ROOT.TH2F('occupancyForwardXY',
125  expRun + 'Forward xy occupancy;x(cm);y(cm)',
126  230, -345.0, 345.0, 230, -345.0, 345.0)
127 
128  self.hist_occupancyBackwardXY = ROOT.TH2F('occupancyBackwardXY',
129  expRun + 'Backward xy occupancy;x(cm);y(cm)',
130  230, -345.0, 345.0, 230, -345.0, 345.0)
131 
133 
134 
136 
137  self.dict_nHit2ds = {}
138  for window in range(self.windowMinValue, self.windowMaxValue+1, self.windowStepValue):
139  label = "occupancyXYByWindow{0:04x}".format(window)
140  title = "{0}Forward xy occupancy for lookback-window {1} = {2:04x};x(cm);y(cm)".format(expRun, self.windowMode, window)
141  self.dict_occupancyXYByWindow[window] = ROOT.TH2F(label, title, 230, -345.0, 345.0, 230, -345.0, 345.0)
142  self.dict_nHit2ds[window] = 0
143 
144 
145  self.dict_nEvents = {}
146  for window in range(self.windowMinValue, self.windowMaxValue+1, self.windowStepValue):
147  self.dict_nEvents[window] = 0
148 
149 
150  self.windowValue = -1
151 
152  def terminate(self):
153  """Handle job termination: draw histograms, close output files"""
154 
155  canvas = ROOT.TCanvas("canvas", self.pdfName, 1600, 1600)
156  title = '{0}['.format(self.pdfName)
157  canvas.SaveAs(title)
158  canvas.Clear()
159  canvas.Divide(1, 1)
160  canvas.GetPad(0).SetGrid(1, 1)
161  canvas.GetPad(0).Update()
162  nWindows = int((self.windowMaxValue - self.windowMinValue) / self.windowStepValue) + 1
163  hist_nEvents = ROOT.TH1F('nEvents',
164  'Number of events;Lookback-window {0} value'.format(self.windowMode),
165  nWindows, self.windowMinValue, self.windowMaxValue+self.windowStepValue)
166  hist_nEvents.SetStats(False)
167  hist_nEvents.SetMinimum(0)
168  values = array.array('d', [0]) # dummy vaue for the histogram's underflow bin
169  for key in self.dict_nEvents:
170  values.append(self.dict_nEvents[key])
171  values.append(0) # dummy value for the histogram's overflow bin
172  hist_nEvents.SetContent(values)
173  hist_nEvents.Draw("HIST")
174  canvas.Print(self.pdfName, "Title:{0}".format(hist_nEvents.GetName()))
175  hist_nRawKLMs = ROOT.TH1F('nRawKLMs',
176  'Mean number of RawKLM hits per event;Lookback-window {0} value'.format(self.windowMode),
177  nWindows, self.windowMinValue, self.windowMaxValue+self.windowStepValue)
178  hist_nRawKLMs.SetStats(False)
179  hist_nRawKLMs.SetMinimum(0)
180  ratios = array.array('d', [0]) # dummy ratio for the histogram's underflow bin
181  errors = array.array('d', [0]) # dummy error for the histogram's underflow bin
182  for key in self.dict_nRawKLMs:
183  numerator = self.dict_nRawKLMs[key]
184  denominator = float(self.dict_nEvents[key])
185  if denominator > 0:
186  ratio = numerator / denominator
187  ratios.append(ratio)
188  errors.append(math.sqrt(ratio * (ratio + 1.0) / denominator)) # avoid 1/numerator
189  else:
190  ratios.append(0)
191  errors.append(0)
192  ratios.append(0) # dummy ratio for the histogram's overflow bin
193  errors.append(0) # dummy error for the histogram's overflow bin
194  hist_nRawKLMs.SetContent(ratios)
195  hist_nRawKLMs.SetError(errors)
196  hist_nRawKLMs.Draw("E0 X0 L")
197  hist_nRawKLMs.Draw("HIST SAME")
198  canvas.Print(self.pdfName, "Title:{0}".format(hist_nRawKLMs.GetName()))
199  hist_nHit2ds = ROOT.TH1F('nBKLMHit2ds',
200  'Mean number of BKLMHit2ds per event;Lookback-window {0} value'.format(self.windowMode),
201  nWindows, self.windowMinValue, self.windowMaxValue+self.windowStepValue)
202  hist_nHit2ds.SetStats(False)
203  hist_nHit2ds.SetMinimum(0)
204  ratios = array.array('d', [0]) # dummy ratio for the histogram's underflow bin
205  errors = array.array('d', [0]) # dummy error for the histogram's underflow bin
206  for key in self.dict_nHit2ds:
207  numerator = self.dict_nHit2ds[key]
208  denominator = float(self.dict_nEvents[key])
209  if denominator > 0:
210  ratio = numerator / denominator
211  ratios.append(ratio)
212  errors.append(math.sqrt(ratio * (ratio + 1.0) / denominator)) # avoid 1/numerator
213  else:
214  ratios.append(0)
215  errors.append(0)
216  ratios.append(0) # dummy ratio for the histogram's overflow bin
217  errors.append(0) # dummy error for the histogram's overflow bin
218  hist_nHit2ds.SetContent(ratios)
219  hist_nHit2ds.SetError(errors)
220  hist_nHit2ds.Draw("E0 X0 L")
221  hist_nHit2ds.Draw("HIST SAME")
222  canvas.Print(self.pdfName, "Title:{0}".format(hist_nHit2ds.GetName()))
223 
224  self.hist_mappedRPCTimeCal.Draw()
225  canvas.Print(self.pdfName, "Title:{0}".format(self.hist_mappedRPCTimeCal.GetName()))
226  for key in self.dict_mappedRPCTimeCalByWindow:
227  theHist = self.dict_mappedRPCTimeCalByWindow[key]
228  theHist.Draw()
229  canvas.Print(self.pdfName, "Title:{0}".format(theHist.GetName()))
230 
231  self.hist_occupancyBackwardXY.Draw("colz")
232  canvas.Print(self.pdfName, "Title:{0}".format(self.hist_occupancyBackwardXY.GetName()))
233  self.hist_occupancyForwardXY.Draw("colz")
234  canvas.Print(self.pdfName, "Title:{0}".format(self.hist_occupancyForwardXY.GetName()))
235  for key in self.dict_occupancyXYByWindow:
236  theHist = self.dict_occupancyXYByWindow[key]
237  theHist.Draw("colz")
238  lastTitle = "Title:{0}".format(theHist.GetName())
239  canvas.Print(self.pdfName, lastTitle)
240  pdfNameLast = '{0}]'.format(self.pdfName)
241  canvas.Print(pdfNameLast, lastTitle)
242  self.histogramFile.Write()
243  self.histogramFile.Close()
244  print('Goodbye')
245 
246  def beginRun(self):
247  """Handle begin of run: print diagnostic message"""
248  EventMetaData = Belle2.PyStoreObj('EventMetaData')
249  print('beginRun', EventMetaData.getRun())
250 
251  def endRun(self):
252  """Handle end of run: print diagnostic message"""
253  EventMetaData = Belle2.PyStoreObj('EventMetaData')
254  print('endRun', EventMetaData.getRun())
255 
256  def event(self):
257  """Process one event: fill histograms"""
258 
259  EventMetaData = Belle2.PyStoreObj('EventMetaData')
260  event = EventMetaData.getEvent()
261  rawklms = Belle2.PyStoreArray('RawKLMs')
262  hit2ds = Belle2.PyStoreArray('BKLMHit2ds')
263 
264  # Process the RawKLMs
265 
266  for copper in range(0, len(rawklms)):
267  rawklm = rawklms[copper]
268  if rawklm.GetNumEntries() != 1:
269  print('##0 Event', event, 'copper', copper, ' getNumEntries=', rawklm.GetNumEntries())
270  continue
271  nodeID = rawklm.GetNodeID(0) - self.BKLM_ID
272  if nodeID >= self.EKLM_ID - self.BKLM_ID:
273  nodeID = nodeID - (self.EKLM_ID - self.BKLM_ID) + 4
274  if (nodeID < 0) or (nodeID > 4): # examine BKLM nodes only
275  continue
276  trigCtime = (rawklm.GetTTCtime(0) & 0x7ffffff) << 3 # (ns)
277  for finesse in range(0, 4):
278  dc = (finesse << 2) + (copper & 0x3)
279  sectorFB = self.dcToSectorFB[dc]
280  nWords = rawklm.GetDetectorNwords(0, finesse)
281  if nWords <= 0:
282  continue
283  bufSlot = rawklm.GetDetectorBuffer(0, finesse)
284  lastWord = bufSlot[nWords - 1]
285  windowValue = (lastWord >> 16) & 0xffff
286  if windowValue != self.windowValue:
287  if windowValue in self.dict_nEvents:
288  self.windowValue = windowValue
290  self.hist_occupancyXYByWindow = self.dict_occupancyXYByWindow[windowValue]
291  else:
292  return # skip bogus event, incuding event with seed value of 0xcafe
293  if lastWord & 0xffff != 0:
294  print("##1 Event", event, 'copper', copper, 'finesse', finesse, 'n=', nWords, 'lastWord=', hex(lastWord))
295  if (nWords % 2) == 0:
296  print("##2 Event", event, 'copper', copper, 'finesse', finesse, 'n=', nWords, 'should be odd -- skipping')
297  continue
298  n = nWords >> 1 # number of Data-Concentrator data packets
299  self.dict_nRawKLMs[self.windowValue] += n
300  # first (and only) pass over this DC's hits: histogram everything
301  for j in range(0, n):
302  word0 = bufSlot[j * 2]
303  word1 = bufSlot[j * 2 + 1]
304  ctime = word0 & 0xffff
305  channel = (word0 >> 16) & 0x7f
306  axis = (word0 >> 23) & 0x01
307  lane = (word0 >> 24) & 0x1f # 1..2 for scints, 8..20 for RPCs (=readout-board slot - 7)
308  flag = (word0 >> 30) & 0x03 # 1 for RPCs, 2 for scints
309  tdc = (word1 >> 16) & 0x07ff
310  isRPC = (flag == 1)
311  electId = (channel << 12) | (axis << 11) | (lane << 6) | (finesse << 4) | nodeID
312  if electId in self.electIdToModuleId: # BKLM mapped-channel histograms
313  if isRPC:
314  tCal = int(tdc - trigCtime) & 0x03ff # in ns, range is 0..1023
315  self.hist_mappedRPCTimeCal.Fill(tCal)
316  self.hist_mappedRPCTimeCalByWindow.Fill(tCal)
317 
318  # for normalization of the hit-counter dictionaries, now that we know that this is a valid event
319 
320  self.dict_nEvents[self.windowValue] += 1
321 
322  # Process the BKLMHit2ds
323 
324  self.dict_nHit2ds[self.windowValue] += len(hit2ds)
325  for hit2d in hit2ds:
326  key = hit2d.getModuleID()
327  fb = (key & self.BKLM_SECTION_MASK) >> self.BKLM_SECTION_BIT
328  x = hit2d.getGlobalPositionX()
329  y = hit2d.getGlobalPositionY()
330  if fb == 0: # backward
331  self.hist_occupancyBackwardXY.Fill(x, y)
332  else: # forward
333  self.hist_occupancyForwardXY.Fill(x, y)
334  self.hist_occupancyXYByWindow.Fill(x, y)
EventInspectorLookback.EventInspectorLookback.hist_mappedRPCTimeCal
hist_mappedRPCTimeCal
histogram of RPC TDC - trigger value
Definition: EventInspectorLookback.py:106
EventInspectorLookback.EventInspectorLookback.dcToSectorFB
dcToSectorFB
map for data concentrator -> sectorFB
Definition: EventInspectorLookback.py:97
EventInspectorLookback.EventInspectorLookback.hist_mappedRPCTimeCalByWindow
hist_mappedRPCTimeCalByWindow
reference to the RPC-time histogram for the currevent value of the lookback window parameter
Definition: EventInspectorLookback.py:119
EventInspectorLookback.EventInspectorLookback.histogramFile
histogramFile
Output ROOT TFile that will contain the histograms/scatterplots.
Definition: EventInspectorLookback.py:99
EventInspectorLookback.EventInspectorLookback.event
def event(self)
Definition: EventInspectorLookback.py:256
EventInspectorLookback.EventInspectorLookback.hist_occupancyForwardXY
hist_occupancyForwardXY
scatterplot of end view of forward BKLM for all BKLMHit2ds
Definition: EventInspectorLookback.py:124
EventInspectorLookback.EventInspectorLookback.BKLM_SECTION_MASK
tuple BKLM_SECTION_MASK
bit mask for section [0..1]; forward is 0
Definition: EventInspectorLookback.py:45
EventInspectorLookback.EventInspectorLookback.dict_occupancyXYByWindow
dict_occupancyXYByWindow
dictionary of scatterplots of end view of forward BKLM, keyed by lookback-window value
Definition: EventInspectorLookback.py:135
EventInspectorLookback.EventInspectorLookback.windowStepValue
windowStepValue
lookback-window value step
Definition: EventInspectorLookback.py:84
EventInspectorLookback.EventInspectorLookback.windowMinValue
windowMinValue
highest observed lookback-window value
Definition: EventInspectorLookback.py:80
EventInspectorLookback.EventInspectorLookback.hist_occupancyBackwardXY
hist_occupancyBackwardXY
scatterplot of end view of backward BKLM for all BKLMHit2ds
Definition: EventInspectorLookback.py:128
Belle2::PyStoreObj
a (simplified) python wrapper for StoreObjPtr.
Definition: PyStoreObj.h:69
EventInspectorLookback.EventInspectorLookback.dict_nHit2ds
dict_nHit2ds
dictionary of the number of BKLMHit2ds for each lookback-window value
Definition: EventInspectorLookback.py:137
EventInspectorLookback.EventInspectorLookback
Definition: EventInspectorLookback.py:17
EventInspectorLookback.EventInspectorLookback.hist_occupancyXYByWindow
hist_occupancyXYByWindow
reference to the xy scatterplot for the currevent value of the lookback window parameter
Definition: EventInspectorLookback.py:132
EventInspectorLookback.EventInspectorLookback.histName
histName
internal copy of the pathname of the output histogram ROOT file
Definition: EventInspectorLookback.py:72
EventInspectorLookback.EventInspectorLookback.BKLM_ID
int BKLM_ID
COPPER base identifier for BKLM readout.
Definition: EventInspectorLookback.py:21
EventInspectorLookback.EventInspectorLookback.pdfName
pdfName
internal copy of the pathname of the output histogram PDF file
Definition: EventInspectorLookback.py:74
EventInspectorLookback.EventInspectorLookback.BKLM_SECTION_BIT
int BKLM_SECTION_BIT
bit position for section [0..1]; forward is 0
Definition: EventInspectorLookback.py:33
EventInspectorLookback.EventInspectorLookback.dict_nRawKLMs
dict_nRawKLMs
dictionary of the number of RawKLM hits for each lookback-window value
Definition: EventInspectorLookback.py:111
bklmDB.fillDB
def fillDB()
Definition: bklmDB.py:9
EventInspectorLookback.EventInspectorLookback.initialize
def initialize(self)
Definition: EventInspectorLookback.py:87
EventInspectorLookback.EventInspectorLookback.sectorFBToDC
sectorFBToDC
map for sectorFB -> data concentrator
Definition: EventInspectorLookback.py:95
EventInspectorLookback.EventInspectorLookback.exp
exp
internal copy of experiment number
Definition: EventInspectorLookback.py:68
EventInspectorLookback.EventInspectorLookback.dict_mappedRPCTimeCalByWindow
dict_mappedRPCTimeCalByWindow
dictionary of histograms of RPC TDC - trigger value, keyed by lookback-window value
Definition: EventInspectorLookback.py:109
EventInspectorLookback.EventInspectorLookback.windowMode
windowMode
window mode as a string for histogram labels/titles
Definition: EventInspectorLookback.py:78
EventInspectorLookback.EventInspectorLookback.electIdToModuleId
electIdToModuleId
readout <-> detector map (from the information retrieved from the conditions database)
Definition: EventInspectorLookback.py:93
Belle2::PyStoreArray
a (simplified) python wrapper for StoreArray.
Definition: PyStoreArray.h:58
EventInspectorLookback.EventInspectorLookback.EKLM_ID
int EKLM_ID
COPPER base identifier for EKLM readout.
Definition: EventInspectorLookback.py:23
EventInspectorLookback.EventInspectorLookback.windowValue
windowValue
cached value of the lookback-window value, to avoid unnecessary reassignments-to-same-value in event(...
Definition: EventInspectorLookback.py:150
EventInspectorLookback.EventInspectorLookback.endRun
def endRun(self)
Definition: EventInspectorLookback.py:251
EventInspectorLookback.EventInspectorLookback.terminate
def terminate(self)
Definition: EventInspectorLookback.py:152
EventInspectorLookback.EventInspectorLookback.__init__
def __init__(self, exp, run, histName, pdfName, mode, window)
Definition: EventInspectorLookback.py:51
EventInspectorLookback.EventInspectorLookback.dict_nEvents
dict_nEvents
dictionary of the number of events for each lookback-window value, for normalization
Definition: EventInspectorLookback.py:145
EventInspectorLookback.EventInspectorLookback.run
run
internal copy of run number
Definition: EventInspectorLookback.py:70
EventInspectorLookback.EventInspectorLookback.beginRun
def beginRun(self)
Definition: EventInspectorLookback.py:246
EventInspectorLookback.EventInspectorLookback.windowMaxValue
windowMaxValue
highest observed lookback-window value
Definition: EventInspectorLookback.py:82