10from ROOT
import Belle2
22ROOT.gSystem.Load(
"libtracking")
26 """Module to collect matching information about the found particles and to generate
27 validation plots and figures of merit on the performance of track finding.
"""
29 """ Expert level behavior:
30 expert_level <= default_expert_level: all figures and plots
from this module
except tree entries
31 expert_level > default_expert_level: everything including tree entries
34 default_expert_level = 10
40 output_file_name=None,
41 reco_tracks_name='RecoTracks',
42 mc_reco_tracks_name='MCRecoTracks',
46 output_file_name = output_file_name or name +
'TrackingValidation.root'
47 super().
__init__(foreach=reco_tracks_name,
50 output_file_name=output_file_name,
51 expert_level=expert_level)
69 """Receive signal at the start of event processing"""
75 """Called once at the start of each event"""
78 mc_reco_tracks_det_hit_ids = []
80 for mc_reco_track
in mc_reco_tracks:
81 mc_reco_track_det_hit_ids = utilities.get_det_hit_ids(mc_reco_track)
82 mc_reco_tracks_det_hit_ids.append(mc_reco_track_det_hit_ids)
88 def pick(self, reco_track):
89 """Method to filter the track candidates to reject part of them"""
92 def peel(self, reco_track):
93 """Looks at the individual pattern recognition tracks and store information about them"""
97 mc_reco_track = track_match_look_up.getRelatedMCRecoTrack(reco_track)
98 mc_particle = track_match_look_up.getRelatedMCParticle(reco_track)
99 mc_particle_crops = peelers.peel_mc_particle(mc_particle)
101 hit_content_crops = peelers.peel_reco_track_hit_content(reco_track)
106 subdetector_hit_purity_crops = peelers.peel_subdetector_hit_purity(reco_track, mc_reco_track)
109 trackfinder_crops = peelers.peel_trackfinder(reco_track)
112 qualityindicator_crops = peelers.peel_quality_indicators(reco_track)
115 seed_fit_crops = peelers.peel_reco_track_seed(reco_track)
117 fit_result = track_match_look_up.getRelatedTrackFitResult(reco_track)
118 fit_crops = peelers.peel_track_fit_result(fit_result)
119 fit_status_crops = peelers.peel_fit_status(reco_track)
121 correct_rl_information = sum(peelers.is_correct_rl_information(cdc_hit, reco_track, self.
mc_hit_lookup)
122 for cdc_hit
in getObjectList(reco_track.getCDCHitList()))
125 correct_rl_information=correct_rl_information,
128 **pr_to_mc_match_info_crops,
129 **subdetector_hit_purity_crops,
131 **qualityindicator_crops,
141 event_crops = peelers.peel_event_info(event_meta_data)
144 store_array_crops = peelers.peel_store_array_info(reco_track, key=
"pr_{part_name}")
145 mc_store_array_crops = peelers.peel_store_array_info(mc_reco_track, key=
"mc_{part_name}")
148 mc_efficiency_information = {
149 "mc_hit_efficiency": track_match_look_up.getRelatedEfficiency(mc_reco_track)
if mc_reco_track
else float(
"nan"),
150 **peelers.peel_subdetector_hit_efficiency(reco_track=reco_track, mc_reco_track=mc_reco_track,
151 key=
"mc_{part_name}")
157 **mc_store_array_crops,
158 **mc_efficiency_information
164 """Extracts track-match information from the MCMatcherTracksModule results"""
166 is_matched = track_match_look_up.isAnyChargeMatchedPRRecoTrack(reco_track)
167 is_matched_correct_charge = track_match_look_up.isCorrectChargeMatchedPRRecoTrack(reco_track)
168 is_matched_wrong_charge = track_match_look_up.isWrongChargeMatchedPRRecoTrack(reco_track)
169 is_clone = track_match_look_up.isAnyChargeClonePRRecoTrack(reco_track)
170 is_clone_correct_charge = track_match_look_up.isCorrectChargeClonePRRecoTrack(reco_track)
171 is_clone_wrong_charge = track_match_look_up.isWrongChargeClonePRRecoTrack(reco_track)
172 is_background = track_match_look_up.isBackgroundPRRecoTrack(reco_track)
173 is_ghost = track_match_look_up.isGhostPRRecoTrack(reco_track)
175 reco_track_det_hit_ids = utilities.get_det_hit_ids(reco_track)
176 n_intersecting_mc_tracks = 0
178 intersects = len(mc_reco_track_det_hit_ids & reco_track_det_hit_ids) > 0
180 n_intersecting_mc_tracks += 1
182 mc_particle = track_match_look_up.getRelatedMCParticle(reco_track)
183 mc_is_primary =
False
185 mc_is_primary = bool(mc_particle.hasStatus(Belle2.MCParticle.c_PrimaryParticle))
188 is_matched=is_matched,
189 is_matchedPrimary=is_matched
and mc_is_primary,
190 is_matched_correct_charge=is_matched_correct_charge,
191 is_matchedPrimary_correct_charge=is_matched_correct_charge
and mc_is_primary,
192 is_matched_wrong_charge=is_matched_wrong_charge,
193 is_matchedPrimary_wrong_charge=is_matched_wrong_charge
and mc_is_primary,
196 is_clone_correct_charge=is_clone_correct_charge,
197 is_clone_wrong_charge=is_clone_wrong_charge,
199 is_background=is_background,
201 is_clone_or_match=(is_matched
or is_clone),
202 is_fake=
not (is_matched
or is_clone),
203 hit_purity=track_match_look_up.getRelatedPurity(reco_track),
204 n_intersecting_mc_tracks=n_intersecting_mc_tracks,
211 save_tree = refiners.save_tree(
213 folder_name=
"pr_tree", name=
"pr_tree", above_expert_level=default_expert_level
218 save_clone_rate = refiners.save_fom(
220 name=
"{module.id}_overview_figures_of_merit",
222 title=
"Overview figures in {module.title}",
223 description=
"clone_rate - ratio of clones divided the number of tracks that are related to a particle (clones and matches)",
227 filter_on=
"is_clone_or_match",
233 save_clone_rate_by_seed_tan_lambda_profile = refiners.save_profiles(
235 filter_on=
"is_clone_or_match",
237 'is_clone':
'clone rate',
238 'seed_tan_lambda_estimate':
'seed tan #lambda',
251 save_clone_rate_by_seed_phi0_profile = refiners.save_profiles(
254 'is_clone':
'clone rate',
255 'seed_phi0_estimate':
'seed #phi',
266 save_clone_rate_by_seed_pt_profile = refiners.save_profiles(
268 filter_on=
"is_clone_or_match",
270 'is_clone':
'clone rate',
271 'seed_pt_estimate':
'seed p_{t}',
284 save_clone_rate_by_seed_pt_profile_groupbyCharge = refiners.save_profiles(
286 filter_on=
"is_clone_or_match",
288 'is_clone':
'clone rate',
289 'seed_pt_estimate':
'seed p_{t}',
293 groupby=[(
"charge_truth", [0.])],
303 save_clone_rate_by_seed_tan_lambda_profile_groupbyCharge = refiners.save_profiles(
305 filter_on=
"is_clone_or_match",
307 'is_clone':
'clone rate',
308 'seed_tan_lambda_estimate':
'seed tan #lambda',
312 groupby=[(
"charge_truth", [0.])],
321 save_fake_rate = refiners.save_fom(
323 name=
"{module.id}_overview_figures_of_merit",
325 title=
"Overview figures in {module.title}",
326 description=
"fake_rate - ratio of pattern recognition tracks that are not related to a particle" +
327 "(background, ghost) to all pattern recognition tracks",
336 save_fake_rate_by_seed_phi0_profile = refiners.save_profiles(
339 'is_fake':
'fake rate',
340 'seed_phi0_estimate':
'seed #phi',
350 save_fake_rate_by_seed_tan_lambda_profile = refiners.save_profiles(
353 'is_fake':
'fake rate',
354 'seed_tan_lambda_estimate':
'seed tan #lambda',
366 save_fake_rate_by_seed_pt_profile = refiners.save_profiles(
369 'is_fake':
'fake rate',
370 'seed_pt_estimate':
'seed p_{t}',
382 save_fake_rate_by_seed_tan_lambda_profile_groupbyCharge = refiners.save_profiles(
384 filter_on=
"has_trackFitResult",
386 'is_fake':
'fake rate',
387 'seed_tan_lambda_estimate':
'seed tan #lambda',
394 groupby=[(
"track_charge", [0.])],
400 save_fake_rate_by_seed_pt_profile_groupbyCharge = refiners.save_profiles(
402 filter_on=
"has_trackFitResult",
404 'is_fake':
'fake rate',
405 'seed_pt_estimate':
'seed p_{t}',
412 groupby=[(
"track_charge", [0.])],
417 save_hit_counts_by_pt_profile = refiners.save_profiles(
419 filter_on=
"is_matched",
421 "pt_truth":
"true p_{t}",
422 "n_pxd_hits":
"pxd hits",
423 "n_svd_hits":
"svd hits",
424 "n_cdc_hits":
"cdc hits",
438 save_hit_efficiency_by_pt_profile = refiners.save_profiles(
440 filter_on=
"is_matchedPrimary",
442 "pt_truth":
"true p_{t}",
443 "mc_pxd_hit_efficiency":
"pxd hit efficiency",
444 "mc_svd_hit_efficiency":
"svd hit efficiency",
445 "mc_cdc_hit_efficiency":
"cdc hit efficiency",
448 "pxd hit efficiency",
449 "svd hit efficiency",
450 "cdc hit efficiency",
459 save_hit_purity_by_pt_profile = refiners.save_profiles(
461 filter_on=
"is_matchedPrimary",
463 "pt_truth":
"true p_{t}",
464 "pxd_hit_purity":
"pxd hit purity",
465 "svd_hit_purity":
"svd hit purity",
466 "cdc_hit_purity":
"cdc hit purity",
480 save_hit_counts_by_tanlambda_profile = refiners.save_profiles(
482 filter_on=
"is_matched",
484 "tan_lambda_truth":
"true tan #lambda",
485 "n_pxd_hits":
"pxd hits",
486 "n_svd_hits":
"svd hits",
487 "n_cdc_hits":
"cdc hits",
501 save_hit_efficiency_by_tanlambda_profile = refiners.save_profiles(
503 filter_on=
"is_matchedPrimary",
505 "tan_lambda_truth":
"true tan #lambda",
506 "mc_pxd_hit_efficiency":
"pxd hit efficiency",
507 "mc_svd_hit_efficiency":
"svd hit efficiency",
508 "mc_cdc_hit_efficiency":
"cdc hit efficiency",
511 "pxd hit efficiency",
512 "svd hit efficiency",
513 "cdc hit efficiency",
522 save_hit_purity_by_tanlambda_profile = refiners.save_profiles(
524 filter_on=
"is_matchedPrimary",
526 "tan_lambda_truth":
"true tan #lambda",
527 "pxd_hit_purity":
"pxd hit purity",
528 "svd_hit_purity":
"svd hit purity",
529 "cdc_hit_purity":
"cdc hit purity",
544 save_hit_counts_by_pt_profile_groupbyCharge = refiners.save_profiles(
546 filter_on=
"is_matched",
548 "pt_truth":
"true p_{t}",
549 "n_pxd_hits":
"pxd hits",
550 "n_svd_hits":
"svd hits",
551 "n_cdc_hits":
"cdc hits",
558 groupby=[(
"charge_truth", [0.])],
567 save_hit_counts_by_tanlambda_profile_groupbyCharge = refiners.save_profiles(
569 filter_on=
"is_matched",
571 "tan_lambda_truth":
"true tan #lambda",
572 "n_pxd_hits":
"pxd hits",
573 "n_svd_hits":
"svd hits",
574 "n_cdc_hits":
"cdc hits",
581 groupby=[(
"charge_truth", [0.])],
590 save_hit_efficiency_by_pt_profile_groupbyCharge = refiners.save_profiles(
592 filter_on=
"is_matchedPrimary",
594 "pt_truth":
"true p_{t}",
595 "mc_pxd_hit_efficiency":
"pxd hit efficiency",
596 "mc_svd_hit_efficiency":
"svd hit efficiency",
597 "mc_cdc_hit_efficiency":
"cdc hit efficiency",
600 "pxd hit efficiency",
601 "svd hit efficiency",
602 "cdc hit efficiency",
604 groupby=[(
"charge_truth", [0.])],
613 save_hit_efficiency_by_tanlambda_profile_groupbyCharge = refiners.save_profiles(
615 filter_on=
"is_matchedPrimary",
617 "tan_lambda_truth":
"true tan #lambda",
618 "mc_pxd_hit_efficiency":
"pxd hit efficiency",
619 "mc_svd_hit_efficiency":
"svd hit efficiency",
620 "mc_cdc_hit_efficiency":
"cdc hit efficiency",
623 "pxd hit efficiency",
624 "svd hit efficiency",
625 "cdc hit efficiency",
627 groupby=[(
"charge_truth", [0.])],
635 save_hit_efficiency = refiners.save_fom(
637 name=
"{module.id}_subdetector_figures_of_merit",
638 title=
"Overview figures in {module.title}",
639 description=
"Hit efficiency in the subdetectors",
640 key=
"hit efficiency",
641 select=
"mc_hit_efficiency",
642 aggregation=np.nanmean,
643 filter_on=
"is_matchedPrimary"
648 save_pxd_hit_efficiency = refiners.save_fom(
650 name=
"{module.id}_subdetector_figures_of_merit",
651 title=
"Overview figures in {module.title}",
652 description=
"Hit efficiency in the subdetectors",
653 key=
"pxd hit efficiency",
654 select=
"mc_pxd_hit_efficiency",
655 aggregation=np.nanmean,
656 filter_on=
"is_matchedPrimary"
661 save_svd_hit_efficiency = refiners.save_fom(
663 name=
"{module.id}_subdetector_figures_of_merit",
664 title=
"Overview figures in {module.title}",
665 description=
"Hit efficiency in the subdetectors",
666 key=
"svd hit efficiency",
667 select=
"mc_svd_hit_efficiency",
668 aggregation=np.nanmean,
669 filter_on=
"is_matchedPrimary"
674 save_cdc_hit_efficiency = refiners.save_fom(
676 name=
"{module.id}_subdetector_figures_of_merit",
677 title=
"Overview figures in {module.title}",
678 description=
"Hit efficiency in the subdetectors",
679 key=
"cdc hit efficiency",
680 select=
"mc_cdc_hit_efficiency",
681 aggregation=np.nanmean,
682 filter_on=
"is_matchedPrimary"
687 save_hit_purity = refiners.save_fom(
689 name=
"{module.id}_subdetector_figures_of_merit",
690 title=
"Overview figures in {module.title}",
691 description=
"Hit purity in the subdetectors",
694 aggregation=np.nanmean,
695 filter_on=
"is_matchedPrimary"
700 save_pxd_hit_purity = refiners.save_fom(
702 name=
"{module.id}_subdetector_figures_of_merit",
703 title=
"Overview figures in {module.title}",
704 description=
"Hit purity in the subdetectors",
705 key=
"pxd hit purity",
706 select=
"pxd_hit_purity",
707 aggregation=np.nanmean,
708 filter_on=
"is_matchedPrimary"
713 save_svd_hit_purity = refiners.save_fom(
715 name=
"{module.id}_subdetector_figures_of_merit",
716 title=
"Overview figures in {module.title}",
717 description=
"Hit purity in the subdetectors",
718 key=
"svd hit purity",
719 select=
"svd_hit_purity",
720 aggregation=np.nanmean,
721 filter_on=
"is_matchedPrimary"
726 save_cdc_hit_purity = refiners.save_fom(
728 name=
"{module.id}_subdetector_figures_of_merit",
729 title=
"Overview figures in {module.title}",
730 description=
"Hit purity in the subdetectors",
731 key=
"cdc hit purity",
732 select=
"cdc_hit_purity",
733 aggregation=np.nanmean,
734 filter_on=
"is_matchedPrimary"
739 save_p_value_histogram = refiners.save_histograms(
741 filter_on=
"is_matched",
742 select={
"p_value":
"Genfit p value"},
744 The distribution of p values from the Genfit track fit.
745 If all errors are propagated correctly the distribution should be flat.
746 Generally some peaking behavior towards zero
is too be expected
if the errors are underestimated.
748 check="The distribution should be flat."
753 save_seed_omega_pull_analysis = refiners.save_pull_analysis(
755 filter_on=
"is_matched",
756 part_name=
"seed_omega",
757 quantity_name=
"seed #omega",
758 folder_name=
"pull_seed_omega",
759 truth_name=
"omega_truth",
765 save_seed_tan_lambda_pull_analysis = refiners.save_pull_analysis(
767 filter_on=
"is_matched",
768 part_name=
"seed_tan_lambda",
769 quantity_name=
"seed tan #lambda",
770 folder_name=
"pull_seed_tan_lambda",
771 truth_name=
"tan_lambda_truth",
776 save_fitted_omega_pull_analysis = refiners.save_pull_analysis(
778 filter_on=
"is_matched",
780 quantity_name=
"#omega",
781 folder_name=
"pull_fitted_omega",
787 save_fitted_tan_lambda_pull_analysis = refiners.save_pull_analysis(
789 filter_on=
"is_matched",
790 part_name=
"tan_lambda",
791 quantity_name=
"tan #lambda",
792 folder_name=
"pull_fitted_tan_lambda",
797 save_fitted_pt_pull_analysis = refiners.save_pull_analysis(
799 filter_on=
"is_matched",
801 quantity_name=
"p_{t}",
802 folder_name=
"pull_fitted_p_t",
807 save_fitted_x_pull_analysis = refiners.save_pull_analysis(
809 filter_on=
"is_matched",
812 folder_name=
"pull_fitted_x{groupby_addition}",
813 groupby=[
None, (
"pt_truth", [0.070, 0.250, 0.600])],
818 save_fitted_y_pull_analysis = refiners.save_pull_analysis(
820 filter_on=
"is_matched",
823 folder_name=
"pull_fitted_y{groupby_addition}",
824 groupby=[
None, (
"pt_truth", [0.070, 0.250, 0.600])],
829 save_fitted_z_pull_analysis = refiners.save_pull_analysis(
831 filter_on=
"is_matched",
834 folder_name=
"pull_fitted_z{groupby_addition}",
835 groupby=[
None, (
"pt_truth", [0.070, 0.250, 0.600])],
840 save_resolutions_by_pt_profile = refiners.save_profiles(
842 filter_on=
"is_matched",
844 "pt_truth":
"true p_{t}",
845 "d0_variance":
"#sigma(d_{0})",
846 "z0_variance":
"#sigma(z_{0})",
847 "pt_resolution":
"#sigma(p_{t}) / p_{t}",
852 "#sigma(p_{t}) / p_{t}",
A (simplified) python wrapper for StoreArray.
a (simplified) python wrapper for StoreObjPtr.
static const CDCMCHitLookUp & getInstance()
Getter for the singletone instance.
Class to provide convenient methods to look up matching information between pattern recognition and M...
mc_hit_lookup
Cache for the MC hit lookup.
mc_reco_tracks_det_hit_ids
Cache for the hit content of the Monte Carlo tracks - updated each event.
track_match_look_up
Reference to the track match lookup object reading the relation information constructed by the MCMatc...
mc_reco_tracks_name
Name of the StoreArray of the ideal mc tracks.
def peel(self, reco_track)
def peel_pr_to_mc_match_info(self, reco_track)
def __init__(self, name, contact, output_file_name=None, reco_tracks_name='RecoTracks', mc_reco_tracks_name='MCRecoTracks', expert_level=None)
def pick(self, reco_track)
reco_tracks_name
Name of the StoreArray of the tracks from pattern recognition.
int default_expert_level
the threshold value for the expert level