Belle II Software  release-06-02-00
module.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 import math
13 import collections
14 import numpy as np
15 
16 from tracking.root_utils import root_save_name
17 
18 from tracking.validation.plot import ValidationPlot, compose_axis_label
19 
20 from tracking.validation.pull import PullAnalysis
21 from tracking.validation.resolution import ResolutionAnalysis
22 from tracking.validation.fom import ValidationFiguresOfMerit
24  getHelixFromMCParticle,
25  getSeedTrackFitResult,
26  is_primary,
27  get_det_hit_ids,
28  calc_ndf_from_det_hit_ids
29 )
30 
31 import basf2
32 
33 import ROOT
34 from ROOT import Belle2
35 import os
36 
37 ROOT.gSystem.Load("libtracking")
38 
39 
40 class FilterProperties(object):
41  """
42  contains all informations necessary for track filters to decide whether
43  track will be included into the processed list of tracks
44  This class is used for both providing information on pattern reco and
45  MC tracks
46  """
47 
48  def __init__(
49  self,
50  trackCand=None,
51  mcParticle=None,
52  mcParticles=None,
53  wasFitted=False,
54  fitResult=None,
55  seedResult=None,
56  ):
57  """Constructor"""
58 
59 
60  self.trackCandtrackCand = trackCand
61 
62  self.mcParticlemcParticle = mcParticle
63 
64  self.mcParticlesmcParticles = mcParticles
65 
66  self.wasFittedwasFitted = wasFitted
67 
68  self.fitResultfitResult = fitResult
69 
70  self.seedResultseedResult = seedResult
71 
72 
73 # This class will accept all pattern reco and mctracks
74 # It is used as the default option for the TrackingValidationModule
75 #
76 # It can be used as a starting point to implement your own particle filter class
77 # and supply it to the TrackingValidationModule via the init method's
78 # track_filter_object property.
79 #
80 # doesPrPass is called for all pattern reconstructed tracks
81 # Objects available infilterProperties:
82 # trackCand is guaranteed to be != None
83 # If wasFitted == True, fitResult will be set
84 # otherwise seedResult will be set
85 #
86 # doesMcPass is called for all MC tracks
87 # Objects available infilterProperties:
88 # mcParticle is guaranteed to be != None
89 #
90 
91 class AlwaysPassFilter(object):
92  """Filter that always passes"""
93 
94  def doesPrPass(self, filterProperties):
95  """Pattern-reconstructed track always passes"""
96  return True
97 
98  def doesMcPass(self, filterProperties):
99  """MC track always passes"""
100  return True
101 
102 
103 class TrackingValidationModule(basf2.Module):
104 
105  """Module to collect matching information about the found particles and to
106  generate validation plots and figures of merit on the performance of track finding."""
107 
108  def __init__(
109  self,
110  name,
111  contact,
112  fit=False,
113  pulls=False,
114  resolution=False,
115  output_file_name=None,
116  track_filter_object=AlwaysPassFilter(),
117  plot_name_postfix='',
118  plot_title_postfix='',
119  exclude_profile_mc_parameter='',
120  exclude_profile_pr_parameter='',
121  use_expert_folder=True,
122  trackCandidatesColumnName="RecoTracks",
123  mcTrackCandidatesColumName="MCRecoTracks"
124  ):
125  """Constructor"""
126 
127  super(TrackingValidationModule, self).__init__()
128 
129 
130  self.validation_namevalidation_name = name
131 
132  self.contactcontact = contact
133 
134  self.fitfit = fit
135 
136  self.pullspulls = pulls
137 
138  self.resolutionresolution = resolution
139 
140  self.output_file_nameoutput_file_name = output_file_name or self.validation_namevalidation_name \
141  + 'TrackingValidation.root'
142 
143  self.track_filter_objecttrack_filter_object = track_filter_object
144 
145  self.plot_name_postfixplot_name_postfix = plot_name_postfix
146 
147  self.plot_title_postfixplot_title_postfix = plot_title_postfix
148 
149  self.exclude_profile_pr_parameterexclude_profile_pr_parameter = exclude_profile_pr_parameter
150 
151  self.exclude_profile_mc_parameterexclude_profile_mc_parameter = exclude_profile_mc_parameter
152 
153  self.use_expert_folderuse_expert_folder = use_expert_folder
154 
155  self.trackCandidatesColumnNametrackCandidatesColumnName = trackCandidatesColumnName
156 
157  self.mcTrackCandidatesColumnNamemcTrackCandidatesColumnName = mcTrackCandidatesColumName
158 
159 
160  self.resolution_pt_binningresolution_pt_binning = [0.05, 0.1, 0.25, 0.4, 0.6, 1., 1.5, 2., 3., 4.]
161 
162 
166  self.referenceFileNamereferenceFileName = None
167  if "DO_NOT_READ_BINNING" not in os.environ:
168  # the validity of the file will be checked later
169  self.referenceFileNamereferenceFileName = Belle2.FileSystem.findFile("tracking/validation/" + self.output_file_nameoutput_file_name, True)
170  basf2.B2INFO("Will read binning from: " + self.referenceFileNamereferenceFileName)
171  basf2.B2INFO("If this is not wanted set the environment variable DO_NOT_READ_BINNING or remove reference files.")
172  else:
173  basf2.B2INFO("Will not read binning from reference files.")
174 
175  def initialize(self):
176  """Receive signal at the start of event processing"""
177 
178 
179  self.trackMatchLookUptrackMatchLookUp = Belle2.TrackMatchLookUp(self.mcTrackCandidatesColumnNamemcTrackCandidatesColumnName, self.trackCandidatesColumnNametrackCandidatesColumnName)
180 
181 
182 
183 
184  self.pr_clones_and_matchespr_clones_and_matches = collections.deque()
185 
186  self.pr_matchespr_matches = collections.deque()
187 
188  self.pr_fakespr_fakes = collections.deque()
189 
190 
191  self.pr_seed_tan_lambdaspr_seed_tan_lambdas = collections.deque()
192 
193  self.pr_seed_phipr_seed_phi = collections.deque()
194 
195  self.pr_seed_thetapr_seed_theta = collections.deque()
196 
197 
198  self.pr_omega_truthspr_omega_truths = collections.deque()
199 
200  self.pr_omega_estimatespr_omega_estimates = collections.deque()
201 
202  self.pr_omega_variancespr_omega_variances = collections.deque()
203 
204 
205  self.pr_tan_lambda_truthspr_tan_lambda_truths = collections.deque()
206 
207  self.pr_tan_lambda_estimatespr_tan_lambda_estimates = collections.deque()
208 
209  self.pr_tan_lambda_variancespr_tan_lambda_variances = collections.deque()
210 
211 
212  self.pr_d0_truthspr_d0_truths = collections.deque()
213 
214  self.pr_d0_estimatespr_d0_estimates = collections.deque()
215 
216  self.pr_d0_variancespr_d0_variances = collections.deque()
217 
218 
219  self.pr_z0_truthspr_z0_truths = collections.deque()
220 
221  self.pr_z0_estimatespr_z0_estimates = collections.deque()
222 
223 
224  self.pr_pt_truthspr_pt_truths = collections.deque()
225 
226  self.pr_pt_estimatespr_pt_estimates = collections.deque()
227 
228 
229  self.pr_bining_ptpr_bining_pt = collections.deque()
230 
231 
232  self.mc_matchesmc_matches = collections.deque()
233 
234  self.mc_primariesmc_primaries = collections.deque()
235 
236  self.mc_d0smc_d0s = collections.deque()
237 
238  self.mc_tan_lambdasmc_tan_lambdas = collections.deque()
239 
240  self.mc_thetamc_theta = collections.deque()
241 
242  self.mc_phimc_phi = collections.deque()
243 
244  self.mc_ptsmc_pts = collections.deque()
245 
246  self.mc_hit_efficienciesmc_hit_efficiencies = collections.deque()
247 
248  self.mc_multiplicitiesmc_multiplicities = collections.deque()
249 
250  self.mc_ndfmc_ndf = collections.deque()
251 
252  def event(self):
253  """Event method"""
254 
255  self.examine_pr_tracksexamine_pr_tracks()
256  self.examine_mc_tracksexamine_mc_tracks()
257 
258  def examine_pr_tracks(self):
259  """Looks at the individual pattern reconstructed tracks and store information about them"""
260 
261  # Analyse from the pattern recognition side
262  trackMatchLookUp = self.trackMatchLookUptrackMatchLookUp
263 
264  trackCands = Belle2.PyStoreArray(self.trackCandidatesColumnNametrackCandidatesColumnName)
265  mcParticles = Belle2.PyStoreArray("MCParticles")
266  if not trackCands:
267  return
268 
269  for trackCand in trackCands:
270  is_matched = trackMatchLookUp.isMatchedPRRecoTrack(trackCand)
271  is_clone = trackMatchLookUp.isClonePRRecoTrack(trackCand)
272 
273  pt_truth = float('nan')
274  omega_truth = float('nan')
275  tan_lambda_truth = float('nan')
276  d0_truth = float('nan')
277  z0_truth = float('nan')
278 
279  mcParticle = None
280  if is_matched or is_clone:
281  # Only matched and clone tracks have a related MCParticle
282  mcParticle = trackMatchLookUp.getRelatedMCParticle(trackCand)
283  mcHelix = getHelixFromMCParticle(mcParticle)
284  omega_truth = mcHelix.getOmega()
285  tan_lambda_truth = mcHelix.getTanLambda()
286  pt_truth = mcParticle.getMomentum().Perp()
287  d0_truth = mcHelix.getD0()
288  z0_truth = mcHelix.getZ0()
289 
290  # fill the FilterProperties will all properties on this track
291  # gathered so far
292  filterProperties = FilterProperties(trackCand=trackCand,
293  mcParticle=mcParticle, mcParticles=mcParticles)
294 
295  if self.fitfit:
296  prTrackFitResult = \
297  trackMatchLookUp.getRelatedTrackFitResult(trackCand)
298  filterProperties.wasFitted = prTrackFitResult is not None
299  filterProperties.fitResult = prTrackFitResult
300  else:
301  prTrackFitResult = getSeedTrackFitResult(trackCand)
302  filterProperties.seedResult = prTrackFitResult
303 
304  # skip this track due to the filtering rules ?
305  if not self.track_filter_objecttrack_filter_object.doesPrPass(filterProperties):
306  continue
307 
308  omega_estimate = float('nan')
309  omega_variance = float('nan')
310  tan_lambda_estimate = float('nan')
311  tan_lambda_variance = float('nan')
312  d0_estimate = float('nan')
313  d0_variance = float('nan')
314  z0_estimate = float('nan')
315  pt_estimate = float('nan')
316 
317  momentum = float('nan')
318 
319  # store seed information, they are always available from the pattern reco
320  # even if the fit was no successful
321  # this information can we used when plotting fake tracks, for example
322  seed_position = trackCand.getPositionSeed()
323  seed_momentum = trackCand.getMomentumSeed()
324  # Avoid zero division exception
325  seed_tan_lambda = np.divide(1.0, math.tan(seed_momentum.Theta()))
326  seed_phi = seed_position.Phi()
327  seed_theta = seed_position.Theta()
328 
329  if prTrackFitResult:
330  omega_estimate = prTrackFitResult.getOmega()
331  omega_variance = prTrackFitResult.getCov()[9]
332 
333  tan_lambda_estimate = prTrackFitResult.getCotTheta()
334  tan_lambda_variance = prTrackFitResult.getCov()[14]
335 
336  d0_estimate = prTrackFitResult.getD0()
337  d0_variance = prTrackFitResult.getCov()[0]
338 
339  z0_estimate = prTrackFitResult.getZ0()
340 
341  momentum = prTrackFitResult.getMomentum()
342  pt_estimate = momentum.Perp()
343 
344  # store properties of the seed
345  self.pr_seed_tan_lambdaspr_seed_tan_lambdas.append(seed_tan_lambda)
346  self.pr_seed_phipr_seed_phi.append(seed_phi)
347  self.pr_seed_thetapr_seed_theta.append(seed_theta)
348 
349  self.pr_bining_ptpr_bining_pt.append(pt_truth)
350 
351  # store properties resulting from this trackfit
352  isMatchedOrIsClone = is_matched or is_clone
353  self.pr_clones_and_matchespr_clones_and_matches.append(isMatchedOrIsClone)
354  self.pr_matchespr_matches.append(is_matched)
355  self.pr_fakespr_fakes.append(not isMatchedOrIsClone)
356 
357  self.pr_omega_estimatespr_omega_estimates.append(omega_estimate)
358  self.pr_omega_variancespr_omega_variances.append(omega_variance)
359  self.pr_omega_truthspr_omega_truths.append(omega_truth)
360 
361  self.pr_tan_lambda_estimatespr_tan_lambda_estimates.append(tan_lambda_estimate)
362  self.pr_tan_lambda_variancespr_tan_lambda_variances.append(tan_lambda_variance)
363  self.pr_tan_lambda_truthspr_tan_lambda_truths.append(tan_lambda_truth)
364 
365  self.pr_d0_estimatespr_d0_estimates.append(d0_estimate)
366  self.pr_d0_variancespr_d0_variances.append(d0_variance)
367  self.pr_d0_truthspr_d0_truths.append(d0_truth)
368 
369  self.pr_z0_estimatespr_z0_estimates.append(z0_estimate)
370  self.pr_z0_truthspr_z0_truths.append(z0_truth)
371 
372  self.pr_pt_estimatespr_pt_estimates.append(pt_estimate)
373  self.pr_pt_truthspr_pt_truths.append(pt_truth)
374 
375  def examine_mc_tracks(self):
376  """Looks at the individual Monte Carlo tracks and store information about them"""
377 
378  trackMatchLookUp = self.trackMatchLookUptrackMatchLookUp
379 
380  # Analyse from the Monte Carlo reference side
381  mcTrackCands = Belle2.PyStoreArray(self.mcTrackCandidatesColumnNamemcTrackCandidatesColumnName)
382  mcParticles = Belle2.PyStoreArray('MCParticles')
383  if not mcTrackCands:
384  return
385 
386  multiplicity = mcTrackCands.getEntries()
387 
388  for mcTrackCand in mcTrackCands:
389  is_matched = trackMatchLookUp.isMatchedMCRecoTrack(mcTrackCand)
390 
391  hit_efficiency = trackMatchLookUp.getRelatedEfficiency(mcTrackCand)
392  if math.isnan(hit_efficiency):
393  hit_efficiency = 0
394 
395  mcParticle = trackMatchLookUp.getRelatedMCParticle(mcTrackCand)
396  mcHelix = getHelixFromMCParticle(mcParticle)
397 
398  # fill the FilterProperties will all properties on this track
399  # gathered so far
400  filterProperties = FilterProperties(mcParticle=mcParticle,
401  mcParticles=mcParticles)
402 
403  if not self.track_filter_objecttrack_filter_object.doesMcPass(filterProperties):
404  continue
405 
406  momentum = mcParticle.getMomentum()
407  pt = momentum.Perp()
408  tan_lambda = np.divide(1.0, math.tan(momentum.Theta())) # Avoid zero division exception
409  d0 = mcHelix.getD0()
410  det_hit_ids = get_det_hit_ids(mcTrackCand)
411  ndf = calc_ndf_from_det_hit_ids(det_hit_ids)
412 
413  self.mc_matchesmc_matches.append(is_matched)
414  self.mc_primariesmc_primaries.append(is_primary(mcParticle))
415  self.mc_hit_efficienciesmc_hit_efficiencies.append(hit_efficiency)
416  self.mc_ptsmc_pts.append(pt)
417  self.mc_d0smc_d0s.append(d0)
418  self.mc_tan_lambdasmc_tan_lambdas.append(tan_lambda)
419  self.mc_multiplicitiesmc_multiplicities.append(multiplicity)
420  self.mc_thetamc_theta.append(momentum.Theta())
421  self.mc_phimc_phi.append(momentum.Phi())
422  self.mc_ndfmc_ndf.append(ndf)
423 
424  def terminate(self):
425  """Receive signal at the end of event processing"""
426  name = self.validation_namevalidation_name
427  contact = self.contactcontact
428 
429  # Overall figures of merit #
430 
431  finding_efficiency = np.average(self.mc_matchesmc_matches, weights=self.mc_primariesmc_primaries)
432  fake_rate = 1.0 - np.mean(self.pr_clones_and_matchespr_clones_and_matches)
433  # can only be computed if there are entries
434  if len(self.pr_clones_and_matchespr_clones_and_matches) > 0 and sum(self.pr_clones_and_matchespr_clones_and_matches) > 0:
435  clone_rate = 1.0 - np.average(self.pr_matchespr_matches,
436  weights=self.pr_clones_and_matchespr_clones_and_matches)
437  else:
438  clone_rate = float('nan')
439 
440  mc_matched_primaries = np.logical_and(self.mc_primariesmc_primaries, self.mc_matchesmc_matches)
441  hit_efficiency = np.average(self.mc_hit_efficienciesmc_hit_efficiencies, weights=mc_matched_primaries)
442 
443  figures_of_merit = ValidationFiguresOfMerit('%s_figures_of_merit'
444  % name)
445  figures_of_merit['finding_efficiency'] = finding_efficiency
446  figures_of_merit['fake_rate'] = fake_rate
447  figures_of_merit['clone_rate'] = clone_rate
448  figures_of_merit['hit_efficiency'] = hit_efficiency
449 
450  figures_of_merit.description = \
451  """
452 finding_efficiency - the ratio of matched Monte Carlo tracks to all Monte Carlo tracks <br/>
453 fake_rate - ratio of pattern recognition tracks that are not related to a particle
454  (background, ghost) to all pattern recognition tracks <br/>
455 clone_rate - ratio of clones divided the number of tracks that are related to a particle (clones and matches) <br/>
456 """
457  figures_of_merit.check = 'Compare for degradations with respect to the reference'
458  figures_of_merit.contact = contact
459  print(figures_of_merit)
460 
461  # Validation plots #
462 
463  validation_plots = []
464  pull_analyses = []
465 
466  # Finding efficiency #
467 
468  plots = self.profiles_by_mc_parametersprofiles_by_mc_parameters(self.mc_matchesmc_matches,
469  'finding efficiency',
470  make_hist=False,
471  weights=self.mc_primariesmc_primaries)
472 
473  validation_plots.extend(plots)
474 
475  # Fake rate (all tracks not matched or clone #
476  # use TrackCand seeds for the fake track plotting #
477  # as the fit (if successful) is probably not meaningful #
478 
479  print('fake list: ' + str(len(self.pr_fakespr_fakes)))
480  plots = self.profiles_by_pr_parametersprofiles_by_pr_parameters(self.pr_fakespr_fakes, 'fake rate',
481  make_hist=False)
482  validation_plots.extend(plots)
483 
484  # Hit efficiency #
485 
486  plots = self.profiles_by_mc_parametersprofiles_by_mc_parameters(self.mc_hit_efficienciesmc_hit_efficiencies,
487  'hit efficiency with matched tracks',
488  weights=mc_matched_primaries)
489  validation_plots.extend(plots)
490 
491  # Fit quality #
492 
493  if self.pullspulls:
494  all_but_diagonal_plots = list(PullAnalysis.default_which_plots)
495  all_but_diagonal_plots.remove("diag_profile")
496  all_but_diagonal_plots.remove("diag_scatter")
497 
498  plot_name_prefix = name + self.plot_name_postfixplot_name_postfix
499  if not self.fitfit:
500  plot_name_prefix += '_seed'
501 
502  # Omega / curvature pull
503  pr_omega_truths = np.array(self.pr_omega_truthspr_omega_truths)
504  pr_omega_estimates = np.array(self.pr_omega_estimatespr_omega_estimates)
505  pr_omega_variances = np.array(self.pr_omega_variancespr_omega_variances)
506 
507  curvature_pull_analysis = PullAnalysis('#omega', unit='1/cm',
508  plot_name_prefix=plot_name_prefix + '_omega',
509  plot_title_postfix=self.plot_title_postfixplot_title_postfix,
510  referenceFileName=self.referenceFileNamereferenceFileName)
511 
512  curvature_pull_analysis.analyse(pr_omega_truths,
513  pr_omega_estimates,
514  pr_omega_variances,
515  which_plots=all_but_diagonal_plots)
516 
517  curvature_pull_analysis.contact = contact
518  pull_analyses.append(curvature_pull_analysis)
519 
520  # Tan lambda pull
521  pr_tan_lambda_truths = np.array(self.pr_tan_lambda_truthspr_tan_lambda_truths)
522  pr_tan_lambda_estimates = np.array(self.pr_tan_lambda_estimatespr_tan_lambda_estimates)
523  pr_tan_lambda_variances = np.array(self.pr_tan_lambda_variancespr_tan_lambda_variances)
524 
525  curvature_pull_analysis = PullAnalysis('tan #lambda',
526  plot_name_prefix=plot_name_prefix + '_tan_lambda',
527  plot_title_postfix=self.plot_title_postfixplot_title_postfix,
528  referenceFileName=self.referenceFileNamereferenceFileName)
529 
530  curvature_pull_analysis.analyse(pr_tan_lambda_truths,
531  pr_tan_lambda_estimates,
532  pr_tan_lambda_variances,
533  which_plots=all_but_diagonal_plots)
534 
535  curvature_pull_analysis.contact = contact
536  pull_analyses.append(curvature_pull_analysis)
537 
538  # d0 pull
539  curvature_pull_analysis = PullAnalysis('d0',
540  plot_name_prefix=plot_name_prefix + '_d0',
541  plot_title_postfix=self.plot_title_postfixplot_title_postfix,
542  referenceFileName=self.referenceFileNamereferenceFileName)
543 
544  curvature_pull_analysis.analyse(np.array(self.pr_d0_truthspr_d0_truths),
545  np.array(self.pr_d0_estimatespr_d0_estimates),
546  np.array(self.pr_d0_variancespr_d0_variances),
547  which_plots=all_but_diagonal_plots)
548 
549  curvature_pull_analysis.contact = contact
550  pull_analyses.append(curvature_pull_analysis)
551 
552  # Resolution plots
553 
554  if self.resolutionresolution:
555  # d0 impact parameter resolution plot
556  d0_resolution_analysis = ResolutionAnalysis('d0_res',
557  self.resolution_pt_binningresolution_pt_binning,
558  'Pt',
559  plot_name_prefix=plot_name_prefix + '_d0_res',
560  plot_title_postfix=self.plot_title_postfixplot_title_postfix,
561  referenceFileName=self.referenceFileNamereferenceFileName)
562  d0_resolution_analysis.analyse(np.array(self.pr_bining_ptpr_bining_pt),
563  np.array(self.pr_d0_truthspr_d0_truths),
564  np.array(self.pr_d0_estimatespr_d0_estimates))
565  d0_resolution_analysis.contact = contact
566  pull_analyses.append(d0_resolution_analysis)
567 
568  # z0 impact parameter resolution plot
569  z0_resolution_analysis = ResolutionAnalysis('z0_res',
570  self.resolution_pt_binningresolution_pt_binning,
571  "Pt",
572  plot_name_prefix=plot_name_prefix + '_z0_res',
573  plot_title_postfix=self.plot_title_postfixplot_title_postfix,
574  referenceFileName=self.referenceFileNamereferenceFileName)
575  z0_resolution_analysis.analyse(np.array(self.pr_bining_ptpr_bining_pt),
576  np.array(self.pr_z0_truthspr_z0_truths),
577  np.array(self.pr_z0_estimatespr_z0_estimates))
578  z0_resolution_analysis.contact = contact
579  pull_analyses.append(z0_resolution_analysis)
580 
581  # omega curvature parameter resolution plot
582  omega_resolution_analysis = ResolutionAnalysis('omega_res',
583  self.resolution_pt_binningresolution_pt_binning,
584  "Pt",
585  plot_name_prefix=plot_name_prefix + '_omega_res',
586  plot_title_postfix=self.plot_title_postfixplot_title_postfix,
587  referenceFileName=self.referenceFileNamereferenceFileName)
588  omega_resolution_analysis.analyse(np.array(self.pr_bining_ptpr_bining_pt),
589  np.array(self.pr_omega_truthspr_omega_truths),
590  np.array(self.pr_omega_estimatespr_omega_estimates))
591  omega_resolution_analysis.contact = contact
592  pull_analyses.append(omega_resolution_analysis)
593 
594  # transverse momentum resolution plot
595  pt_resolution_analysis = ResolutionAnalysis('pt_res',
596  self.resolution_pt_binningresolution_pt_binning,
597  "Pt",
598  plot_name_prefix=plot_name_prefix + '_pt_res',
599  plot_title_postfix=self.plot_title_postfixplot_title_postfix,
600  referenceFileName=self.referenceFileNamereferenceFileName)
601  pt_resolution_analysis.analyse(np.array(self.pr_bining_ptpr_bining_pt),
602  np.array(self.pr_pt_truthspr_pt_truths),
603  np.array(self.pr_pt_estimatespr_pt_estimates))
604  pt_resolution_analysis.contact = contact
605  pull_analyses.append(pt_resolution_analysis)
606 
607  # Saving #
608 
609 
610  # Save everything to a ROOT file
611  output_tfile = ROOT.TFile(self.output_file_nameoutput_file_name, 'recreate')
612 
613  # Show all parameters and the fit result in the plots
614  # if viewed in the browser or the validation
615  opt_fit = 0o112
616  ROOT.gStyle.SetOptFit(opt_fit)
617 
618  figures_of_merit.write()
619 
620  for validation_plot in validation_plots:
621  validation_plot.write()
622 
623  if self.use_expert_folderuse_expert_folder:
624  expert_tdirectory = output_tfile.mkdir('expert', 'Expert')
625  expert_tdirectory.cd()
626  ROOT.gStyle.SetOptFit(opt_fit)
627 
628  for pull_analysis in pull_analyses:
629  pull_analysis.write()
630 
631  output_tfile.Close()
632 
634  self,
635  xs,
636  quantity_name,
637  unit=None,
638  parameter_names=[
639  'd_0',
640  'p_t',
641  'tan_lambda',
642  'multiplicity',
643  'phi',
644  'theta',
645  'ndf',
646  ],
647  non_expert_parameters=['p_{t}'],
648  make_hist=True,
649  weights=None
650  ):
651  """Create profile histograms by MC-track parameters"""
652 
653  # apply exclusion list
654  new_parameter_names = [item for item in parameter_names if item
655  not in self.exclude_profile_mc_parameterexclude_profile_mc_parameter]
656 
657  # Profile versus the various parameters
658  profile_parameters = {
659  'd_{0}': self.mc_d0smc_d0s,
660  'p_{t}': self.mc_ptsmc_pts,
661  'tan #lambda': self.mc_tan_lambdasmc_tan_lambdas,
662  '#phi': self.mc_phimc_phi,
663  '#theta': self.mc_thetamc_theta,
664  'multiplicity': self.mc_multiplicitiesmc_multiplicities,
665  'ndf': self.mc_ndfmc_ndf,
666  }
667 
668  return self.profiles_by_parameters_baseprofiles_by_parameters_base(
669  xs,
670  quantity_name,
671  new_parameter_names,
672  profile_parameters,
673  unit,
674  make_hist,
675  non_expert_parameters=non_expert_parameters,
676  weights=weights
677  )
678 
680  self,
681  xs,
682  quantity_name,
683  unit=None,
684  parameter_names=['Seed tan #lambda', 'Seed #phi', 'Seed #theta'],
685  make_hist=True,
686  ):
687  """Create profile histograms by PR-track parameters"""
688 
689  # apply exclusion list
690  new_parameter_names = [item for item in parameter_names if item
691  not in self.exclude_profile_pr_parameterexclude_profile_pr_parameter]
692 
693  # Profile versus the various parameters
694  profile_parameters = {'Seed tan #lambda': self.pr_seed_tan_lambdaspr_seed_tan_lambdas,
695  'Seed #phi': self.pr_seed_phipr_seed_phi,
696  'Seed #theta': self.pr_seed_thetapr_seed_theta}
697 
698  return self.profiles_by_parameters_baseprofiles_by_parameters_base(
699  xs,
700  quantity_name,
701  new_parameter_names,
702  profile_parameters,
703  unit,
704  make_hist,
705  )
706 
708  self,
709  xs,
710  quantity_name,
711  parameter_names,
712  profile_parameters,
713  unit,
714  make_hist,
715  non_expert_parameters=[],
716  weights=None,
717  ):
718  """Create profile histograms for generic parameters"""
719 
720  contact = self.contactcontact
721 
722  validation_plots = []
723  plot_name_prefix = self.validation_namevalidation_name + '_' + root_save_name(quantity_name) \
724  + self.plot_name_postfixplot_name_postfix
725 
726  if make_hist:
727  # Histogram of the quantity
728  histogram = ValidationPlot(plot_name_prefix, self.referenceFileNamereferenceFileName)
729  histogram.hist(xs, weights=weights)
730 
731  histogram.xlabel = quantity_name
732  histogram.description = 'Not a serious plot yet.'
733  histogram.check = ''
734  histogram.contact = contact
735  histogram.title = quantity_name + self.plot_title_postfixplot_title_postfix
736 
737  validation_plots.append(histogram)
738 
739  for (parameter_name, parameter_values) in list(profile_parameters.items()):
740  if parameter_name in parameter_names \
741  or root_save_name(parameter_name) in parameter_names:
742 
743  is_expert = not(parameter_name in non_expert_parameters)
744 
745  # Apply some boundaries for the maximal tracking acceptance
746  # such that the plots look more instructive
747  if root_save_name(parameter_name) == 'tan_lambda':
748  lower_bound = -1.73
749  upper_bound = 3.27
750  elif root_save_name(parameter_name) == 'theta':
751  lower_bound = 17 * math.pi / 180
752  upper_bound = 150 * math.pi / 180
753  elif root_save_name(parameter_name) == 'ndf':
754  lower_bound = 0
755  upper_bound = min(200, np.max(parameter_values))
756  else:
757  lower_bound = None
758  upper_bound = None
759 
760  profile_plot_name = plot_name_prefix + '_by_' \
761  + root_save_name(parameter_name)
762  profile_plot = ValidationPlot(profile_plot_name, self.referenceFileNamereferenceFileName)
763  profile_plot.profile(parameter_values,
764  xs,
765  weights=weights,
766  outlier_z_score=10.0,
767  lower_bound=lower_bound,
768  upper_bound=upper_bound,
769  y_binary=True,
770  is_expert=is_expert)
771 
772  profile_plot.xlabel = compose_axis_label(parameter_name)
773  profile_plot.ylabel = compose_axis_label(quantity_name, unit)
774  profile_plot.title = quantity_name + ' by ' + parameter_name \
775  + ' profile' + self.plot_title_postfixplot_title_postfix
776 
777  profile_plot.description = \
778  'Dependence of %s of the track over the true %s' \
779  % (quantity_name, parameter_name)
780  profile_plot.check = 'Variations should be low'
781  profile_plot.contact = contact
782  validation_plots.append(profile_plot)
783 
784  return validation_plots
static std::string findFile(const std::string &path, bool silent=false)
Search for given file or directory in local or central release directory, and return absolute path if...
Definition: FileSystem.cc:145
a (simplified) python wrapper for StoreArray.
Definition: PyStoreArray.h:56
Class to provide convenient methods to look up matching information between pattern recognition and M...
def doesPrPass(self, filterProperties)
Definition: module.py:94
def doesMcPass(self, filterProperties)
Definition: module.py:98
mcParticle
cached value of the MC particle
Definition: module.py:62
wasFitted
cached value of the fitted flag
Definition: module.py:66
def __init__(self, trackCand=None, mcParticle=None, mcParticles=None, wasFitted=False, fitResult=None, seedResult=None)
Definition: module.py:56
trackCand
cached value of the track candidate
Definition: module.py:60
seedResult
cached value of the seed result
Definition: module.py:70
fitResult
cached value of the fit result
Definition: module.py:68
mcParticles
cached value of the MCParticles StoreArray
Definition: module.py:64
pr_omega_variances
list of PR-track seed omega-variance values
Definition: module.py:202
exclude_profile_mc_parameter
cached list of perigee parameters excluded from MC side plots
Definition: module.py:151
track_filter_object
cached value of the track-filter object
Definition: module.py:143
pr_seed_tan_lambdas
list of PR-track seed tan(lambda) values
Definition: module.py:191
pr_tan_lambda_estimates
list of PR-track seed tan(lambda)-estimate values
Definition: module.py:207
mc_theta
direction of the track in theta
Definition: module.py:240
contact
cached value of the contact person name
Definition: module.py:132
pr_bining_pt
list of PR-track binning values
Definition: module.py:229
pr_tan_lambda_variances
list of PR-track seed tan(lambda)-variance values
Definition: module.py:209
pr_pt_estimates
list of PR-track seed pt-estimate values
Definition: module.py:226
trackCandidatesColumnName
cached name of the RecoTracks StoreArray
Definition: module.py:155
pr_pt_truths
list of PR-track seed pt-truth values
Definition: module.py:224
pulls
cached values of the track-fit pulls
Definition: module.py:136
mc_ndf
list of MC-track number of degrees of freedom
Definition: module.py:250
pr_omega_truths
list of PR-track seed omega-truth values
Definition: module.py:198
def profiles_by_mc_parameters(self, xs, quantity_name, unit=None, parameter_names=['d_0', 'p_t', 'tan_lambda', 'multiplicity', 'phi', 'theta', 'ndf',], non_expert_parameters=['p_{t}'], make_hist=True, weights=None)
Definition: module.py:650
pr_seed_theta
list of PR-track seed theta values
Definition: module.py:195
pr_seed_phi
list of PR-track seed phi values
Definition: module.py:193
output_file_name
cached value of the output ROOT TFile
Definition: module.py:140
plot_name_postfix
cached value of the suffix appended to the plot names
Definition: module.py:145
trackMatchLookUp
Track-match object that examines relation information from MCMatcherTracksModule.
Definition: module.py:179
pr_omega_estimates
list of PR-track seed omega-estimate values
Definition: module.py:200
plot_title_postfix
cached value of the suffix appended to the plot titles
Definition: module.py:147
pr_z0_estimates
list of PR-track seed z0-estimate values
Definition: module.py:221
pr_d0_variances
list of PR-track seed d0-variance values
Definition: module.py:216
resolution_pt_binning
default binning used for resolution plots over pt
Definition: module.py:160
def profiles_by_pr_parameters(self, xs, quantity_name, unit=None, parameter_names=['Seed tan #lambda', 'Seed #phi', 'Seed #theta'], make_hist=True)
Definition: module.py:686
mc_multiplicities
list of MC-track multiplicities
Definition: module.py:248
pr_clones_and_matches
Use deques in favour of lists to prevent repeated memory allocation of cost O(n)
Definition: module.py:184
resolution
cached value of the resolution
Definition: module.py:138
def profiles_by_parameters_base(self, xs, quantity_name, parameter_names, profile_parameters, unit, make_hist, non_expert_parameters=[], weights=None)
Definition: module.py:717
def __init__(self, name, contact, fit=False, pulls=False, resolution=False, output_file_name=None, track_filter_object=AlwaysPassFilter(), plot_name_postfix='', plot_title_postfix='', exclude_profile_mc_parameter='', exclude_profile_pr_parameter='', use_expert_folder=True, trackCandidatesColumnName="RecoTracks", mcTrackCandidatesColumName="MCRecoTracks")
Definition: module.py:124
referenceFileName
If this variable is set the code will open the file with same name as the file created here and will ...
Definition: module.py:166
use_expert_folder
cached flag to use the "expert" folder for the pull and residual plots
Definition: module.py:153
pr_z0_truths
list of PR-track seed z0-truth values
Definition: module.py:219
mcTrackCandidatesColumnName
cached name of the MCRecoTracks StoreArray
Definition: module.py:157
pr_tan_lambda_truths
list of PR-track seed tan(lambda)-truth values
Definition: module.py:205
pr_d0_estimates
list of PR-track seed d0-estimate values
Definition: module.py:214
validation_name
cached value of the tracking-validation name
Definition: module.py:130
mc_tan_lambdas
list of MC-track tan(lambda) values
Definition: module.py:238
mc_hit_efficiencies
list of MC-track hit efficiencies
Definition: module.py:246
pr_d0_truths
list of PR-track seed d0-truth values
Definition: module.py:212
exclude_profile_pr_parameter
cached list of perigee parameters excluded from PR side plots
Definition: module.py:149