Belle II Software development
PXDPositionEstimation Class Reference
Inheritance diagram for PXDPositionEstimation:

Public Member Functions

def initialize (self)
 
def event (self)
 
def terminate (self)
 

Public Attributes

 nclusters
 Counter for all clusters.
 
 nfound_shapes
 Counter for cluster where shape likelyhood was found in payload.
 
 nfound_offset
 Counter for clusters where position correction was found in payload.
 
 rfile
 Output file to store all plots.
 
 hist_map_momentum
 Histograms for true particle momenta.
 
 hist_map_theta_u
 Histograms for true particle angle thetaU.
 
 hist_map_theta_v
 Histograms for true particle angle thetaV.
 
 hist_map_clustercharge
 Histograms for cluster charge related to particle.
 
 hist_map_residual_u
 Histograms for u residuals.
 
 hist_map_residual_v
 Histograms for v residuals.
 
 hist_map_residual_v_special
 Histograms for v residuals for smaller thetaV range.
 
 hist_map_residual_pull_u
 Histograms for u residual pulls.
 
 hist_map_residual_pull_v
 Histograms for v residual pulls.
 
 binlimits
 ThetaV angle ranges for v residuals.
 

Detailed Description

Histogram the difference position residuals and pulls between clusters and truehits.

Definition at line 26 of file test_cluster_position_estimator.py.

Member Function Documentation

◆ event()

def event (   self)
Fill the residual and pull histograms

Definition at line 106 of file test_cluster_position_estimator.py.

