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 tu = mom[0] / mom[2]
126 tv = mom[1] / mom[2]
127 thetaU = math.atan(tu) * 180 / math.pi
128 thetaV = math.atan(tv) * 180 / math.pi
129
130 # Only look at primary particles -> check if the following is needed
131 # for mcp in truehit.getRelationsFrom("MCParticles"):
132 # if not mcp.hasStatus(1):
133 # reject = True
134
135 # Get instance of position estimator
137 clusterkind = cls.getKind()
138
139 # Clusterkinds 0,1,2,3 refer to all cases which can currently
140 # be corrected. Cases where a cluster pixel touches a sensor
141 # edge or contains pixel with varying vPitch are excluded here.
142 if clusterkind <= 3 and mom.Mag() > 0.02:
143
144 self.nclusters += 1
145
146 # Fill momentum and angles for clusterkind
147 self.hist_map_momentum[clusterkind].Fill(mom.Mag())
148 self.hist_map_theta_u[clusterkind].Fill(thetaU)
149 self.hist_map_theta_v[clusterkind].Fill(thetaV)
150 self.hist_map_clustercharge[clusterkind].Fill(cls.getCharge())
151
152 # Fill clusterkind=4 for all PXD sensors
153 self.hist_map_momentum[4].Fill(mom.Mag())
154 self.hist_map_theta_u[4].Fill(thetaU)
155 self.hist_map_theta_v[4].Fill(thetaV)
156 self.hist_map_clustercharge[4].Fill(cls.getCharge())
157
158 # Fill the histograms (mode=2)
159 mode = 2
160 pull_u = (truehit.getU() - cls.getU()) / cls.getUSigma()
161 pull_v = (truehit.getV() - cls.getV()) / cls.getVSigma()
162
163 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - cls.getU())
164 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - cls.getV())
165 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
166 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
167
168 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
169 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(truehit.getV() - cls.getV())
170 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
171 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(truehit.getV() - cls.getV())
172 else:
173 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(truehit.getV() - cls.getV())
174
175 shape_likelyhood = PositionEstimator.getShapeLikelyhood(cls, tu, tv)
176 if shape_likelyhood > 0:
177 self.nfound_shapes += 1
178
179 offset = PositionEstimator.getClusterOffset(cls, tu, tv)
180 if offset:
181 # Now, we can safely querry the correction
182 self.nfound_offset += 1
183
184 # We need to explicitely add a shift to the offsets
185 # This is not needed when working with PXDRecoHits
186 shiftU = sensor_info.getUCellPosition(cls.getUStart())
187 shiftV = sensor_info.getVCellPosition(cls.getVStart())
188
189 # Fill the histograms (mode=0)
190 mode = 0
191 pull_u = (truehit.getU() - shiftU - offset.getU()) / (math.sqrt(offset.getUSigma2()))
192 pull_v = (truehit.getV() - shiftV - offset.getV()) / (math.sqrt(offset.getVSigma2()))
193
194 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - shiftU - offset.getU())
195 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - shiftV - offset.getV())
196 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
197 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
198
199 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
200 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(
201 truehit.getV() - shiftV - offset.getV())
202 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
203 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(
204 truehit.getV() - shiftV - offset.getV())
205 else:
206 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(
207 truehit.getV() - shiftV - offset.getV())
208
209 # Fill the histograms (mode=1)
210 mode = 1
211 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - shiftU - offset.getU())
212 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - shiftV - offset.getV())
213 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
214 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
215
216 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
217 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(
218 truehit.getV() - shiftV - offset.getV())
219 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
220 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(
221 truehit.getV() - shiftV - offset.getV())
222 else:
223 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(
224 truehit.getV() - shiftV - offset.getV())
225
226 else:
227
228 # Fill the histograms (mode=1)
229 mode = 1
230 pull_u = (truehit.getU() - cls.getU()) / cls.getUSigma()
231 pull_v = (truehit.getV() - cls.getV()) / cls.getVSigma()
232
233 self.hist_map_residual_u[(clusterkind, mode)].Fill(truehit.getU() - cls.getU())
234 self.hist_map_residual_v[(clusterkind, mode)].Fill(truehit.getV() - cls.getV())
235 self.hist_map_residual_pull_u[(clusterkind, mode)].Fill(pull_u)
236 self.hist_map_residual_pull_v[(clusterkind, mode)].Fill(pull_v)
237
238 if thetaV >= self.binlimits[0][0] and thetaV < self.binlimits[0][1]:
239 self.hist_map_residual_v_special[(clusterkind, mode, 0)].Fill(truehit.getV() - cls.getV())
240 elif thetaV >= self.binlimits[1][0] and thetaV < self.binlimits[1][1]:
241 self.hist_map_residual_v_special[(clusterkind, mode, 1)].Fill(truehit.getV() - cls.getV())
242 else:
243 self.hist_map_residual_v_special[(clusterkind, mode, 2)].Fill(truehit.getV() - cls.getV())
244
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 245 of file test_cluster_position_estimator.py.

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

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: