Belle II Software development
studyTBCResolution.py
1#!/usr/bin/env python3
2
3
10
11# ------------------------------------------------------------------------
12# Module to study the features of the double pulse used for the TOP calibration.
13# To be used to determine the TBC quality and precision
14#
15# usage: basf2 studyTBCResolution.py dbaddress (path|none) type (local|pocket) output_name.root path_to_files run1 run2 ... runN
16# The run number accepts wildcards
17# ------------------------------------------------------------------------
18
19import basf2 as b2
20import sys
21import glob
22from ROOT import Belle2
23from ROOT import TH1F, TH2F, TF1, TFile, TGraphErrors
24
25
26class TOPTBCResolution(b2.Module):
27
28 ''' Module to study resolution and performances of the TOP Time Base Calibration.'''
29
30
31 h_WidthVSAmplitude_1 = TH2F(
32 'WidthVSAmplitude_1',
33 'Width VS amplidute of the TOPDigits, first calibration pulse',
34 2000, 0., 2000, 100, 0., 10.)
35
36 h_WidthVSAmplitude_2 = TH2F(
37 'WidthVSAmplitude_2',
38 'Width VS amplidute of the TOPDigits, second calibration pulse',
39 2000, 0., 2000, 100, 0., 10.)
40
41
42 h_dVdtRising_1 = TH1F('dVdtRising_1', ' dV/dt of the TOPRawDigits (rising edge), first calibration pulse', 1000, 0, 1000)
43
44 h_dVdtRising_2 = TH1F('dVdtRising_2', ' dV/dt of the TOPRawDigits (rising edge), second calibration pulse', 1000, 0, 1000)
45
46 h_dVdtFalling_1 = TH1F('dVdtFalling_1', ' dV/dt of the TOPRawDigits (falling edge), first calibration pulse', 1000, 0, 1000)
47
48 h_dVdtFalling_2 = TH1F('dVdtFalling_2', ' dV/dt of the TOPRawDigits (falling edge), second calibration pulse', 1000, 0, 1000)
49
50 h_dVdtRisingVSdVdtFalling_1 = TH2F(
51 'dVdtRisingVSdVdtFalling_1',
52 ' dV/dt of the TOPRawDigit: rising edge VS falling edge, first calibration pulse ',
53 1000, 0, 1000, 1000, 0., 1000.)
54
55 h_dVdtRisingVSdVdtFalling_2 = TH2F(
56 'dVdtRisingVSdVdtFalling_2',
57 ' dV/dt of the TOPRawDigit: rising edge VS falling edge, second calibration pulse ',
58 1000, 0, 1000, 1000, 0., 1000.)
59
60 h_dVdtRisingDifference = TH1F(
61 'dVdtRisingDifference', ' difference between the rising edge dV/dt of the first and the second pulse', 1000, -500, 500)
62
63 h_dVdtFallingDifference = TH1F(
64 'dVdtFallingDifference', ' difference between the falling edge dV/dt of the first and the second pulse', 1000, -500, 500)
65
66
67 h_DeltaT_RR = TH1F('DeltaT_RR', ' DeltaT bewteen the rising edges', 4000, 10, 30)
68
69 h_DeltaT_FF = TH1F('DeltaT_FF', ' DeltaT bewteen the falling edges', 4000, 10, 30)
70
71 h_DeltaT_FR = TH1F('DeltaT_FR', ' DeltaT bewteen falling and rising edges', 4000, 10, 30)
72
73 h_DeltaT_RF = TH1F('DeltaT_RF', ' DeltaT bewteen rising and falling edges', 4000, 10, 30)
74
75
76 h_DeltaTVSChannel_RR = TH2F(
77 'DeltaTVSChannel_RR',
78 ' DeltaT bewteen the rising edges, as function of the channel number',
79 512 * 16, 0, 512 * 16, 4000, 10., 30.)
80
81 h_DeltaTVSChannel_FF = TH2F(
82 'DeltaTVSChannel_FF',
83 ' DeltaT bewteen the falling edges, as function of the channel number',
84 512 * 16, 0, 512 * 16, 4000, 10., 30.)
85
86 h_DeltaTVSChannel_FR = TH2F(
87 'DeltaTVSChannel_FR',
88 ' DeltaT bewteen falling (pulse 1) and rising (pulse 2) edge, as function of the channel number',
89 512 * 16, 0, 512 * 16, 4000, 10., 30.)
90
91 h_DeltaTVSChannel_RF = TH2F(
92 'DeltaTVSChannel_RF',
93 ' DeltaT bewteen rising (pulse 1) and falling (pulse 2) edge, as function of the channel number',
94 512 * 16, 0, 512 * 16, 4000, 10., 30.)
95
96 h_DeltaTVSdVdt_RR = TH2F(
97 'DeltaTVSdVdt_RR',
98 'DeltaT bewteen the rising edges VS average of dV/dt on the first and second pulser',
99 1000, 0., 1000., 4000, 10., 30.)
100
101 h_DeltaTVSdVdt_FF = TH2F(
102 'DeltaTVSdVdt_FF',
103 'DeltaT bewteen the rising edges VS average of dV/dt on the first and second pulser',
104 1000, 0., 1000., 4000, 10., 30.)
105
106
107 h_ResolutionVSdVdt_FF = TGraphErrors()
108
109 h_ResolutionVSdVdt_RR = TGraphErrors()
110
111
112 outname = 'outStudyTBCResolution.root'
113
114 m_calpulseMaxWidth = 3.
115
116 m_calpulseMinWidth = 0.5
117
118 m_calpulseMaxAmp = 700.
119
120 m_calpulseMinAmp = 250.
121
122 m_ignoreNotCalibrated = True
123
124 def setOutputName(self, outputname):
125 ''' Sets the output file name '''
126
127 self.outnameoutname = outputname
128
129 def setMaxWidth(self, maxWidth):
130 ''' Sets the maximum calpulse width '''
131
133
134 def setMinWidth(self, minWidth):
135 ''' Sets the minimum calpulse width '''
136
138
139 def setMaxAmp(self, maxAmp):
140 ''' Sets the maximum calpulse amplitude '''
141
143
144 def setMinAmp(self, minAmp):
145 ''' Sets the minimum calpulse amplitude '''
146
148
149 def ignoreNotCalibrated(self, ignoreNotCal):
150 ''' Sets the flag to ingore the hits without calibration '''
151
153
154 def event(self):
155 ''' Event processor: fill histograms '''
156
157 digits = Belle2.PyStoreArray('TOPDigits')
158
159 for ipulse1, digit1 in enumerate(digits):
160 if(self.ignoreNotCalibrated and not digit1.isTimeBaseCalibrated()):
161 continue
162 if (digit1.getHitQuality() != 0 and
163 digit1.getPulseHeight() > self.m_calpulseMinAmpm_calpulseMinAmp and
164 digit1.getPulseHeight() < self.m_calpulseMaxAmpm_calpulseMaxAmp and
165 digit1.getPulseWidth() > self.m_calpulseMinWidthm_calpulseMinWidth and
166 digit1.getPulseWidth() < self.m_calpulseMaxWidthm_calpulseMaxWidth):
167
168 slotID = digit1.getModuleID()
169 hwchan = digit1.getChannel()
170 for ipulse2, digit2 in enumerate(digits, start=ipulse1 + 1):
171 if(self.ignoreNotCalibrated and not digit2.isTimeBaseCalibrated()):
172 continue
173
174 if (digit2.getHitQuality() != 0 and
175 digit2.getPulseHeight() > self.m_calpulseMinAmpm_calpulseMinAmp and
176 digit2.getPulseHeight() < self.m_calpulseMaxAmpm_calpulseMaxAmp and
177 digit2.getPulseWidth() > self.m_calpulseMinWidthm_calpulseMinWidth and
178 digit2.getPulseWidth() < self.m_calpulseMaxWidthm_calpulseMaxWidth and
179 slotID == digit2.getModuleID() and
180 hwchan == digit2.getChannel()):
181
182 # finds which one is the first calpulse
183 rawDigitFirst = digit1.getRelated('TOPRawDigits')
184 rawDigitSecond = digit2.getRelated('TOPRawDigits')
185 if digit1.getTime() > digit2.getTime():
186 rawDigitFirst = digit2.getRelated('TOPRawDigits')
187 rawDigitSecond = digit1.getRelated('TOPRawDigits')
188 digitFirst = rawDigitFirst.getRelated('TOPDigits')
189 digitSecond = rawDigitSecond.getRelated('TOPDigits')
190
191 globalCh = hwchan + 512 * (slotID - 1)
192 dV1_R = rawDigitFirst.getLeadingSlope()
193 dV1_F = -rawDigitFirst.getFallingSlope()
194 dV2_R = rawDigitSecond.getLeadingSlope()
195 dV2_F = -rawDigitSecond.getFallingSlope()
196 t1_R = digitFirst.getTime()
197 t1_F = digitFirst.getTime() + digitFirst.getPulseWidth()
198 t2_R = digitSecond.getTime()
199 t2_F = digitSecond.getTime() + digitSecond.getPulseWidth()
200 amp1 = digitFirst.getPulseHeight()
201 amp2 = digitSecond.getPulseHeight()
202 w1 = digitFirst.getPulseWidth()
203 w2 = digitSecond.getPulseWidth()
204
205 self.h_WidthVSAmplitude_1.Fill(amp1, w1)
206 self.h_WidthVSAmplitude_2.Fill(amp2, w2)
207 self.h_dVdtRising_1.Fill(dV1_R)
208 self.h_dVdtRising_2.Fill(dV2_R)
209 self.h_dVdtFalling_1.Fill(dV1_F)
210 self.h_dVdtFalling_2.Fill(dV2_F)
211 self.h_dVdtRisingVSdVdtFalling_1.Fill(dV1_F, dV1_R)
212 self.h_dVdtRisingVSdVdtFalling_2.Fill(dV2_F, dV2_R)
213 self.h_dVdtRisingDifference.Fill(dV1_R - dV2_R)
214 self.h_dVdtFallingDifference.Fill(dV1_F - dV2_F)
215 self.h_DeltaT_RR.Fill(t2_R - t1_R)
216 self.h_DeltaT_FF.Fill(t2_F - t1_F)
217 self.h_DeltaT_FR.Fill(t2_F - t1_R)
218 self.h_DeltaT_RF.Fill(t2_R - t1_F)
219 self.h_DeltaTVSChannel_RR.Fill(globalCh, t2_R - t1_R)
220 self.h_DeltaTVSChannel_FF.Fill(globalCh, t2_F - t1_F)
221 self.h_DeltaTVSChannel_FR.Fill(globalCh, t2_F - t1_R)
222 self.h_DeltaTVSChannel_RF.Fill(globalCh, t2_R - t1_F)
223 self.h_DeltaTVSdVdt_RR.Fill(0.5 * (dV1_R + dV2_R), t2_R - t1_R)
224 self.h_DeltaTVSdVdt_FF.Fill(0.5 * (dV1_F + dV2_F), t2_F - t1_F)
225
226 def terminate(self):
227 ''' Write histograms to file, fills and fits the resolution plots'''
228
229 self.h_ResolutionVSdVdt_RR.SetName('ResolutionVSdVdt_RR')
230 self.h_ResolutionVSdVdt_RR.SetTitle('Resolution VS dV/dt (rising-rising)')
231 self.h_ResolutionVSdVdt_FF.SetName('ResolutionVSdVdt_FF')
232 self.h_ResolutionVSdVdt_FF.SetTitle('Resolution VS dV/dt (falling-falling)')
233
234 for ibin in range(0, 10):
235 projection = self.h_DeltaTVSdVdt_RR.ProjectionY("tmpProj", ibin * 100 + 1, (ibin + 1) * 100)
236 gaussFit = TF1("gaussFit", "[0]*exp(-0.5*((x-[1])/[2])**2)", 10., 30.)
237 gaussFit.SetParameter(0, 1.)
238 gaussFit.SetParameter(1, projection.GetMean())
239 gaussFit.SetParameter(2, projection.GetRMS())
240 gaussFit.SetParLimits(2, 0., 3. * projection.GetRMS())
241
242 projection.Fit("gaussFit")
243 self.h_ResolutionVSdVdt_RR.SetPoint(ibin, ibin * 100. + 50., gaussFit.GetParameter(2))
244 self.h_ResolutionVSdVdt_RR.SetPointError(ibin, 50., gaussFit.GetParError(2))
245
246 tfile = TFile(self.outnameoutname, 'recreate')
247 self.h_WidthVSAmplitude_1.GetXaxis().SetTitle("TOPDigit amplitude [ADC counts]")
248 self.h_WidthVSAmplitude_1.GetYaxis().SetTitle("TOPDigit width [ns]")
249 self.h_WidthVSAmplitude_1.Write()
250 self.h_WidthVSAmplitude_2.GetXaxis().SetTitle("TOPDigit amplitude [ADC counts]")
251 self.h_WidthVSAmplitude_2.GetYaxis().SetTitle("TOPDigit width [ns]")
252 self.h_WidthVSAmplitude_2.Write()
253
254 self.h_dVdtRising_1.GetXaxis().SetTitle("dV/dt [ADC counts / sample]")
255 self.h_dVdtRising_1.Write()
256 self.h_dVdtRising_2.GetXaxis().SetTitle("dV/dt [ADC counts / sample]")
257 self.h_dVdtRising_2.Write()
258 self.h_dVdtFalling_1.GetXaxis().SetTitle("dV/dt [ADC counts / sample]")
259 self.h_dVdtFalling_1.Write()
260 self.h_dVdtFalling_2.GetXaxis().SetTitle("dV/dt [ADC counts / sample]")
261 self.h_dVdtFalling_2.Write()
262
263 self.h_dVdtRisingVSdVdtFalling_1.GetXaxis().SetTitle("dV/dt on the falling edge [ADC counts / sample]")
264 self.h_dVdtRisingVSdVdtFalling_1.GetYaxis().SetTitle("dV/dt on the rising edge [ADC counts / sample]")
265 self.h_dVdtRisingVSdVdtFalling_1.Write()
266
267 self.h_dVdtRisingVSdVdtFalling_2.GetXaxis().SetTitle("dV/dt on the falling edge [ADC counts / sample]")
268 self.h_dVdtRisingVSdVdtFalling_2.GetYaxis().SetTitle("dV/dt on the rising edge [ADC counts / sample]")
269 self.h_dVdtRisingVSdVdtFalling_2.Write()
270
271 self.h_dVdtFallingDifference.GetXaxis().SetTitle("dV/dt_1 - dV/dt_2 [ADC counts / sample]")
272 self.h_dVdtFallingDifference.Write()
273
274 self.h_dVdtRisingDifference.GetXaxis().SetTitle("dV/dt_1 - dV/dt_2 [ADC counts / sample]")
275 self.h_dVdtRisingDifference.Write()
276
277 self.h_DeltaT_RR.GetXaxis().SetTitle("#Delta t [ns]")
278 self.h_DeltaT_RR.Write()
279 self.h_DeltaT_FF.GetXaxis().SetTitle("#Delta t [ns]")
280 self.h_DeltaT_FF.Write()
281 self.h_DeltaT_FR.GetXaxis().SetTitle("#Delta t [ns]")
282 self.h_DeltaT_FR.Write()
283 self.h_DeltaT_RF.GetXaxis().SetTitle("#Delta t [ns]")
284 self.h_DeltaT_RF.Write()
285
286 self.h_DeltaTVSChannel_RR.GetXaxis().SetTitle("Global channel number [hwChannel + 512*(slotID-1)]")
287 self.h_DeltaTVSChannel_RR.GetYaxis().SetTitle("#Delta t [ns]")
288 self.h_DeltaTVSChannel_RR.Write()
289 self.h_DeltaTVSChannel_FF.GetXaxis().SetTitle("Global channel number [hwChannel + 512*(slotID-1)]")
290 self.h_DeltaTVSChannel_FF.GetYaxis().SetTitle("#Delta t [ns]")
291 self.h_DeltaTVSChannel_FF.Write()
292 self.h_DeltaTVSChannel_FR.GetXaxis().SetTitle("Global channel number [hwChannel + 512*(slotID-1)]")
293 self.h_DeltaTVSChannel_FR.GetYaxis().SetTitle("#Delta t [ns]")
294 self.h_DeltaTVSChannel_FR.Write()
295 self.h_DeltaTVSChannel_RF.GetXaxis().SetTitle("Global channel number [hwChannel + 512*(slotID-1)]")
296 self.h_DeltaTVSChannel_RF.GetYaxis().SetTitle("#Delta t [ns]")
297 self.h_DeltaTVSChannel_RF.Write()
298
299 self.h_DeltaTVSdVdt_RR.GetXaxis().SetTitle("Average of dV/dt on first and second pulse [ACD counts / sample]")
300 self.h_DeltaTVSdVdt_RR.GetYaxis().SetTitle("#Delta t [ns]")
301 self.h_DeltaTVSdVdt_RR.Write()
302
303 self.h_DeltaTVSdVdt_FF.GetXaxis().SetTitle("Average of dV/dt on first and second pulse [ACD counts / sample]")
304 self.h_DeltaTVSdVdt_FF.GetYaxis().SetTitle("#Delta t [ns]")
305 self.h_DeltaTVSdVdt_FF.Write()
306
307 self.h_ResolutionVSdVdt_RR.Write()
308 tfile.Close()
309
310
311argvs = sys.argv
312
313print('usage: basf2', argvs[0], 'runNumber outfileName')
314
315dbaddress = argvs[1] # path to the calibration DB (absolute path or 'none')
316datatype = argvs[2] # data type ('pocket' or 'local')
317outfile = argvs[3] # output name
318folder = argvs[4] # folder containing input files
319runnumbers = sys.argv[5:] # run numbers
320
321files = []
322for runnumber in runnumbers:
323 files += [f for f in glob.glob(str(folder) + '/*' + str(runnumber) + '*.sroot')]
324sroot = True
325if len(files) == 0:
326 sroot = False
327 for runnumber in runnumbers:
328 files += [f for f in glob.glob(str(folder) + '/*' + str(runnumber) + '*.root')]
329
330for fname in files:
331 print("file: " + fname)
332
333if dbaddress != 'none':
334 print("using local DB " + dbaddress)
335 b2.conditions.append_testing_payloads(dbaddress + "/localDB.txt")
336else:
337 print("database not set. Continuing without calibrations")
338
339# Suppress messages and warnings during processing
340b2.set_log_level(b2.LogLevel.ERROR)
341
342# Define a global tag (note: the one given bellow can be out-dated!)
343b2.conditions.override_globaltags()
344b2.conditions.append_globaltag('online')
345
346# Create path
347main = b2.create_path()
348
349# input
350if sroot:
351 roinput = b2.register_module('SeqRootInput') # sroot files
352else:
353 roinput = b2.register_module('RootInput') # root files
354roinput.param('inputFileNames', files)
355main.add_module(roinput)
356
357# conversion from RawCOPPER or RawDataBlock to RawDetector objects
358if datatype == 'pocket':
359 print('pocket DAQ data assumed')
360 converter = b2.register_module('Convert2RawDet')
361 main.add_module(converter)
362
363# Initialize TOP geometry parameters (creation of Geant geometry is not needed)
364main.add_module('TOPGeometryParInitializer')
365
366# Unpacking (format auto detection works now)
367unpack = b2.register_module('TOPUnpacker')
368main.add_module(unpack)
369
370# Add multiple hits by running feature extraction offline
371featureExtractor = b2.register_module('TOPWaveformFeatureExtractor')
372main.add_module(featureExtractor)
373
374# Convert to TOPDigits
375converter = b2.register_module('TOPRawDigitConverter')
376if dbaddress == 'none':
377 print("Not using TBC")
378 converter.param('useSampleTimeCalibration', False)
379else:
380 print("Using TBC")
381 converter.param('useSampleTimeCalibration', True)
382converter.param('useAsicShiftCalibration', False)
383converter.param('useChannelT0Calibration', False)
384converter.param('useModuleT0Calibration', False)
385converter.param('useCommonT0Calibration', False)
386converter.param('calibrationChannel', -1) # do not specify the calpulse channel
387converter.param('lookBackWindows', 28) # in number of windows
388main.add_module(converter)
389
390# resolution plotter
391resolutionModule = TOPTBCResolution()
392resolutionModule.setOutputName(outfile)
393resolutionModule.setMinWidth(0.5) # calpluse candidate selection
394resolutionModule.setMaxWidth(3.5) # calpluse candidate selection
395resolutionModule.setMinAmp(150) # calpluse candidate selection
396resolutionModule.setMaxAmp(999) # calpluse candidate selection
397if dbaddress == 'none':
398 resolutionModule.ignoreNotCalibrated(False)
399else:
400 resolutionModule.ignoreNotCalibrated(True)
401main.add_module(resolutionModule)
402
403# Show progress of processing
404progress = b2.register_module('Progress')
405main.add_module(progress)
406
407# Process events
408b2.process(main)
409
410# Print call statistics
411print(b2.statistics)
412print(b2.statistics(b2.statistics.TERM))
A (simplified) python wrapper for StoreArray.
Definition: PyStoreArray.h:72
TGraphErrors h_ResolutionVSdVdt_FF
DeltaT resolution VS average of dV/dt (falling-falling)
bool m_ignoreNotCalibrated
ignores the hits wthout calibration
int m_calpulseMinAmp
minimum amplitude to flag a calpulse candidate
TH1F h_dVdtFallingDifference
Difference between the dV/dt of the first and the second calpulse, using the rising edges.
def ignoreNotCalibrated(self, ignoreNotCal)
TH1F h_dVdtFalling_2
dV/dt on the falling edge, second calibration pulse
TH1F h_DeltaT_FR
DeltaT falling-rising.
TH1F h_dVdtRising_1
dV/dt on the rising edge, first calibration pulse
TH1F h_dVdtRisingDifference
Difference between the dV/dt of the first and the second calpulse, using the rising edges.
TGraphErrors h_ResolutionVSdVdt_RR
DeltaT resolution VS average of dV/dt (rising-rising)
TH2F h_dVdtRisingVSdVdtFalling_1
dV/dt on the rising edge VS dV/dt on the falling edge, first calibration pulse
TH2F h_DeltaTVSdVdt_FF
DeltaT falling-falling VS average of dV/dt on the first and second pulse.
TH1F h_DeltaT_RF
DeltaT rising-falling.
int m_calpulseMaxAmp
minimum amplitude to flag a calpulse candidate
TH2F h_DeltaTVSdVdt_RR
DeltaT rising-rising VS average of dV/dt on the first and second pulse.
TH1F h_dVdtRising_2
dV/dt on the rising edge, second calibration pulse
TH2F h_DeltaTVSChannel_RR
DeltaT rising-rising VS channel.
TH1F h_DeltaT_FF
DeltaT falling-falling.
TH1F h_dVdtFalling_1
dV/dt on the falling edge, first calibration pulse
TH2F h_DeltaTVSChannel_FR
DeltaT falling-rising VS channel.
TH2F h_dVdtRisingVSdVdtFalling_2
dV/dt on the rising edge VS dV/dt on the falling edge, first calibration pulse
TH2F h_WidthVSAmplitude_1
Width VS amplitude, first calibration pulse.
float m_calpulseMinWidth
minimum width to flag a calpulse candidate
int m_calpulseMaxWidth
maximum width to flag a calpulse candidate
TH2F h_WidthVSAmplitude_2
Width VS amplitude, second calibration pulse.
TH2F h_DeltaTVSChannel_FF
DeltaT falling-falling VS channel.
TH2F h_DeltaTVSChannel_RF
DeltaT rising-falling VS channel.
TH1F h_DeltaT_RR
DeltaT rising-rising.