106 def event(self):
107 """Fill the residual and pull histograms"""
108
109 # Get truehits
110 truehits = Belle2.PyStoreArray("PXDTrueHits")
111
112 for truehit in truehits:
113 if isinstance(truehit, Belle2.PXDTrueHit):
114 sensor_info = Belle2.VXD.GeoCache.getInstance().getSensorInfo(truehit.getSensorID())
115 clusters = truehit.getRelationsFrom("PXDClusters")
116
117 # now check if we find a cluster
118 for j, cls in enumerate(clusters):
119 # we ignore all clusters where less then 100 electrons come from
120 # our truehit
121 if clusters.weight(j) < 100:
122 continue
123
124 mom = truehit.getMomentum()
125 abs_momentum = mom.R()
126 tu = mom.X() / mom.Z()
127 tv = mom.Y() / mom.Z()
128 thetaU = math.atan(tu) * 180 / math.pi
129 thetaV = math.atan(tv) * 180 / math.pi
130
131 # Get instance of position estimator
133 clusterkind = cls.getKind()
134
135 # Clusterkinds 0,1,2,3 refer to all cases which can currently
136 # be corrected. Cases where a cluster pixel touches a sensor
137 # edge or contains pixel with varying vPitch are excluded here.
138 if clusterkind <= 3 and abs_momentum > 0.02:
139
140 self.nclusters += 1
141
142 # Fill momentum and angles for clusterkind
143 self.hist_map_momentum[clusterkind].Fill(abs_momentum)
144 self.hist_map_theta_u[clusterkind].Fill(thetaU)
145 self.hist_map_theta_v[clusterkind].Fill(thetaV)
146 self.hist_map_clustercharge[clusterkind].Fill(cls.getCharge())
147
148 # Fill clusterkind=4 for all PXD sensors
149 self.hist_map_momentum[4].Fill(abs_momentum)
150 self.hist_map_theta_u[4].Fill(thetaU)
151 self.hist_map_theta_v[4].Fill(thetaV)
152 self.hist_map_clustercharge[4].Fill(cls.getCharge())
153
154 # Fill the histograms (mode=2)
155 mode = 2
156 pull_u = (truehit.getU() - cls.getU()) / cls.getUSigma()
157 pull_v = (truehit.getV() - cls.getV()) / cls.getVSigma()
158
159 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - cls.getU())
160 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - cls.getV())
161 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
162 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
163
164 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
165 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(truehit.getV() - cls.getV())
166 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
167 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(truehit.getV() - cls.getV())
168 else:
169 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(truehit.getV() - cls.getV())
170
171 shape_likelyhood = PositionEstimator.getShapeLikelyhood(cls, tu, tv)
172 if shape_likelyhood > 0:
173 self.nfound_shapes += 1
174
175 offset = PositionEstimator.getClusterOffset(cls, tu, tv)
176 if offset:
177 # Now, we can safely query the correction
178 self.nfound_offset += 1
179
180 # We need to explicitly add a shift to the offsets
181 # This is not needed when working with PXDRecoHits
182 shiftU = sensor_info.getUCellPosition(cls.getUStart())
183 shiftV = sensor_info.getVCellPosition(cls.getVStart())
184
185 # Fill the histograms (mode=0)
186 mode = 0
187 pull_u = (truehit.getU() - shiftU - offset.getU()) / (math.sqrt(offset.getUSigma2()))
188 pull_v = (truehit.getV() - shiftV - offset.getV()) / (math.sqrt(offset.getVSigma2()))
189
190 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - shiftU - offset.getU())
191 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - shiftV - offset.getV())
192 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
193 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
194
195 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
196 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(
197 truehit.getV() - shiftV - offset.getV())
198 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
199 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(
200 truehit.getV() - shiftV - offset.getV())
201 else:
202 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(
203 truehit.getV() - shiftV - offset.getV())
204
205 # Fill the histograms (mode=1)
206 mode = 1
207 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - shiftU - offset.getU())
208 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - shiftV - offset.getV())
209 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
210 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
211
212 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
213 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(
214 truehit.getV() - shiftV - offset.getV())
215 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
216 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(
217 truehit.getV() - shiftV - offset.getV())
218 else:
219 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(
220 truehit.getV() - shiftV - offset.getV())
221
222 else:
223
224 # Fill the histograms (mode=1)
225 mode = 1
226 pull_u = (truehit.getU() - cls.getU()) / cls.getUSigma()
227 pull_v = (truehit.getV() - cls.getV()) / cls.getVSigma()
228
229 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - cls.getU())
230 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - cls.getV())
231 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
232 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
233
234 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
235 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(truehit.getV() - cls.getV())
236 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
237 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(truehit.getV() - cls.getV())
238 else:
239 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(truehit.getV() - cls.getV())
240
Class PXDTrueHit - Records of tracks that either enter or leave the sensitive volume.
Definition: PXDTrueHit.h:31
static PXDClusterPositionEstimator & getInstance()
Main (and only) way to access the PXDClusterPositionEstimator.
A (simplified) python wrapper for StoreArray.
Definition: PyStoreArray.h:72
static GeoCache & getInstance()
Return a reference to the singleton instance.
Definition: GeoCache.cc:214

◆ initialize()

def initialize (   self)
Create histograms for pulls and residuals

Definition at line 31 of file test_cluster_position_estimator.py.

