Belle II Software  release-05-02-19
segmentPairCreationValidation.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 import os
5 import sys
6 import numpy as np
7 
8 import basf2
9 
10 from ROOT import gSystem
11 gSystem.Load('libtracking')
12 gSystem.Load('libtrackFindingCDC')
13 
14 from ROOT import Belle2 # make Belle2 namespace available
15 from ROOT import std
16 
17 from tracking.utilities import NonstrictChoices
18 from tracking.validation.utilities import prob, is_primary
19 from tracking.validation.plot import ValidationPlot
20 
21 import tracking.harvest.harvesting as harvesting
22 import tracking.harvest.refiners as refiners
23 import tracking.metamodules as metamodules
24 
25 from tracking.run.event_generation import StandardEventGenerationRun
26 from tracking.run.mixins import BrowseTFileOnTerminateRunMixin
27 
28 import logging
29 
30 
31 def get_logger():
32  return logging.getLogger(__name__)
33 
34 
35 CONTACT = "oliver.frost@desy.de"
36 
37 
39  """Generate, postprocess and inspect MC events for track segment-pair validation"""
40 
41  segment_finder_module = basf2.register_module("TFCDC_SegmentCreatorMCTruth")
42  segment_finder_module.param({"MinCDCHits": 4})
43 
44 
45  segment_pair_finder_module = basf2.register_module("TFCDC_TrackFinderSegmentPairAutomaton")
46  segment_pair_finder_module.param({
47  "WriteSegmentPairs": True,
48  "SegmentPairFilter": "all",
49  "SegmentPairRelationFilter": "none",
50  })
51 
52 
53  py_profile = True
54 
55  output_file_name = "SegmentPairCreationValidation.root" # Specification for BrowseTFileOnTerminateRunMixin
56 
57  def create_argument_parser(self, **kwds):
58  """Convert command-line arguments to basf2 argument list"""
59  argument_parser = super(SegmentPairCreationValidationRun, self).create_argument_parser(**kwds)
60  return argument_parser
61 
62  def create_path(self):
63  """
64  Sets up a path that plays back pregenerated events or generates events
65  based on the properties in the base class.
66  """
67  main_path = super(SegmentPairCreationValidationRun, self).create_path()
68 
69  segment_finder_module = self.get_basf2_module(self.segment_finder_module)
70  main_path.add_module(segment_finder_module)
71 
72  main_path.add_module("TFCDC_SegmentFitter")
73 
74  segment_pair_finder_module = self.get_basf2_module(self.segment_pair_finder_module)
75  main_path.add_module(segment_pair_finder_module)
76 
77  # main_path.add_module(AxialStereoPairFitterModule())
78  validation_module = SegmentPairCreationValidationModule(output_file_name=self.output_file_name)
79  if self.py_profile:
80  main_path.add_module(metamodules.PyProfilingModule(validation_module))
81  else:
82  main_path.add_module(validation_module)
83 
84  return main_path
85 
86 
87 class SegmentPairCreationValidationModule(harvesting.HarvestingModule):
88 
89  """Module to collect information about the generated segments and compose validation plots on terminate."""
90 
91  def __init__(self, output_file_name):
92  """Constructor"""
93  super(SegmentPairCreationValidationModule, self).__init__(foreach="CDCSegmentPairVector",
94  output_file_name=output_file_name)
95 
96  self.mc_segment_lookup = None
97 
99 
101 
102  def initialize(self):
103  """Receive signal at the start of event processing"""
104  super(SegmentPairCreationValidationModule, self).initialize()
108 
109  def prepare(self):
110  """Initialize the MC-hit lookup method"""
112 
113  def pick(self, segment_pair_relation):
114  """Select segment pairs with 4 or more hit in each segments and a matching primary MC particle"""
115  mc_segment_lookup = self.mc_segment_lookup
116  start_segment = segment_pair_relation.getStartSegment()
117  end_segment = segment_pair_relation.getEndSegment()
118  mc_particle = mc_segment_lookup.getMCParticle(start_segment)
119  return (mc_particle and
120  is_primary(mc_particle) and
121  start_segment.size() > 3 and
122  end_segment.size() > 3)
123 
124  def peel(self, segment_pair_relation):
125  """Aggregate the track and MC information for track segment-pair analysis"""
126  crops = self.peel_target(segment_pair_relation)
127  crops.update(self.peel_mc(segment_pair_relation))
128  crops.update(self.peel_fit(segment_pair_relation))
129  return crops
130 
131  def peel_target(self, segment_pair_relation):
132  """Create a dictionary of MC-truth (weight,decision) pairs"""
133  mc_weight = self.mc_segment_pair_filter(segment_pair_relation)
134  mc_decision = np.isfinite(mc_weight) # Filters for nan
135 
136  return dict(
137  mc_weight=mc_weight,
138  mc_decision=mc_decision,
139  )
140 
141  def peel_mc(self, segment_pair_relation):
142  """Create a dictionary of MC-truth (curvature,tanlambda) pairs"""
143  mc_segment_lookup = self.mc_segment_lookup
144 
145  end_segment = segment_pair_relation.getEndSegment()
146 
147  # Take the fit best at the middle of the segment pair
148  mc_particle = mc_segment_lookup.getMCParticle(end_segment)
149  fit3d_truth = mc_segment_lookup.getTrajectory3D(end_segment)
150 
151  return dict(
152  curvature_truth=fit3d_truth.getCurvatureXY(),
153  tan_lambda_truth=fit3d_truth.getTanLambda(),
154  )
155 
156  def peel_fit(self, segment_pair_relation):
157  """Create a dictionary of track-segment-fit information"""
158  fitless_crops = self.peel_fitless(segment_pair_relation)
159 
160  select_fitless = fitless_crops["select_fitless"]
161  if select_fitless:
162  # Now fit
163  self.fit(segment_pair_relation)
164  fit3d = segment_pair_relation.getTrajectory3D()
165 
166  i_curv = 0
167  i_tan_lambda = 3
168 
169  chi2 = fit3d.getChi2()
170  ndf = fit3d.getNDF()
171 
172  curvature_estimate = fit3d.getCurvatureXY()
173  curvature_variance = fit3d.getLocalVariance(i_curv)
174 
175  tan_lambda_estimate = fit3d.getTanLambda()
176  tan_lambda_variance = fit3d.getLocalVariance(i_tan_lambda)
177 
178  chi2 = chi2
179  ndf = ndf
180  p_value = prob(chi2, ndf)
181  select = True
182 
183  else:
184  nan = float('nan')
185  curvature_estimate = nan
186  curvature_variance = nan
187 
188  tan_lambda_estimate = nan
189  tan_lambda_variance = nan
190 
191  chi2 = nan
192  ndf = nan
193  p_value = nan
194 
195  crops = dict(
196  curvature_estimate=curvature_estimate,
197  curvature_variance=curvature_variance,
198 
199  tan_lambda_estimate=tan_lambda_estimate,
200  tan_lambda_variance=tan_lambda_variance,
201 
202  chi2=chi2,
203  ndf=ndf,
204  p_value=p_value,
205  )
206 
207  if select_fitless:
208  crops["select"] = self.select(crops)
209  else:
210  crops["select"] = False
211 
212  crops.update(fitless_crops)
213 
214  return crops
215 
216  def peel_fitless(self, segment_pair_relation):
217  """Create a dictionary of track-segments-without-fit information"""
218  # Try to make some judgements without executing the common fit.
219  mc_segment_lookup = self.mc_segment_lookup
220 
221  start_segment = segment_pair_relation.getStartSegment()
222  end_segment = segment_pair_relation.getEndSegment()
223 
224  start_fit2d = start_segment.getTrajectory2D()
225  end_fit2d = end_segment.getTrajectory2D()
226 
227  start_superlayer_id = start_segment.getISuperLayer()
228  end_superlayer_id = end_segment.getISuperLayer()
229 
230  sorted_superlayer_ids = sorted([start_superlayer_id, end_superlayer_id])
231 
232  superlayer_id_pair = 10.0 * sorted_superlayer_ids[1] + sorted_superlayer_ids[0]
233 
234  fitless_crops = dict(
235  start_superlayer_id=start_superlayer_id,
236  end_superlayer_id=end_superlayer_id,
237  superlayer_id_pair=superlayer_id_pair,
238 
239  start_size=start_segment.size(),
240  end_size=end_segment.size(),
241 
242  start_curvature_estimate=start_fit2d.getCurvature(),
243  end_curvature_estimate=end_fit2d.getCurvature(),
244 
245  delta_phi=segment_pair_relation.computeDeltaPhiAtSuperLayerBound(),
246  is_coaligned=segment_pair_relation.computeIsCoaligned(),
247 
248  start_is_before_end=segment_pair_relation.computeStartIsBeforeEnd(),
249  end_is_after_start=segment_pair_relation.computeEndIsAfterStart(),
250  )
251 
252  fitless_crops["select_fitless"] = self.select_fitless(fitless_crops)
253  return fitless_crops
254 
255  def fit(self, segment_pair_relation):
256  """Fit the segment pair"""
257  self.segment_pair_fusion.reconstructFuseTrajectories(segment_pair_relation, True)
258 
259 
260  delta_phi_cut_value = 1.0
261 
262  is_after_cut_value = 1.0
263 
264  def select_fitless(self, fitless_crops):
265  """Selection of track-segments-without-fit"""
266  delta_phi = fitless_crops["delta_phi"]
267  start_is_before_end = fitless_crops["start_is_before_end"]
268  end_is_after_start = fitless_crops["end_is_after_start"]
269  is_after_select = (abs(start_is_before_end) < self.is_after_cut_value) & (abs(end_is_after_start) < self.is_after_cut_value)
270  return (abs(delta_phi) < self.delta_phi_cut_value) & is_after_select
271 
272  def select(self, crops):
273  """Select every track-segment-pair"""
274  return True
275 
276  # Refiners to be executed at the end of the harvesting / termination of the module
277 
278  save_histograms = refiners.save_histograms(outlier_z_score=5.0, allow_discrete=True)
279 
280  save_tree = refiners.save_tree()
281 
282  # Investigate the preselection
283 
284  save_fitless_selection_variables_histograms = refiners.save_histograms(
285  select=["mc_decision", "delta_phi", "start_is_before_end", "end_is_after_start", "is_coaligned"],
286  outlier_z_score=5.0,
287  allow_discrete=True,
288  stackby="mc_decision",
289  folder_name="fitless_selection_variables",
290  )
291 
292 
293  save_view_is_after_cut_histograms = refiners.save_histograms(
294  select=["mc_decision", "start_is_before_end", "end_is_after_start"],
295  lower_bound=-is_after_cut_value,
296  upper_bound=is_after_cut_value,
297  stackby="mc_decision",
298  folder_name="view_fitless_cuts",
299  )
300 
301 
302  save_view_delta_phi_cut_histograms = refiners.save_histograms(
303  select=["mc_decision", "delta_phi"],
304  lower_bound=-delta_phi_cut_value,
305  upper_bound=delta_phi_cut_value,
306  stackby="mc_decision",
307  folder_name="view_fitless_cuts",
308  )
309 
310  # Investigate the main selection
311 
312  save_selection_variables_after_fitless_selection_histograms = refiners.save_histograms(
313  select=["mc_decision", "chi2", "ndf", "p_value"],
314  outlier_z_score=5.0,
315  allow_discrete=True,
316  stackby="mc_decision",
317  folder_name="selection_variables_after_fitless_selection",
318  filter_on="select_fitless",
319  )
320 
321  # TODO: Is this interesting enough to keep it.
322 
323  save_p_value_over_curvature_profile = refiners.save_profiles(
324  select={"p_value": "p-value", "curvature_truth": "true curvature"},
325  y="p-value",
326  folder_name="selection_variables_after_fitless_selection",
327  title=r"$p$-value versus true curvature after fitless selection",
328  filter_on="select_fitless",
329  )
330 
331  # ! @cond Doxygen_Suppress
332  @refiners.context(groupby=[None, "superlayer_id_pair"], exclude_groupby=False)
333  # ! @endcond
334  def print_signal_number(self, crops, tdirectory, **kwds):
335  """Print diagnostic information about the track-segment-pair selection"""
336  info = get_logger().info
337 
338  start_superlayer_ids = crops["start_superlayer_id"]
339  end_superlayer_ids = crops["end_superlayer_id"]
340 
341  superlayer_id_pair = crops["superlayer_id_pair"]
342  info("Number of pairs in superlayers %s : %s", np.unique(superlayer_id_pair), len(superlayer_id_pair))
343 
344  mc_decisions = crops["mc_decision"]
345  n = len(mc_decisions)
346  n_signal = np.sum(mc_decisions)
347  n_background = n - n_signal
348  info("#Signal : %s", n_signal)
349  info("#Background : %s", n_background)
350 
351  fitless_selections = np.nonzero(crops["select_fitless"])
352  info("#Signal after precut : %s", np.sum(mc_decisions[fitless_selections]))
353  info("#Background after precut : %s", np.sum(1 - mc_decisions[fitless_selections]))
354 
355 
356 def main():
358  run.configure_and_execute_from_commandline()
359 
360 
361 if __name__ == "__main__":
362  logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(levelname)s:%(message)s')
363  main()
segmentPairCreationValidation.SegmentPairCreationValidationRun.create_path
def create_path(self)
Definition: segmentPairCreationValidation.py:62
segmentPairCreationValidation.SegmentPairCreationValidationModule.peel
def peel(self, segment_pair_relation)
Definition: segmentPairCreationValidation.py:124
segmentPairCreationValidation.SegmentPairCreationValidationModule.peel_fit
def peel_fit(self, segment_pair_relation)
Definition: segmentPairCreationValidation.py:156
tracking.run.mixins
Definition: mixins.py:1
tracking.run.mixins.BrowseTFileOnTerminateRunMixin
Definition: mixins.py:50
tracking.harvest.refiners
Definition: refiners.py:1
segmentPairCreationValidation.SegmentPairCreationValidationModule.peel_target
def peel_target(self, segment_pair_relation)
Definition: segmentPairCreationValidation.py:131
segmentPairCreationValidation.SegmentPairCreationValidationRun.segment_finder_module
segment_finder_module
Use the SegmentFinderFacetAutomaton for track-segment creation with MC truth-matching.
Definition: segmentPairCreationValidation.py:41
tracking.utilities
Definition: utilities.py:1
segmentPairCreationValidation.SegmentPairCreationValidationRun
Definition: segmentPairCreationValidation.py:38
segmentPairCreationValidation.SegmentPairCreationValidationModule.is_after_cut_value
float is_after_cut_value
default selection for the ordering of the segment pair
Definition: segmentPairCreationValidation.py:262
segmentPairCreationValidation.SegmentPairCreationValidationRun.segment_pair_finder_module
segment_pair_finder_module
use the TrackFinderSegmentPairAutomaton for track-segment finding
Definition: segmentPairCreationValidation.py:45
segmentPairCreationValidation.SegmentPairCreationValidationModule
Definition: segmentPairCreationValidation.py:87
segmentPairCreationValidation.SegmentPairCreationValidationModule.pick
def pick(self, segment_pair_relation)
Definition: segmentPairCreationValidation.py:113
tracking.harvest.harvesting
Definition: harvesting.py:1
segmentPairCreationValidation.SegmentPairCreationValidationModule.select
def select(self, crops)
Definition: segmentPairCreationValidation.py:272
Belle2::TrackFindingCDC::CDCMCSegment2DLookUp::getInstance
static const CDCMCSegment2DLookUp & getInstance()
Getter for the singletone instance.
Definition: CDCMCSegment2DLookUp.cc:23
segmentPairCreationValidation.SegmentPairCreationValidationModule.segment_pair_fusion
segment_pair_fusion
defer reference to CDCAxialStereoFusion until after it is constructed
Definition: segmentPairCreationValidation.py:100
segmentPairCreationValidation.SegmentPairCreationValidationModule.peel_mc
def peel_mc(self, segment_pair_relation)
Definition: segmentPairCreationValidation.py:141
tracking.run.event_generation.StandardEventGenerationRun
Definition: event_generation.py:188
segmentPairCreationValidation.SegmentPairCreationValidationModule.select_fitless
def select_fitless(self, fitless_crops)
Definition: segmentPairCreationValidation.py:264
main
int main(int argc, char **argv)
Run all tests.
Definition: test_main.cc:77
segmentPairCreationValidation.SegmentPairCreationValidationModule.prepare
def prepare(self)
Definition: segmentPairCreationValidation.py:109
segmentPairCreationValidation.SegmentPairCreationValidationModule.__init__
def __init__(self, output_file_name)
Definition: segmentPairCreationValidation.py:91
segmentPairCreationValidation.SegmentPairCreationValidationModule.mc_segment_pair_filter
mc_segment_pair_filter
defer reference to MCSegmentPairFilter until after it is constructed
Definition: segmentPairCreationValidation.py:98
tracking.metamodules
Definition: metamodules.py:1
segmentPairCreationValidation.SegmentPairCreationValidationModule.peel_fitless
def peel_fitless(self, segment_pair_relation)
Definition: segmentPairCreationValidation.py:216
segmentPairCreationValidation.SegmentPairCreationValidationRun.py_profile
bool py_profile
post-process with profiling validation
Definition: segmentPairCreationValidation.py:53
segmentPairCreationValidation.SegmentPairCreationValidationModule.fit
def fit(self, segment_pair_relation)
Definition: segmentPairCreationValidation.py:255
Belle2::TrackFindingCDC::CDCAxialStereoFusion
Utility class implementing the Kalmanesk combination of to two dimensional trajectories to one three ...
Definition: CDCAxialStereoFusion.h:40
tracking.run.event_generation
Definition: event_generation.py:1
segmentPairCreationValidation.SegmentPairCreationValidationModule.initialize
def initialize(self)
Definition: segmentPairCreationValidation.py:102
Belle2::TrackFindingCDC::CDCMCHitLookUp::getInstance
static const CDCMCHitLookUp & getInstance()
Getter for the singletone instance.
Definition: CDCMCHitLookUp.cc:32
tracking.validation.utilities
Definition: utilities.py:1
segmentPairCreationValidation.SegmentPairCreationValidationModule.print_signal_number
def print_signal_number(self, crops, tdirectory, **kwds)
Definition: segmentPairCreationValidation.py:334
segmentPairCreationValidation.SegmentPairCreationValidationModule.delta_phi_cut_value
float delta_phi_cut_value
default selection for the delta-phi of the segment pair
Definition: segmentPairCreationValidation.py:260
segmentPairCreationValidation.SegmentPairCreationValidationModule.mc_segment_lookup
mc_segment_lookup
defer reference to CDCMCSegment2dLookUp singleton until after it is constructed
Definition: segmentPairCreationValidation.py:96
segmentPairCreationValidation.SegmentPairCreationValidationRun.create_argument_parser
def create_argument_parser(self, **kwds)
Definition: segmentPairCreationValidation.py:57
Belle2::TrackFindingCDC::MCSegmentPairFilter
Filter for the constuction of axial to stereo segment pairs based on MC information.
Definition: MCSegmentPairFilter.h:32
tracking.validation.plot
Definition: plot.py:1
tracking.run.mixins.BrowseTFileOnTerminateRunMixin.output_file_name
output_file_name
There is no default for the name of the output TFile.
Definition: mixins.py:54