98 """Receive signal at the start of event processing"""
100 self.mc_segment_lookup = Belle2.TrackFindingCDC.CDCMCSegment2DLookUp.getInstance()
101 self.mc_segment_pair_filter = Belle2.TrackFindingCDC.MCSegmentPairFilter()
102 self.segment_pair_fusion = Belle2.TrackFindingCDC.CDCAxialStereoFusion
108 def pick(self, segment_pair_relation):
109 """Select segment pairs with 4 or more hit in each segments and a matching primary MC particle"""
110 mc_segment_lookup = self.mc_segment_lookup
111 start_segment = segment_pair_relation.getStartSegment()
112 end_segment = segment_pair_relation.getEndSegment()
113 mc_particle = mc_segment_lookup.getMCParticle(start_segment)
114 return (mc_particle and
115 is_primary(mc_particle) and
116 start_segment.size() > 3 and
117 end_segment.size() > 3)
119 def peel(self, segment_pair_relation):
120 """Aggregate the track and MC information for track segment-pair analysis"""
121 crops = self.peel_target(segment_pair_relation)
122 crops.update(self.peel_mc(segment_pair_relation))
123 crops.update(self.peel_fit(segment_pair_relation))
126 def peel_target(self, segment_pair_relation):
127 """Create a dictionary of MC-truth (weight,decision) pairs"""
128 mc_weight = self.mc_segment_pair_filter(segment_pair_relation)
129 mc_decision = np.isfinite(mc_weight) # Filters for nan
133 mc_decision=mc_decision,
136 def peel_mc(self, segment_pair_relation):
137 """Create a dictionary of MC-truth (curvature,tanlambda) pairs"""
138 mc_segment_lookup = self.mc_segment_lookup
140 end_segment = segment_pair_relation.getEndSegment()
142 # Take the fit best at the middle of the segment pair
143 # mc_particle = mc_segment_lookup.getMCParticle(end_segment)
144 fit3d_truth = mc_segment_lookup.getTrajectory3D(end_segment)
147 curvature_truth=fit3d_truth.getCurvatureXY(),
148 tan_lambda_truth=fit3d_truth.getTanLambda(),
151 def peel_fit(self, segment_pair_relation):
152 """Create a dictionary of track-segment-fit information"""
153 fitless_crops = self.peel_fitless(segment_pair_relation)
155 select_fitless = fitless_crops["select_fitless"]
158 self.fit(segment_pair_relation)
159 fit3d = segment_pair_relation.getTrajectory3D()
164 chi2 = fit3d.getChi2()
167 curvature_estimate = fit3d.getCurvatureXY()
168 curvature_variance = fit3d.getLocalVariance(i_curv)
170 tan_lambda_estimate = fit3d.getTanLambda()
171 tan_lambda_variance = fit3d.getLocalVariance(i_tan_lambda)
175 p_value = prob(chi2, ndf)
180 curvature_estimate = nan
181 curvature_variance = nan
183 tan_lambda_estimate = nan
184 tan_lambda_variance = nan
191 curvature_estimate=curvature_estimate,
192 curvature_variance=curvature_variance,
194 tan_lambda_estimate=tan_lambda_estimate,
195 tan_lambda_variance=tan_lambda_variance,
203 crops["select"] = self.select(crops)
205 crops["select"] = False
207 crops.update(fitless_crops)
211 def peel_fitless(self, segment_pair_relation):
212 """Create a dictionary of track-segments-without-fit information"""
213 # Try to make some judgements without executing the common fit.
215 start_segment = segment_pair_relation.getStartSegment()
216 end_segment = segment_pair_relation.getEndSegment()
218 start_fit2d = start_segment.getTrajectory2D()
219 end_fit2d = end_segment.getTrajectory2D()
221 start_superlayer_id = start_segment.getISuperLayer()
222 end_superlayer_id = end_segment.getISuperLayer()
224 sorted_superlayer_ids = sorted([start_superlayer_id, end_superlayer_id])
226 superlayer_id_pair = 10.0 * sorted_superlayer_ids[1] + sorted_superlayer_ids[0]
228 fitless_crops = dict(
229 start_superlayer_id=start_superlayer_id,
230 end_superlayer_id=end_superlayer_id,
231 superlayer_id_pair=superlayer_id_pair,
233 start_size=start_segment.size(),
234 end_size=end_segment.size(),
236 start_curvature_estimate=start_fit2d.getCurvature(),
237 end_curvature_estimate=end_fit2d.getCurvature(),
239 delta_phi=segment_pair_relation.computeDeltaPhiAtSuperLayerBound(),
240 is_coaligned=segment_pair_relation.computeIsCoaligned(),
242 start_is_before_end=segment_pair_relation.computeStartIsBeforeEnd(),
243 end_is_after_start=segment_pair_relation.computeEndIsAfterStart(),
246 fitless_crops["select_fitless"] = self.select_fitless(fitless_crops)
258 def select_fitless(self, fitless_crops):
259 """Selection of track-segments-without-fit"""
260 delta_phi = fitless_crops["delta_phi"]
261 start_is_before_end = fitless_crops["start_is_before_end"]
262 end_is_after_start = fitless_crops["end_is_after_start"]
263 is_after_select = (abs(start_is_before_end) < self.is_after_cut_value) & (abs(end_is_after_start) < self.is_after_cut_value)
264 return (abs(delta_phi) < self.delta_phi_cut_value) & is_after_select
328 def print_signal_number(self, crops, tdirectory, **kwds):
329 """Print diagnostic information about the track-segment-pair selection"""
330 info = get_logger().info
332 # start_superlayer_ids = crops["start_superlayer_id"]
333 # end_superlayer_ids = crops["end_superlayer_id"]
335 superlayer_id_pair = crops["superlayer_id_pair"]
336 info("Number of pairs in superlayers %s : %s", np.unique(superlayer_id_pair), len(superlayer_id_pair))
338 mc_decisions = crops["mc_decision"]
339 n = len(mc_decisions)
340 n_signal = np.sum(mc_decisions)
341 n_background = n - n_signal
342 info("#Signal : %s", n_signal)
343 info("#Background : %s", n_background)
345 fitless_selections = np.nonzero(crops["select_fitless"])
346 info("#Signal after precut : %s", np.sum(mc_decisions[fitless_selections]))
347 info("#Background after precut : %s", np.sum(1 - mc_decisions[fitless_selections]))