31 def initialize(self):
32 """
33 Create histograms for pulls and residuals
34 """
35
36
37 self.nclusters = 0
38
39 self.nfound_shapes = 0
40
41 self.nfound_offset = 0
42
43 # Let's create a root file to store all profiles
44
45 self.rfile = ROOT.TFile("PXDPositionEstimation.root", "RECREATE")
46 self.rfile.cd()
47
48
49 self.hist_map_momentum = {}
50
51 self.hist_map_theta_u = {}
52
53 self.hist_map_theta_v = {}
54
55 self.hist_map_clustercharge = {}
56
57 # Loop over clusterkinds (=4 means 'all' kinds)
58 for kind in range(5):
59 self.hist_map_momentum[kind] = ROOT.TH1F(f"hist_momentum_kind_{kind:d}",
60 f'Particle momentum kind={kind:d}', 5000, 0.0, 10.0)
61 self.hist_map_theta_u[kind] = ROOT.TH1F(f"hist_theta_u_kind_{kind:d}",
62 f'Particle angle thetaU kind={kind:d}', 180, -90, +90)
63 self.hist_map_theta_v[kind] = ROOT.TH1F(f"hist_theta_v_kind_{kind:d}",
64 f'Particle angle thetaV kind={kind:d}', 180, -90, +90)
65 self.hist_map_clustercharge[kind] = ROOT.TH1F(f"hist_clustercharge_kind_{kind:d}",
66 f'Cluster charge kind={kind:d}', 255, 0.0, 255.0)
67
68
69 self.hist_map_residual_u = {}
70
71 self.hist_map_residual_v = {}
72
73 self.hist_map_residual_v_special = {}
74
75 self.hist_map_residual_pull_u = {}
76
77 self.hist_map_residual_pull_v = {}
78
79 for kind in range(4):
80 for mode in range(3):
81 self.hist_map_residual_u[(kind, mode)] = ROOT.TH1F(f'hist_map_residual_u_kind_{kind:d}_mode_{mode:d}',
82 f'PXD residual U kind={kind:d} mode={mode:d}',
83 400, -0.007, +0.007)
84 self.hist_map_residual_v[(kind, mode)] = ROOT.TH1F(f'hist_map_residual_v_kind_{kind:d}_mode_{mode:d}',
85 f'PXD residual V kind={kind:d} mode={mode:d}',
86 400, -0.007, +0.007)
87 self.hist_map_residual_pull_u[(kind, mode)] = ROOT.TH1F(f'hist_map_residual_pull_u_kind_{kind:d}_mode_{mode:d}',
88 f'PXD residual pull U kind={kind:d} mode={mode:d}',
89 200, -10, +10)
90 self.hist_map_residual_pull_v[(kind, mode)] = ROOT.TH1F(f'hist_map_residual_pull_v_kind_{kind:d}_mode_{mode:d}',
91 f'PXD residual pull V kind={kind:d} mode={mode:d}',
92 200, -10, +10)
93
94
95 self.binlimits = {}
96 self.binlimits[0] = (-90, -30)
97 self.binlimits[1] = (-30, +30)
98 self.binlimits[2] = (+30, +90)
99
100 for bin in range(3):
101 name = f'hist_map_residual_v_kind_{kind:d}_mode_{mode:d}_special_{bin:d}'
102 title = f'PXD residual V kind={kind:d} mode={mode:d} {self.binlimits[bin][0]:.0f}' + \
103 f'<thetaV<{self.binlimits[bin][1]:.0f}'
104 self.hist_map_residual_v_special[(kind, mode, bin)] = ROOT.TH1F(name, title, 400, -0.007, +0.007)
105

◆ terminate()

def terminate (   self)
Format and write all histograms and plot them

Definition at line 241 of file test_cluster_position_estimator.py.

