20 from ROOT
import Belle2
21 from ROOT
import TH1F, TH2F, TFile, TTree, TF1
22 from array
import array
31 data_dir =
'/group/belle2/dataprod/Data/release-03-02-02/DB00000635/proc00000009_nofilter'
32 skim_dir =
'skim/hlt_bhabha/cdst/sub00'
33 globalTag =
'data_reprocessing_prompt'
34 stagingTags = [
'staging_data_reprocessing']
37 output_dir =
'commonT0'
44 print(
"usage: basf2", argvs[0],
"experiment run")
46 experiment = int(argvs[1])
49 expNo =
'e' +
'{:0=4d}'.format(experiment)
50 runNo =
'r' +
'{:0=5d}'.format(run)
54 for typ
in [
'4S',
'Continuum',
'Scan']:
55 folder = data_dir +
'/' + expNo +
'/' + typ +
'/' + runNo +
'/' + skim_dir
56 files += glob.glob(folder +
'/cdst.*.root')
58 b2.B2ERROR(
'No cdst files found')
62 output_folder = output_dir +
'/' + expNo +
'/' + sampleType +
'/' + method
63 if not os.path.isdir(output_folder):
64 os.makedirs(output_folder)
65 print(
'New folder created: ' + output_folder)
68 fileName = output_folder +
'/commonT0-' + expNo +
'-' + runNo +
'.root'
69 print(
'Output file:', fileName)
73 ''' exclude (mask-out) BS 13d '''
76 ''' event processing '''
79 if digit.getModuleID() == 13
and digit.getBoardstackNumber() == 3:
80 digit.setHitQuality(Belle2.TOPDigit.c_Junk)
86 Module to calculate the commont time offset of the TOP detector.
87 It selects two-track events, saves the bunch finder time offset in an histrogram and
88 fits it to extract the global time offset with respect to the RF clock.
89 It should be run in an individual job for each run, but in future it may be further
90 authomatize to run on multiple runs in the same job.
94 * The histogram of the bunch finder time offset
96 * The fit parameters ina tree format (usefuly when merging several files)
101 Creates the histogram used for the commoT0 calculation, and
102 takes the necessary objects from the DataStore
106 self.
filefile = TFile.Open(fileName,
'recreate')
109 if not geo.isValid():
110 b2.B2FATAL(
'TOP geometry not available in database')
113 self.
bunchTimeSepbunchTimeSep = geo.getNominalTDC().getSyncTimeBase() / 24
116 self.
h1h1 = TH1F(
"offset",
"current offset; offset [ns]", 600, -9.0, 9.0)
119 self.
h2h2 = TH2F(
"offset_vs_event",
"current offset versus event number",
120 100, 0.0, 1000000.0, 200, -3.0, 3.0)
121 self.
h2h2.SetXTitle(
"event number")
122 self.
h2h2.SetYTitle(
"offset [ns]")
127 self.
h1ah1a = TH1F(
"offset_a",
"current offset; offset [ns]", 200, xmi, xma)
130 self.
h2ah2a = TH2F(
"offset_vs_event_a",
"current offset versus event number",
131 100, 0.0, 1000000.0, 200, xmi, xma)
132 self.
h2ah2a.SetXTitle(
"event number")
133 self.
h2ah2a.SetYTitle(
"offset [ns]")
138 self.
h1bh1b = TH1F(
"offset_b",
"current offset; offset [ns]", 200, xmi, xma)
141 self.
h2bh2b = TH2F(
"offset_vs_event_b",
"current offset versus event number",
142 100, 0.0, 1000000.0, 200, xmi, xma)
143 self.
h2bh2b.SetXTitle(
"event number")
144 self.
h2bh2b.SetYTitle(
"offset [ns]")
149 self.
expNoexpNo = evtMetaData.getExperiment()
152 self.
runrun =
'{:0=5d}'.format(evtMetaData.getRun())
159 if commonT0.isValid():
160 if commonT0.isCalibrated():
161 self.
t0t0 = commonT0.getT0()
162 self.
t0Errt0Err = commonT0.getT0Error()
163 b2.B2INFO(
'Common T0 used in data processing: ' + str(self.
t0t0))
165 b2.B2INFO(
'No common T0 calibration done yet')
167 b2.B2ERROR(
'Common T0 not available in database')
171 Fills the histogram of the time offset
175 if not recBunch.isValid():
177 if recBunch.isReconstructed()
and recBunch.getNumTracks() == 2:
178 offset = recBunch.getCurrentOffset()
179 evtNum = evtMetaData.getEvent()
180 self.
h1h1.Fill(offset)
181 self.
h2h2.Fill(evtNum, offset)
185 self.
h2ah2a.Fill(evtNum, a)
189 self.
h2bh2b.Fill(evtNum, b)
193 Selects a histogram with the peak closest to histogram center
196 halfbins = self.
h1ah1a.GetNbinsX() / 2
197 if abs(self.
h1ah1a.GetMaximumBin() - halfbins) < abs(self.
h1bh1b.GetMaximumBin() - halfbins):
204 Performs the fit of the bunch finder offset distribution,
205 using a line + gaussian function.
206 The results of the fit are saved in a tree
211 maximum = h_to_fit.GetBinCenter(h_to_fit.GetMaximumBin())
212 hmax = h_to_fit.GetMaximum()
214 xmin = h_to_fit.GetXaxis().GetXmin()
215 xmax = h_to_fit.GetXaxis().GetXmax()
220 '([0]/TMath::Sqrt(2*TMath::Pi() * [2]*[2])) * exp(-0.5*((x-[1])/[2])**2) \
223 func.SetParameter(0, hmax * 0.9 * math.sqrt(2*math.pi) * sigma0)
224 func.SetParameter(1, maximum)
225 func.SetParameter(2, sigma0)
226 func.SetParLimits(2, 0.05, 0.3)
227 func.SetParameter(3, 0.)
228 func.SetParameter(4, hmax * 0.1)
229 status = h_to_fit.Fit(func,
'L R S')
232 tree = TTree(
'tree',
'')
234 expNum = array(
'i', [0])
235 runNum = array(
'i', [0])
236 fitted_offset = array(
'f', [0.])
237 offset = array(
'f', [0.])
238 offsetErr = array(
'f', [0.])
239 sigma = array(
'f', [0.])
240 integral = array(
'f', [0.])
241 nEvt = array(
'f', [0.])
242 chi2 = array(
'f', [0.])
243 fitStatus = array(
'i', [0])
245 tree.Branch(
'expNum', expNum,
'expNum/I')
246 tree.Branch(
'runNum', runNum,
'runNum/I')
247 tree.Branch(
'fitted_offset', fitted_offset,
'fitted_offset/F')
248 tree.Branch(
'offset', offset,
'offset/F')
249 tree.Branch(
'offsetErr', offsetErr,
'offsetErr/F')
250 tree.Branch(
'sigma', sigma,
'sigma/F')
251 tree.Branch(
'chi2', chi2,
'chi2/F')
252 tree.Branch(
'integral', integral,
'integral/F')
253 tree.Branch(
'nEvt', nEvt,
'nEvt/F')
254 tree.Branch(
'fitStatus', fitStatus,
'fitStatus/I')
257 expNum[0] = self.
expNoexpNo
258 runNum[0] = int(self.
runrun)
259 fitted_offset[0] = func.GetParameter(1)
260 new_t0 = fitted_offset[0] + self.
t0t0
262 offsetErr[0] = func.GetParError(1)
263 sigma[0] = func.GetParameter(2)
264 integral[0] = func.GetParameter(0) / h_to_fit.GetBinWidth(1)
265 chi2[0] = func.GetChisquare() / float(func.GetNDF())
266 nEvt[0] = h_to_fit.Integral()
267 fitStatus[0] = int(status)
277 self.
filefile.Close()
279 b2.B2RESULT(
'Calibration for exp' + str(self.
expNoexpNo) +
'-run' + self.
runrun)
280 if self.
t0Errt0Err > 0:
281 b2.B2RESULT(
'Old common T0 [ns]: ' + str(round(self.
t0t0, 3)) +
' +- ' +
282 str(round(self.
t0Errt0Err, 3)))
284 b2.B2RESULT(
'Old common T0 [ns]: -- not calibrated -- ')
285 b2.B2RESULT(
'New common T0 [ns]: ' + str(round(offset[0], 3)) +
' +- ' +
286 str(round(offsetErr[0], 3)))
287 b2.B2RESULT(
"Output written to " + fileName)
291 b2.use_central_database(globalTag)
292 for tag
in stagingTags:
293 b2.use_central_database(tag)
295 if os.path.isfile(db):
296 b2.use_local_database(db, invertLogging=
True)
298 b2.B2ERROR(db +
": local database not found")
302 main = b2.create_path()
305 main.add_module(
'RootInput', inputFileNames=files)
308 main.add_module(
'TOPGeometryParInitializer')
311 main.add_module(
'TOPTimeRecalibrator', subtractBunchTime=
False)
314 main.add_module(
'TOPChannelMasker')
320 main.add_module(
'TOPBunchFinder', usePIDLikelihoods=
True, subtractRunningOffset=
False)
326 main.add_module(
'TOPCommonT0Calibrator', sample=sampleType, outputFileName=fileName)
328 b2.B2ERROR(
'unknown method ' + method)
332 progress = b2.register_module(
'Progress')
333 main.add_module(progress)
Class to access a DBObjPtr from Python.
a (simplified) python wrapper for StoreArray.
a (simplified) python wrapper for StoreObjPtr.
run
run number formatted as string with leading zeros
bunchTimeSep
bunch separation time
def getHistogramToFit(self)
h1b
histogram of current offset, wrap-around into [0, 1] of bunch sep.
t0Err
common T0 uncertainty
h1
histogram of current offset
h1a
histogram of current offset, wrap-around into [-1/2, 1/2] of bunch sep.
h2b
histogram of current offset vs event number, wrap-around into [0, 1]
t0
common T0 used for the calibration of the input file
h2
histogram of current offset vs event number
h2a
histogram of current offset vs event number, wrap-around into [-1/2, 1/2]