23 getHelixFromMCParticle,
24 getSeedTrackFitResult,
27 calc_ndf_from_det_hit_ids
33from ROOT
import Belle2
36ROOT.gSystem.Load(
"libtracking")
41 contains all information necessary for track filters to decide whether
42 track will be included into the processed list of tracks
43 This
class is used for both providing information on pattern reco and
91 """Filter that always passes"""
94 """Pattern-reconstructed track always passes"""
98 """MC track always passes"""
104 """Module to collect matching information about the found particles and to
105 generate validation plots and figures of merit on the performance of track finding.
"""
114 output_file_name=None,
115 track_filter_object=AlwaysPassFilter(),
116 plot_name_postfix=
'',
117 plot_title_postfix=
'',
118 exclude_profile_mc_parameter=
'',
119 exclude_profile_pr_parameter=
'',
120 use_expert_folder=
True,
121 trackCandidatesColumnName=
"RecoTracks",
122 mcTrackCandidatesColumName=
"MCRecoTracks",
123 non_expert_parameters=[
'p_{t}']
141 +
'TrackingValidation.root'
169 if "DO_NOT_READ_BINNING" not in os.environ:
173 basf2.B2INFO(
"If this is not wanted set the environment variable DO_NOT_READ_BINNING or remove reference files.")
175 basf2.B2INFO(
"Will not read binning from reference files.")
178 """Receive signal at the start of event processing"""
265 """Looks at the individual pattern reconstructed tracks and store information about them"""
275 for trackCand
in trackCands:
276 is_matched = trackMatchLookUp.isAnyChargeMatchedPRRecoTrack(trackCand)
277 is_clone = trackMatchLookUp.isAnyChargeClonePRRecoTrack(trackCand)
279 pt_truth = float(
'nan')
280 omega_truth = float(
'nan')
281 tan_lambda_truth = float(
'nan')
282 d0_truth = float(
'nan')
283 z0_truth = float(
'nan')
286 if is_matched
or is_clone:
288 mcParticle = trackMatchLookUp.getRelatedMCParticle(trackCand)
289 mcHelix = getHelixFromMCParticle(mcParticle)
290 omega_truth = mcHelix.getOmega()
291 tan_lambda_truth = mcHelix.getTanLambda()
292 pt_truth = mcParticle.getMomentum().Rho()
293 d0_truth = mcHelix.getD0()
294 z0_truth = mcHelix.getZ0()
299 mcParticle=mcParticle, mcParticles=mcParticles)
303 trackMatchLookUp.getRelatedTrackFitResult(trackCand)
304 filterProperties.wasFitted = prTrackFitResult
is not None
305 filterProperties.fitResult = prTrackFitResult
307 prTrackFitResult = getSeedTrackFitResult(trackCand)
308 filterProperties.seedResult = prTrackFitResult
314 omega_estimate = float(
'nan')
315 omega_variance = float(
'nan')
316 tan_lambda_estimate = float(
'nan')
317 tan_lambda_variance = float(
'nan')
318 d0_estimate = float(
'nan')
319 d0_variance = float(
'nan')
320 z0_estimate = float(
'nan')
321 pt_estimate = float(
'nan')
323 momentum = float(
'nan')
328 seed_momentum = trackCand.getMomentumSeed()
330 seed_tan_lambda = np.divide(1.0, math.tan(seed_momentum.Theta()))
331 seed_phi = seed_momentum.Phi()
332 seed_pt = seed_momentum.Rho()
335 omega_estimate = prTrackFitResult.getOmega()
336 omega_variance = prTrackFitResult.getCov()[9]
338 tan_lambda_estimate = prTrackFitResult.getCotTheta()
339 tan_lambda_variance = prTrackFitResult.getCov()[14]
341 d0_estimate = prTrackFitResult.getD0()
342 d0_variance = prTrackFitResult.getCov()[0]
344 z0_estimate = prTrackFitResult.getZ0()
346 momentum = prTrackFitResult.getMomentum()
347 pt_estimate = momentum.Rho()
357 isMatchedOrIsClone = is_matched
or is_clone
361 self.
pr_fakes.append(
not isMatchedOrIsClone)
382 """Looks at the individual Monte Carlo tracks and store information about them"""
392 multiplicity = mcTrackCands.getEntries()
393 multiplicity_primaries = multiplicity
399 for mcTrackCand
in mcTrackCands:
400 is_matched = trackMatchLookUp.isAnyChargeMatchedMCRecoTrack(mcTrackCand)
402 relatedPRtrackCand = trackMatchLookUp.getRelatedPRRecoTrack(mcTrackCand)
403 if relatedPRtrackCand:
404 is_chargeMatched = trackMatchLookUp.isChargeMatched(relatedPRtrackCand)
406 is_chargeMatched =
False
409 if mcTrackCand.getChargeSeed() > 0:
414 hit_efficiency = trackMatchLookUp.getRelatedEfficiency(mcTrackCand)
415 if math.isnan(hit_efficiency):
418 mcParticle = trackMatchLookUp.getRelatedMCParticle(mcTrackCand)
419 mcHelix = getHelixFromMCParticle(mcParticle)
424 mcParticles=mcParticles)
429 momentum = mcParticle.getMomentum()
431 tan_lambda = np.divide(1.0, math.tan(momentum.Theta()))
433 det_hit_ids = get_det_hit_ids(mcTrackCand)
434 ndf = calc_ndf_from_det_hit_ids(det_hit_ids)
444 self.
mc_phi.append(momentum.Phi())
446 if not is_primary(mcParticle):
447 multiplicity_primaries -= 1
449 charge_asymmetry = (n_matched_plus - n_matched_minus)/(n_matched_plus +
450 n_matched_minus)
if (n_matched_plus + n_matched_minus) != 0
else 0
451 for mcTrackCand
in mcTrackCands:
452 if is_primary(mcParticle):
460 """Receive signal at the end of event processing"""
470 if len(mc_matched_primaries) > 0
and sum(mc_matched_primaries) > 0:
471 charge_efficiency = np.average(self.
mc_charge_matches, weights=mc_matched_primaries)
474 charge_efficiency = float(
'nan')
475 hit_efficiency = float(
'nan')
481 clone_rate = 1.0 - np.average(self.
pr_matches,
484 clone_rate = float(
'nan')
487 figures_of_merit[
'finding_charge_efficiency'] = finding_charge_efficiency
488 figures_of_merit[
'finding_efficiency'] = finding_efficiency
489 figures_of_merit[
'charge_efficiency'] = charge_efficiency
490 figures_of_merit[
'charge_asymmetry'] = charge_asymmetry
491 figures_of_merit[
'fake_rate'] = fake_rate
492 figures_of_merit[
'clone_rate'] = clone_rate
493 figures_of_merit[
'hit_efficiency'] = hit_efficiency
495 figures_of_merit.description = \
497finding_efficiency - the ratio of matched Monte Carlo tracks to all primary Monte Carlo tracks <br/>
498charge_efficiency - the ratio of matched Monte Carlo tracks with correct charge to matched primary Monte Carlo tracks <br/>
499finding_charge_efficiency - the ratio of matched Monte Carlo tracks with correct charge to all primary Monte Carlo tracks <br/>
500fake_rate - ratio of pattern recognition tracks that are not related to a particle
501 (background, ghost) to all pattern recognition tracks <br/>
502clone_rate - ratio of clones divided the number of tracks that are related to a particle (clones and matches) <br/>
505 figures_of_merit.check = 'Compare for degradations with respect to the reference'
506 figures_of_merit.contact = contact
507 print(figures_of_merit)
511 validation_plots = []
517 'finding efficiency',
521 validation_plots.extend(plots)
527 print(
'fake list: ' + str(self.
pr_fakes.count(1)))
531 validation_plots.extend(plots)
536 'charge efficiency for matched primary tracks',
537 weights=mc_matched_primaries)
539 validation_plots.extend(plots)
544 'finding and charge efficiency for primary tracks',
547 validation_plots.extend(plots)
552 'charge asymmetry for primary tracks',
556 validation_plots.extend(plots)
561 'hit efficiency with matched tracks',
562 weights=mc_matched_primaries)
564 validation_plots.extend(plots)
569 all_but_diagonal_plots = list(PullAnalysis.default_which_plots)
570 all_but_diagonal_plots.remove(
"diag_profile")
571 all_but_diagonal_plots.remove(
"diag_scatter")
575 plot_name_prefix +=
'_seed'
582 curvature_pull_analysis =
PullAnalysis(
'#omega', unit=
'1/cm',
583 plot_name_prefix=plot_name_prefix +
'_omega',
587 curvature_pull_analysis.analyse(pr_omega_truths,
590 which_plots=all_but_diagonal_plots)
592 curvature_pull_analysis.contact = contact
593 pull_analyses.append(curvature_pull_analysis)
601 plot_name_prefix=plot_name_prefix +
'_tan_lambda',
605 curvature_pull_analysis.analyse(pr_tan_lambda_truths,
606 pr_tan_lambda_estimates,
607 pr_tan_lambda_variances,
608 which_plots=all_but_diagonal_plots)
610 curvature_pull_analysis.contact = contact
611 pull_analyses.append(curvature_pull_analysis)
615 plot_name_prefix=plot_name_prefix +
'_d0',
619 curvature_pull_analysis.analyse(np.array(self.
pr_d0_truths),
622 which_plots=all_but_diagonal_plots)
624 curvature_pull_analysis.contact = contact
625 pull_analyses.append(curvature_pull_analysis)
634 plot_name_prefix=plot_name_prefix +
'_d0_res',
637 d0_resolution_analysis.analyse(np.array(self.
pr_bining_pt),
640 d0_resolution_analysis.contact = contact
641 pull_analyses.append(d0_resolution_analysis)
647 plot_name_prefix=plot_name_prefix +
'_z0_res',
650 z0_resolution_analysis.analyse(np.array(self.
pr_bining_pt),
653 z0_resolution_analysis.contact = contact
654 pull_analyses.append(z0_resolution_analysis)
660 plot_name_prefix=plot_name_prefix +
'_omega_res',
663 omega_resolution_analysis.analyse(np.array(self.
pr_bining_pt),
666 omega_resolution_analysis.contact = contact
667 pull_analyses.append(omega_resolution_analysis)
673 plot_name_prefix=plot_name_prefix +
'_pt_res',
676 pt_resolution_analysis.analyse(np.array(self.
pr_bining_pt),
679 pt_resolution_analysis.contact = contact
680 pull_analyses.append(pt_resolution_analysis)
691 ROOT.gStyle.SetOptFit(opt_fit)
693 figures_of_merit.write()
695 for validation_plot
in validation_plots:
696 validation_plot.write()
699 expert_tdirectory = output_tfile.mkdir(
'expert',
'Expert')
700 expert_tdirectory.cd()
701 ROOT.gStyle.SetOptFit(opt_fit)
703 for pull_analysis
in pull_analyses:
704 pull_analysis.write()
725 """Create profile histograms by MC-track parameters"""
728 new_parameter_names = [item
for item
in parameter_names
if item
732 profile_parameters = {
749 is_asymmetry=is_asymmetry
757 parameter_names=['Seed_p_t', 'Seed tan
760 """Create profile histograms by PR-track parameters"""
763 new_parameter_names = [item
for item
in parameter_names
if item
767 profile_parameters = {
'Seed p_{t}': self.
pr_seed_pt,
791 """Create profile histograms for generic parameters"""
795 validation_plots = []
796 plot_name_prefix = self.
validation_name +
'_' + root_save_name(quantity_name) \
802 histogram.hist(xs, weights=weights)
804 histogram.xlabel = quantity_name
805 histogram.description =
'Not a serious plot yet.'
807 histogram.contact = contact
810 validation_plots.append(histogram)
812 for (parameter_name, parameter_values)
in list(profile_parameters.items()):
813 if parameter_name
in parameter_names \
814 or root_save_name(parameter_name)
in parameter_names:
818 parameter_root_name = root_save_name(parameter_name)
822 if 'tan_lambda' in parameter_root_name:
830 elif 'ndf' in parameter_root_name:
832 upper_bound = min(200, np.max(parameter_values))
833 elif 'p_t' in parameter_root_name:
840 elif 'd_0' in parameter_root_name:
852 profile_plot_name = plot_name_prefix +
'_by_' \
853 + root_save_name(parameter_name)
855 profile_plot.profile(parameter_values,
858 outlier_z_score=10.0,
859 lower_bound=lower_bound,
860 upper_bound=upper_bound,
863 is_asymmetry=is_asymmetry)
865 profile_plot.xlabel = compose_axis_label(parameter_name)
866 profile_plot.ylabel = compose_axis_label(quantity_name, unit)
867 profile_plot.title = quantity_name +
' by ' + parameter_name \
870 profile_plot.description = \
871 'Dependence of %s of the track over the true %s' \
872 % (quantity_name, parameter_name)
873 profile_plot.check =
'Variations should be low'
874 profile_plot.contact = contact
875 validation_plots.append(profile_plot)
877 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...
A (simplified) python wrapper for StoreArray.
Class to provide convenient methods to look up matching information between pattern recognition and M...
def doesPrPass(self, filterProperties)
def doesMcPass(self, filterProperties)
mcParticle
cached value of the MC particle
wasFitted
cached value of the fitted flag
def __init__(self, trackCand=None, mcParticle=None, mcParticles=None, wasFitted=False, fitResult=None, seedResult=None)
trackCand
cached value of the track candidate
seedResult
cached value of the seed result
fitResult
cached value of the fit result
mcParticles
cached value of the MCParticles StoreArray
mc_d0s
list of MC-track d0 values
pr_omega_variances
list of PR-track seed omega-variance values
exclude_profile_mc_parameter
cached list of perigee parameters excluded from MC side plots
track_filter_object
cached value of the track-filter object
pr_seed_tan_lambdas
list of PR-track seed tan(lambda) values
pr_tan_lambda_estimates
list of PR-track seed tan(lambda)-estimate values
pr_fakes
list of PR-track fakes
contact
cached value of the contact person name
fit
cached value of the track fit
pr_matches
list of PR-track matches
pr_bining_pt
list of PR-track binning values
def examine_pr_tracks(self)
pr_tan_lambda_variances
list of PR-track seed tan(lambda)-variance values
pr_pt_estimates
list of PR-track seed pt-estimate values
trackCandidatesColumnName
cached name of the RecoTracks StoreArray
pr_pt_truths
list of PR-track seed pt-truth values
pulls
cached values of the track-fit pulls
mc_ndf
list of MC-track number of degrees of freedom
pr_omega_truths
list of PR-track seed omega-truth values
pr_seed_phi
list of PR-track seed phi values
output_file_name
cached value of the output ROOT TFile
plot_name_postfix
cached value of the suffix appended to the plot names
trackMatchLookUp
Track-match object that examines relation information from MCMatcherTracksModule.
pr_omega_estimates
list of PR-track seed omega-estimate values
plot_title_postfix
cached value of the suffix appended to the plot titles
pr_z0_estimates
list of PR-track seed z0-estimate values
pr_d0_variances
list of PR-track seed d0-variance values
def profiles_by_pr_parameters(self, xs, quantity_name, unit=None, parameter_names=['Seed_p_t', 'Seed tan #lambda', 'Seed #phi'], make_hist=True)
mc_pts
list of MC-track pt values
resolution_pt_binning
default binning used for resolution plots over pt
mc_multiplicities
list of MC-track multiplicities
mc_matches
list of MC-track matches
def examine_mc_tracks(self)
pr_clones_and_matches
Use dequeues in favour of lists to prevent repeated memory allocation of cost O(n)
mc_primaries
list of MC-track primaries
non_expert_parameters
list of parameters that determines which plots (all with corresponding x-axis) are marked as shifter ...
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", non_expert_parameters=['p_{t}'])
resolution
cached value of the resolution
referenceFileName
If this variable is set the code will open the file with same name as the file created here and will ...
use_expert_folder
cached flag to use the "expert" folder for the pull and residual plots
def profiles_by_mc_parameters(self, xs, quantity_name, unit=None, parameter_names=['d_0', 'p_t', 'tan_lambda', 'multiplicity', 'phi', 'ndf',], make_hist=True, weights=None, is_asymmetry=False)
pr_seed_pt
list of PR-track seed pt values
pr_z0_truths
list of PR-track seed z0-truth values
mc_phi
direction of the track in phi
mcTrackCandidatesColumnName
cached name of the MCRecoTracks StoreArray
pr_tan_lambda_truths
list of PR-track seed tan(lambda)-truth values
pr_d0_estimates
list of PR-track seed d0-estimate values
validation_name
cached value of the tracking-validation name
mc_charge_asymmetry_weights
list of MC-track matches charge asymmetry weights
mc_tan_lambdas
list of MC-track tan(lambda) values
mc_hit_efficiencies
list of MC-track hit efficiencies
pr_d0_truths
list of PR-track seed d0-truth values
mc_charge_matches
list of MC-track matches, including matched charge
mc_charge_asymmetry
list of MC-track matches charge asymmetry
exclude_profile_pr_parameter
cached list of perigee parameters excluded from PR side plots
def profiles_by_parameters_base(self, xs, quantity_name, parameter_names, profile_parameters, unit, make_hist, weights=None, is_asymmetry=False)