241 def terminate(self):
242 """
243 Format and write all histograms and plot them
244 """
245
246 for kind in range(5):
247 self.hist_map_momentum[kind].SetLineWidth(2)
248 self.hist_map_momentum[kind].SetXTitle('momentum / GeV')
249 self.hist_map_momentum[kind].SetYTitle('number of particles')
250
251 self.hist_map_theta_u[kind].SetLineWidth(2)
252 self.hist_map_theta_u[kind].SetXTitle('thetaU / degree')
253 self.hist_map_theta_u[kind].SetYTitle('number of particles')
254
255 self.hist_map_theta_v[kind].SetLineWidth(2)
256 self.hist_map_theta_v[kind].SetXTitle('thetaV / degree')
257 self.hist_map_theta_v[kind].SetYTitle('number of particles')
258
259 self.hist_map_clustercharge[kind].SetLineWidth(2)
260 self.hist_map_clustercharge[kind].SetXTitle('cluster charge / ADU')
261 self.hist_map_clustercharge[kind].SetYTitle('number of particles')
262
263 for kind in range(4):
264 for mode in range(3):
265 self.hist_map_residual_pull_u[(kind, mode)].SetLineWidth(2)
266 self.hist_map_residual_pull_u[(kind, mode)].SetXTitle('pull u')
267 self.hist_map_residual_pull_u[(kind, mode)].SetYTitle('number of particles')
268
269 self.hist_map_residual_pull_v[(kind, mode)].SetLineWidth(2)
270 self.hist_map_residual_pull_v[(kind, mode)].SetXTitle('pull v')
271 self.hist_map_residual_pull_v[(kind, mode)].SetYTitle('number of particles')
272
273 self.hist_map_residual_u[(kind, mode)].SetLineWidth(2)
274 self.hist_map_residual_u[(kind, mode)].SetXTitle('residuals u / cm')
275 self.hist_map_residual_u[(kind, mode)].SetYTitle('number of particles')
276
277 self.hist_map_residual_v[(kind, mode)].SetLineWidth(2)
278 self.hist_map_residual_v[(kind, mode)].SetXTitle('residuals v / cm')
279 self.hist_map_residual_v[(kind, mode)].SetYTitle('number of particles')
280
281 for bin in range(3):
282 self.hist_map_residual_v_special[(kind, mode, bin)].SetLineWidth(2)
283 self.hist_map_residual_v_special[(kind, mode, bin)].SetXTitle('residuals v / cm')
284 self.hist_map_residual_v_special[(kind, mode, bin)].SetYTitle('number of particles')
285
286 hcoverage = ROOT.TH1F("hist_coverage", 'Coverage of corrections', 2, 1, 2)
287 hcoverage.SetBinContent(1, 100.0 * float(self.nfound_offset / self.nclusters))
288 hcoverage.SetBinContent(2, 100.0 * float(self.nfound_shapes / self.nclusters))
289 hcoverage.SetLineWidth(2)
290 hcoverage.SetYTitle('coverage / %')
291 hcoverage.SetTitle('Coverage of cluster shape corrections')
292
293 print(f"Coverage of cluster shape corrections is {100.0 * float(self.nfound_offset / self.nclusters):.2f}% ")
294 print(f"Coverage of cluster shape likelyhoods is {100.0 * float(self.nfound_shapes / self.nclusters):.2f}% ")
295
296 self.rfile.Write()
297 self.rfile.Close()
298
299

Member Data Documentation

◆ binlimits

binlimits

ThetaV angle ranges for v residuals.

Definition at line 95 of file test_cluster_position_estimator.py.

◆ hist_map_clustercharge

hist_map_clustercharge

Histograms for cluster charge related to particle.

Definition at line 55 of file test_cluster_position_estimator.py.

◆ hist_map_momentum

hist_map_momentum

Histograms for true particle momenta.

Definition at line 49 of file test_cluster_position_estimator.py.

◆ hist_map_residual_pull_u

hist_map_residual_pull_u

Histograms for u residual pulls.

Definition at line 75 of file test_cluster_position_estimator.py.

◆ hist_map_residual_pull_v

hist_map_residual_pull_v

Histograms for v residual pulls.

Definition at line 77 of file test_cluster_position_estimator.py.

◆ hist_map_residual_u

hist_map_residual_u

Histograms for u residuals.

Definition at line 69 of file test_cluster_position_estimator.py.

◆ hist_map_residual_v

hist_map_residual_v

Histograms for v residuals.

Definition at line 71 of file test_cluster_position_estimator.py.

◆ hist_map_residual_v_special

hist_map_residual_v_special

Histograms for v residuals for smaller thetaV range.

Definition at line 73 of file test_cluster_position_estimator.py.

◆ hist_map_theta_u

hist_map_theta_u

Histograms for true particle angle thetaU.

Definition at line 51 of file test_cluster_position_estimator.py.

◆ hist_map_theta_v

hist_map_theta_v

Histograms for true particle angle thetaV.

Definition at line 53 of file test_cluster_position_estimator.py.

◆ nclusters

nclusters

Counter for all clusters.

Definition at line 37 of file test_cluster_position_estimator.py.

◆ nfound_offset

nfound_offset

Counter for clusters where position correction was found in payload.

Definition at line 41 of file test_cluster_position_estimator.py.

◆ nfound_shapes

nfound_shapes

Counter for cluster where shape likelyhood was found in payload.

Definition at line 39 of file test_cluster_position_estimator.py.

◆ rfile

rfile

Output file to store all plots.

Definition at line 45 of file test_cluster_position_estimator.py.


The documentation for this class was generated from the following file: