15 from ROOT
import Belle2
16 from ROOT
import TH1F, TH2F, TFile
17 from ROOT
import gROOT, AddressOf, gRandom
18 from ROOT
import TLorentzVector
27 file_num = sys.argv[1]
30 gROOT.ProcessLine(
'struct TreeStruct {\
31 int run; /* run number */ \
32 int itrk; /* track counter */ \
33 float offset; /* current bunch offset */ \
34 int usedTrk; /* number of tracks used for bunch reconstruction */ \
35 int slot; /* slot ID */ \
36 float p; /* extHit momentum */ \
37 float cth; /* extHit local cos(theta) (global must be pretty much the same) */ \
38 float phi; /* extHit local phi */ \
39 float z; /* extHit local z */ \
40 float x; /* extHit local x */ \
41 float tof; /* extHit time-of-flight */ \
42 int charge; /* particle charge */ \
43 float poca_x; /* POCA x */ \
44 float poca_y; /* POCA y */ \
45 float poca_z; /* POCA z */ \
46 int hitsCDC; /* number of CDC hits */ \
47 float dEcms; /* delta Ecms for muon */ \
48 float rec_t0; /* t0 of this track determined with bunch finder */ \
49 int valid_t0; /* reconstruction status of t0 */ \
50 int nfot; /* number of photons */ \
51 int channel[1000]; /* channel */ \
52 int pixel[1000] ; /* pixel ID */ \
53 float time[1000]; /* photon time */ \
54 float timeErr[1000]; /* photon time uncertainty */ \
55 int pulseHeight[1000]; /* photon pulse height */ \
56 float pulseWidth[1000]; /* photon pulse width */ \
57 int sample[1000]; /* sample number modulo 256 */ \
58 int status[1000]; /* calibration status bits */ \
59 float t0[1000]; /* leading PDF peak: position */ \
60 float wid0[1000]; /* leading PDF peak: width w/o TTS */ \
61 float t1[1000]; /* next to leading PDF peak: position */ \
62 float t_pdf[1000]; /* associated pdf peak time */ \
63 int type[1000]; /* 0 bkg, 1 direct, 2 reflected */ \
64 int nx[1000]; /* total number of reflections in x */ \
65 int ny[1000]; /* total number of reflections in y */ \
66 int nxm[1000]; /* number of reflections in x before mirror */ \
67 int nym[1000]; /* number of reflections in y before mirror */ \
68 int nxe[1000]; /* number of reflections in x in prism */ \
69 int nye[1000]; /* number of reflections in y in prism */ \
70 int nys[1000]; /* number of reflections on slanted surface of prism */ \
71 float xd[1000]; /* unfolded x coordinate of a pixel */ \
72 float yd[1000]; /* unfolded y coordinate of a pixel */ \
73 float xm[1000]; /* unfolded x coordinate of a reconstructed point on mirror */ \
74 float kx[1000]; /* reconstructed photon direction in x at emission */ \
75 float ky[1000]; /* reconstructed photon direction in y at emission */ \
76 float alpha[1000]; /* impact angle on photo-cathode [degrees] */ \
79 int_arrays = [
'channel',
'pixel',
'pulseHeight',
'sample',
'status',
'type',
'nx',
'ny',
80 'nxm',
'nym',
'nxe',
'nye',
'nys']
81 float_arrays = [
'time',
'timeErr',
'pulseWidth',
't0',
'wid0',
't1',
't_pdf',
'alpha',
82 'xd',
'yd',
'xm',
'kx',
'ky']
84 from ROOT
import TreeStruct
88 ''' Makes a flat ntuple '''
94 ''' initialize: open root file, construct ntuple '''
97 expNo = evtMetaData.obj().getExperiment()
98 runNo = evtMetaData.obj().
getRun()
99 exp_run =
'-e' +
'{:0=4d}'.format(expNo) +
'-r' +
'{:0=5d}'.format(runNo)
101 outName =
'out_data/timeResoNtuple' + exp_run +
'.root'
103 outName =
'out_mc/timeResoNtuple' + exp_run +
'-' + file_num +
'.root'
106 self.
file = ROOT.TFile(outName,
'recreate')
109 self.
bunchOffset = TH1F(
"bunchOffset",
"bunch offset", 100, -1.0, 1.0)
112 self.
h_cth_vs_p = TH2F(
"cth_vs_p",
"local cos #theta vs. p", 100, 0.0, 10.0,
117 self.
h_momentum = TH1F(
"momentum",
"momentum", 100, 0.0, 10.0)
120 self.
h_cth = TH1F(
"cos_theta",
"local cos #theta", 100, -1.0, 1.0)
121 self.
h_cth.SetXTitle(
"cos #theta")
123 self.
h_phi = TH1F(
"local_phi",
"local phi", 100, -math.pi, math.pi)
124 self.
h_phi.SetXTitle(
"local #phi")
126 self.
h_z = TH1F(
"local_z",
"local z", 100, -140.0, 140.0)
127 self.
h_z.SetXTitle(
"local z [cm]")
129 self.
h_x = TH1F(
"local_x",
"local x", 100, -23.0, 23.0)
130 self.
h_x.SetXTitle(
"local x [cm]")
132 self.
h_charge = TH1F(
"charge",
"charge", 3, -1.5, 1.5)
135 self.
h_poca_xy = TH2F(
"poca_xy",
"POCA distribution in x-y", 100, -1.0, 1.0,
140 self.
h_poca_z = TH1F(
"poca_z",
"POCA distribution in z", 100, -2.0, 2.0)
143 self.
h_hitsCDC = TH1F(
"cdc_hits",
"CDC hits", 100, 0.0, 100.0)
144 self.
h_hitsCDC.SetXTitle(
"number of CDC hits")
146 self.
h_Ecms = TH1F(
"Ecms",
"c.m.s. energy of muon", 300, 4.5, 6.0)
147 self.
h_Ecms.SetXTitle(
"E_{cm} [GeV/c]")
150 self.
tree = ROOT.TTree(
'tree',
'time resolution')
155 for key
in TreeStruct.__dict__.keys():
158 if isinstance(self.
data.__getattribute__(key), int):
160 if key
in int_arrays:
161 formstring =
'[nfot]/I'
162 elif key
in float_arrays:
163 formstring =
'[nfot]/F'
164 self.
tree.Branch(key, AddressOf(self.
data, key), key + formstring)
167 ''' sort PDF peaks according to their positions '''
169 py_list = [x
for x
in unsortedPeaks]
170 return sorted(py_list, key=
lambda x: (x.mean))
173 ''' make histogram of PDF peak positions for the first 20 tracks '''
178 h = TH2F(
'pdf' + str(self.
nhisto),
'muon PDF, itrk = ' + str(self.
data.itrk),
179 512, 0.0, 512.0, 1000, 0.0, 75.0)
180 h.SetXTitle(
'pixelID - 1')
181 h.SetYTitle(
'peak positions [ns]')
189 ''' returns c.m.s. energy of a particle '''
190 mom = tfit.getMomentum()
191 lorentzLab = TLorentzVector()
192 mass = chargedStable.getMass()
193 lorentzLab.SetXYZM(mom.X(), mom.Y(), mom.Z(), mass)
195 lorentzCms = T.labToCms(lorentzLab)
196 return [lorentzCms.Energy(), T.getCMSEnergy()/2]
199 ''' returns true if track fulfills selection criteria '''
201 if abs(self.
data.dEcms) > 0.1:
203 if abs(self.
data.poca_x) > 0.2:
205 if abs(self.
data.poca_y) > 0.2:
207 if abs(self.
data.poca_z) > 0.5:
212 ''' returns timo-of-flight of extrapolated track '''
214 extHits = track.getRelationsWith(
'ExtHits')
217 for extHit
in extHits:
218 if abs(extHit.getPdgCode()) != pdg:
220 if extHit.getDetectorID() != Belle2.Const.TOP:
222 if extHit.getCopyID() != slot:
224 if extHit.getStatus() == Belle2.EXT_ENTER:
226 elif extHit.getStatus() == Belle2.EXT_EXIT:
229 return (extEnter.getTOF() + extExit.getTOF()) / 2
233 ''' event processing '''
237 B2ERROR(
'no TOPRecBunch')
239 if not recBunch.isReconstructed():
244 self.
data.run = evtMetaData.getRun()
245 self.
data.offset = recBunch.getCurrentOffset()
246 self.
data.usedTrk = recBunch.getUsedTracks()
249 pdfs = track.getRelated(
'TOPPDFCollections')
252 self.
data.slot = pdfs.getModuleID()
253 momentum = pdfs.getAssociatedLocalMomentum()
254 position = pdfs.getAssociatedLocalHit()
255 self.
data.p = momentum.Mag()
256 self.
data.cth = momentum.CosTheta()
257 self.
data.phi = momentum.Phi()
258 self.
data.z = position.Z()
259 self.
data.x = position.X()
262 tfit = track.getTrackFitResultWithClosestMass(Belle2.Const.muon)
264 B2ERROR(
"No trackFitResult available")
266 self.
data.charge = tfit.getChargeSign()
267 pocaPosition = tfit.getPosition()
268 self.
data.poca_x = pocaPosition.X()
269 self.
data.poca_y = pocaPosition.Y()
270 self.
data.poca_z = pocaPosition.Z()
271 self.
data.hitsCDC = tfit.getHitPatternCDC().getNHits()
272 Ecms = self.
getEcms(tfit, Belle2.Const.muon)
273 self.
data.dEcms = Ecms[0] - Ecms[1]
277 topll = track.getRelated(
'TOPLikelihoods')
278 extHit = topll.getRelated(
'ExtHits')
279 timeZero = extHit.getRelated(
'TOPTimeZeros')
280 self.
data.rec_t0 = timeZero.getTime()
281 self.
data.valid_t0 = timeZero.isValid()
284 self.
data.valid_t0 = 0
298 pdf = pdfs.getHypothesisPDF(13)
300 B2ERROR(
"No PDF available for PDG = 13")
304 x0 = position.X() - momentum.X() / momentum.Y() * position.Y()
305 z0 = position.Z() - momentum.Z() / momentum.Y() * position.Y()
308 if digit.getModuleID() == self.
data.slot
and digit.getHitQuality() == 1:
313 self.
data.channel[k] = digit.getChannel()
314 self.
data.pixel[k] = digit.getPixelID()
315 self.
data.time[k] = digit.getTime()
316 self.
data.timeErr[k] = digit.getTimeError()
317 self.
data.pulseHeight[k] = digit.getPulseHeight()
318 self.
data.pulseWidth[k] = digit.getPulseWidth()
319 self.
data.sample[k] = digit.getModulo256Sample()
320 self.
data.status[k] = digit.getStatus()
321 peaks = pdf[digit.getPixelID() - 1]
324 self.
data.wid0[k] = 0
328 self.
data.t0[k] = sorted_peaks[0].mean
329 self.
data.wid0[k] = sorted_peaks[0].width
330 self.
data.t1[k] = self.
data.t0[k] + 100
332 self.
data.t1[k] = sorted_peaks[1].mean
333 self.
data.t_pdf[k] = 0
334 self.
data.type[k] = 0
347 self.
data.alpha[k] = 0
348 assocPDF = digit.getRelated(
'TOPAssociatedPDFs')
350 pik = assocPDF.getSinglePeak()
352 self.
data.t_pdf[k] = pik.position
353 self.
data.type[k] = pik.type
354 self.
data.nx[k] = pik.nx
355 self.
data.ny[k] = pik.ny
356 self.
data.nxm[k] = pik.nxm
357 self.
data.nym[k] = pik.nym
358 self.
data.nxe[k] = pik.nxe
359 self.
data.nye[k] = pik.nye
361 self.
data.nys[k] = int(pik.nye / 2)
363 self.
data.nys[k] = int((pik.nye + 1) / 2)
364 self.
data.xd[k] = pik.xd
365 self.
data.yd[k] = pik.yd
367 self.
data.xm[k] = x0 + pik.kxe / pik.kze * (130.0 - z0)
368 self.
data.kx[k] = pik.kxe
369 self.
data.ky[k] = pik.kye
370 self.
data.alpha[k] = math.degrees(math.acos(abs(pik.kzd)))
375 ''' terminate: close root file '''
386 main.add_module(
'RootInput')
389 main.add_module(
'TOPGeometryParInitializer')
392 main.add_module(
'TOPChannelMasker')
395 main.add_module(
'TOPPDFDebugger', pdgCodes=[13])
401 progress = register_module(
'Progress')
402 main.add_module(progress)