File indexing completed on 2026-03-29 08:37:27
0001 import os
0002 from datetime import datetime
0003 from matplotlib.backends.backend_pdf import PdfPages
0004 import matplotlib.pyplot as plt
0005
0006 _PDF_BASENAME = 'plot_single_resol'
0007 _PDF_COVER_ADDED = False
0008
0009 def _cover_title_from_globals():
0010 for key in ('tag', 'fname'):
0011 if key in globals() and globals()[key] is not None:
0012 val = str(globals()[key])
0013 return os.path.basename(val)
0014 return _PDF_BASENAME
0015
0016 def _add_pdf_cover(fname, pdf_pages):
0017 fig = plt.figure(figsize=(8.5, 11))
0018 fig.text(0.5, 0.6, 'source file: '+fname+'.root', ha='center', va='center', fontsize=16)
0019 fig.text(0.5, 0.5, datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
0020 ha='center', va='center', fontsize=12)
0021 pdf_pages.savefig(fig)
0022 plt.close(fig)
0023
0024 _PDF_PATH = f'{_PDF_BASENAME}_figures.pdf'
0025 _pdf_pages = PdfPages(_PDF_PATH)
0026
0027 def _save_new_figs(figs_before):
0028 global _PDF_COVER_ADDED
0029 if not _PDF_COVER_ADDED:
0030 _add_pdf_cover(_cover_title_from_globals(), _pdf_pages)
0031 _PDF_COVER_ADDED = True
0032 for num in plt.get_fignums():
0033 if num not in figs_before:
0034 _pdf_pages.savefig(plt.figure(num))
0035
0036
0037
0038
0039
0040
0041 import sys
0042 from pathlib import Path
0043 import numpy as np
0044 import pandas as pd
0045 import matplotlib.pyplot as plt
0046
0047 repo_root = Path('/global/homes/s/shujie/eic_dir/worksim/scripts/modules')
0048 if str(repo_root) not in sys.path:
0049 sys.path.insert(0, str(repo_root))
0050
0051 import epic_analysis_base as ana
0052 ana.configure_analysis_environment()
0053
0054
0055
0056
0057
0058
0059
0060 deg_list=['3to50deg']
0061 mom_list=['500MeV', '1GeV', '2GeV', '5GeV', '10GeV', '20GeV']
0062 deg_name = deg_list[0]
0063 mom_name = mom_list[0]
0064 s3_path = f"EPIC/RECO/25.12.0/epic_craterlake/SINGLE/pi+/{mom_name}/{deg_name}/"
0065 fname = f"pi+_{mom_name}_{deg_name}.0001.eicrecon.edm4eic.root"
0066
0067 ana.COL_TABLE = ana.get_col_table(fname,s3_dir=s3_path)
0068 tree = ana.read_ur(fname, 'events',s3_dir=s3_path)
0069
0070 tag=fname.split('/')[-1]
0071 tag=tag.split('.root')[0]
0072
0073 track_params = 'CentralCKFTrackParameters'
0074 assoc_name = 'CentralCKFTrackAssociations'
0075 cov_branch = f'{track_params}/{track_params}.covariance.covariance[21]'
0076
0077 def _col_id(name):
0078 return next(k for k, v in ana.COL_TABLE.items() if v == name)
0079
0080 track_col_id = _col_id('CentralCKFTracks')
0081 mc_col_id = _col_id('MCParticles')
0082
0083 params = ana.get_branch_df(tree, track_params)
0084 cov_df = ana.get_branch_df(tree, cov_branch)
0085 cov_wide = cov_df.pivot_table(index=['entry', 'subentry'], columns='subsubentry', values='values')
0086 cov_wide.columns = [f'cov_{c}' for c in cov_wide.columns]
0087 cov_wide = cov_wide.reset_index()
0088
0089 params = params.merge(cov_wide, on=['entry', 'subentry'], how='left')
0090 params = params.rename(columns={'subentry': 'track_index', 'theta': 'theta_rec', 'phi': 'phi_rec', 'qOverP': 'qOverP_rec'})
0091
0092 rec_assoc = ana.get_branch_df(tree, f'_{assoc_name}_rec')
0093 sim_assoc = ana.get_branch_df(tree, f'_{assoc_name}_sim')
0094 assoc = rec_assoc[['entry', 'subentry', 'index', 'collectionID']].rename(
0095 columns={'subentry': 'assoc_index', 'index': 'track_index', 'collectionID': 'track_colID'}
0096 )
0097 assoc['mc_index'] = sim_assoc['index']
0098 assoc['mc_colID'] = sim_assoc['collectionID']
0099 assoc = assoc[(assoc['track_colID'] == track_col_id) & (assoc['mc_colID'] == mc_col_id)]
0100
0101 df = assoc.merge(params, on=['entry', 'track_index'], how='inner')
0102
0103 mc = ana.get_branch_df(tree, 'MCParticles')
0104 mc = mc.rename(columns={'subentry': 'mc_index'})
0105 mc['p_mc'] = np.sqrt(mc['momentum.x']**2 + mc['momentum.y']**2 + mc['momentum.z']**2)
0106 mc['theta_mc'] = np.arccos(mc['momentum.z'] / mc['p_mc'])
0107 mc['phi_mc'] = np.arctan2(mc['momentum.y'], mc['momentum.x'])
0108 mc['qOverP_true'] = mc['charge'] / mc['p_mc']
0109
0110 df = df.merge(mc[['entry', 'mc_index', 'theta_mc', 'phi_mc', 'qOverP_true', 'p_mc']], on=['entry', 'mc_index'], how='inner')
0111
0112 valid = (df['cov_5'] > 0) & (df['cov_9'] > 0) & (df['cov_14'] > 0)
0113 valid &= np.isfinite(df['theta_rec']) & np.isfinite(df['phi_rec']) & np.isfinite(df['qOverP_rec'])
0114 valid &= np.isfinite(df['theta_mc']) & np.isfinite(df['phi_mc']) & np.isfinite(df['qOverP_true'])
0115 df = df[valid]
0116
0117 df['pull_theta'] = (df['theta_rec'] - df['theta_mc']) / np.sqrt(df['cov_9'])
0118 df['pull_phi'] = (df['phi_rec'] - df['phi_mc']) / np.sqrt(df['cov_5'])
0119 df['pull_qoverp'] = (np.abs(df['qOverP_rec']) - np.abs(df['qOverP_true'])) / np.sqrt(df['cov_14'])
0120
0121
0122
0123 df['resol_theta'] = (df['theta_rec'] - df['theta_mc']) *1000
0124 df['resol_phi'] = (df['phi_rec'] - df['phi_mc']) *1000
0125 df['p_rec'] = (1./np.abs(df['qOverP_rec']))
0126 df['resol_dp'] = (df['p_rec'] - df['p_mc'])/df['p_mc']*100
0127
0128 _fig_nums_before = set(plt.get_fignums())
0129 bins = np.arange(-4, 4, 0.1)
0130 eta_mc_in_rec = ana.theta2eta(df['theta_mc'])
0131 eta_mc = ana.theta2eta(mc[mc.generatorStatus == 1]['theta_mc'])
0132
0133 ha_counts, bin_edges = np.histogram(eta_mc_in_rec, bins=bins)
0134 hb_counts, _ = np.histogram(eta_mc, bins=bins)
0135
0136 bin_centers = 0.5 * (bin_edges[:-1] + bin_edges[1:])
0137 eff = np.divide(ha_counts, hb_counts, out=np.zeros_like(ha_counts, dtype=float), where=hb_counts > 0)
0138 eff_err = np.zeros_like(eff)
0139 mask = hb_counts > 0
0140 eff_err[mask] = np.sqrt(eff[mask] * (1.0 - eff[mask]) / hb_counts[mask])
0141
0142 fig, (ax_top, ax_bot) = plt.subplots(2,1, figsize=(7, 6), sharex=True, gridspec_kw={'height_ratios': [3, 2]})
0143 ax_top.hist(eta_mc, bins=bins, histtype='step', color='black', label='Gen')
0144 ax_top.hist(eta_mc_in_rec, bins=bins, histtype='step', color='tab:blue', label='Reco matched')
0145 ax_top.set_ylabel('Entries')
0146 ax_top.legend(frameon=False)
0147 ax_top.grid(True, alpha=0.3)
0148
0149 ax_bot.errorbar(bin_centers, eff, yerr=eff_err, fmt='o', ms=3, lw=1, color='tab:blue', ecolor='gray', capsize=2)
0150 ax_bot.axhline(1.0, color='gray', lw=1, ls='--')
0151 ax_bot.set_xlabel(r'$\eta$')
0152 ax_bot.set_ylabel('Efficiency')
0153 ax_bot.set_xlim(bin_edges[0], bin_edges[-1])
0154 ax_bot.set_ylim(0, 1.05)
0155 ax_bot.grid(True, alpha=0.3)
0156 plt.tight_layout()
0157
0158 _save_new_figs(_fig_nums_before)
0159
0160 _fig_nums_before = set(plt.get_fignums())
0161 import math
0162 plots = [
0163 ('pull_theta' , 'Pull distribution(theta)'),
0164 ('pull_phi' , 'Pull distribution(phi)'),
0165 ('pull_qoverp', 'Pull distribution(q/p)'),
0166 ('resol_theta', 'Resolution (theta[mrad])'),
0167 ('resol_phi' , 'Resolution (phi[mrad])'),
0168 ('resol_dp' , 'Resolution (dp/p[%])'),
0169 ('loc.a' , 'Resolution (DCA$_r$[mm])'),
0170 ]
0171
0172 cols = 3
0173 rows = math.ceil(len(plots) / cols)
0174 fig, axes = plt.subplots(rows, cols, figsize=(4 * cols, 3 * rows))
0175
0176 def _label_from_title(title):
0177 ss=title.split("(")
0178 label1=ss[0]+":"
0179 label2 = ss[1].replace(')', '')
0180 return label1, label2
0181
0182 axes_flat = axes.flatten()
0183 for ax, (col, title) in zip(axes_flat, plots):
0184 bins = 101
0185 mean, sigma, sigma_err = ana.hist_gaus(df[col], ax, bins=bins)
0186 label1,label2 = _label_from_title(title)
0187 if np.isfinite(sigma) and np.isfinite(sigma_err):
0188 label2 = f'{label2} = {sigma:.3g} +/- {sigma_err:.3g}'
0189 ax.text(
0190 0.05,
0191 0.9,
0192 label1+"\n"+label2,
0193 transform=ax.transAxes,
0194 ha='left',
0195 va='center',
0196 fontsize=12,
0197 bbox=dict(boxstyle='round,pad=0.2', facecolor='white', alpha=0.7, edgecolor='none'),
0198 )
0199 ax.set_ylabel('Entries')
0200 ax.set_xlabel('')
0201 ax.grid(True, alpha=0.3)
0202
0203 for ax in axes_flat[len(plots):]:
0204 ax.axis('off')
0205
0206 plt.tight_layout()
0207
0208
0209 _save_new_figs(_fig_nums_before)
0210
0211
0212 _pdf_pages.close()