File indexing completed on 2026-09-26 08:07:54
0001 import numpy as np, pandas as pd, matplotlib.pyplot as plt, matplotlib as mpl, awkward as ak, sys, uproot as ur
0002 import mplhep as hep
0003 hep.style.use("CMS")
0004
0005 plt.rcParams['figure.facecolor']='white'
0006 plt.rcParams['savefig.facecolor']='white'
0007 plt.rcParams['savefig.bbox']='tight'
0008
0009 plt.rcParams["figure.figsize"] = (7, 7)
0010
0011 config=sys.argv[1].split("/")[1]
0012 outdir=sys.argv[1]+"/"
0013 try:
0014 import os
0015 os.mkdir(outdir[:-1])
0016 except:
0017 pass
0018
0019 import uproot as ur
0020 arrays_sim={p:ur.open(f'sim_output/femc_electron/{config}_rec_e-_{p}GeV.edm4eic.root:events').arrays() for p in (10, 20, 30, 40, 50, 60,70,80)}
0021
0022 for p in arrays_sim:
0023 array=arrays_sim[p]
0024 tilt=-.025
0025 px=array['MCParticles.momentum.x'][:,2]
0026 py=array['MCParticles.momentum.y'][:,2]
0027 pz=array['MCParticles.momentum.z'][:,2]
0028 p=np.sqrt(px**2+py**2+pz**2)
0029
0030 pxp=px*np.cos(tilt)-pz*np.sin(tilt)
0031 pyp=py
0032 pzp=pz*np.cos(tilt)+px*np.sin(tilt)
0033
0034 array['eta_truth']=1/2*np.log((p+pzp)/(p-pzp))
0035 array['nclust_endcap']=[len(array['EcalEndcapPClusters.energy'][i]) for i in range(len(array))]
0036
0037 for array in arrays_sim.values():
0038 tilt=-0.025
0039 px=array['MCParticles.momentum.x'][:,2]
0040 py=array['MCParticles.momentum.y'][:,2]
0041 pz=array['MCParticles.momentum.z'][:,2]
0042 p=np.sqrt(px**2+py**2+pz**2)
0043
0044 pxp=px*np.cos(tilt)-pz*np.sin(tilt)
0045 pyp=py
0046 pzp=pz*np.cos(tilt)+px*np.sin(tilt)
0047
0048 array['eta_truth']=1/2*np.log((p+pzp)/(p-pzp))
0049 array['phi_truth']=np.arctan2(pyp,pxp)
0050
0051
0052 plt.figure()
0053 for eta_min, eta_max, field in (1.5, 2.8, 'nclust_endcap'),:
0054 for p in arrays_sim:
0055 array=arrays_sim[p]
0056 plt.hist(array[field][(array['eta_truth']>eta_min)&(array['eta_truth']<eta_max)],
0057 bins=np.linspace(0,10,11), histtype='step', label=f'{p} GeV', density=True)
0058 plt.ylabel("events")
0059 plt.xlabel("# of Ecal clusters")
0060 plt.legend()
0061 plt.savefig(outdir+f"/{field}.pdf")
0062
0063
0064
0065 fig, axs=plt.subplots(1,2, figsize=(16,8))
0066 avgs=[]
0067 stds=[]
0068 pvals=[]
0069
0070 for p in arrays_sim:
0071
0072 a=arrays_sim[p]
0073 n=[]
0074 nn=-a['EcalEndcapPClusters.hits_begin']+a['EcalEndcapPClusters.hits_end']
0075 E=a['EcalEndcapPClusters.energy']
0076 for evt in range(len(array)):
0077 if len(E[evt])==0:
0078 continue
0079 maxE=np.max(E[evt])
0080 found=False
0081 for i in range(len(E[evt])):
0082 if E[evt][i]==maxE:
0083 n.append(nn[evt][i])
0084 found=True
0085 break
0086
0087
0088
0089 if p ==50:
0090 plt.sca(axs[0])
0091 y,x,_=plt.hist(n, range=(0,100), bins=100, histtype='step', label=f"E={p} GeV")
0092 plt.ylabel("events")
0093 plt.xlabel("# hits in cluster")
0094 plt.title(f"e-, E={p} GeV")
0095 pvals.append(p)
0096 avgs.append(np.mean(n))
0097 stds.append(np.std(n))
0098
0099 plt.sca(axs[1])
0100 plt.errorbar(pvals, avgs, stds, marker='o',ls='')
0101 plt.xlabel("E [GeV]")
0102 plt.ylabel("# hits in cluster [mean$\\pm$std]")
0103 plt.ylim(0)
0104 plt.savefig(outdir+"/nhits_per_cluster.pdf")
0105
0106
0107
0108 def gauss(x, A,mu, sigma):
0109 return A * np.exp(-(x-mu)**2/(2*sigma**2))
0110 from scipy.optimize import curve_fit
0111
0112 fig, axs=plt.subplots(1,3, figsize=(24,8))
0113 pvals=[]
0114 res=[]
0115 dres=[]
0116 scale=[]
0117 dscale=[]
0118 for p in arrays_sim:
0119 bins=np.linspace(15*p/20,22*p/20, 50)
0120 if p==50:
0121 plt.sca(axs[0])
0122 plt.title(f"E={p} GeV")
0123 y,x,_=plt.hist(ak.flatten(arrays_sim[p]['EcalEndcapPClusters.energy']), bins=bins, histtype='step')
0124 plt.ylabel("events")
0125 plt.xlabel("$E^{rec}_e$ [GeV]")
0126 else:
0127 y,x=np.histogram(ak.flatten(arrays_sim[p]['EcalEndcapPClusters.energy']), bins=bins)
0128 bcs=(x[1:]+x[:-1])/2
0129
0130 fnc=gauss
0131 slc=abs(bcs-p)<3
0132 sigma=np.sqrt(y[slc])+0.5*(y[slc]==0)
0133 p0=(100, p, 3)
0134
0135 try:
0136 coeff, var_matrix = curve_fit(fnc, list(bcs[slc]), list(y[slc]), p0=p0, sigma=list(sigma), maxfev=10000)
0137
0138 if p==50:
0139 xx=np.linspace(15*p/20,22*p/20, 100)
0140
0141 plt.plot(xx, fnc(xx,*coeff), label=f"$\\sigma_E/E={abs(coeff[2])/coeff[1]*100:.1f}\%$")
0142 plt.axvline(p, color='g', ls='--', alpha=0.7)
0143 plt.legend()
0144
0145
0146 pvals.append(p)
0147 res.append(abs(coeff[2])/coeff[1])
0148 dres.append(np.sqrt(var_matrix[2][2])/coeff[1])
0149 scale.append(abs(coeff[1])/p)
0150 dscale.append(np.sqrt(var_matrix[1][1])/p)
0151 except RuntimeError as e:
0152 print(e)
0153 print("x:", list(bcs[slc]), "y:", list(y[slc]))
0154 plt.sca(axs[1])
0155 plt.errorbar(pvals, 100*np.array(res), 100*np.array(dres), ls='', marker='o')
0156 fnc = lambda E, a, b: np.hypot(a,b/np.sqrt(E))
0157 p0=(.05, .12)
0158 try:
0159 coeff, var_matrix = curve_fit(fnc, pvals, res, p0=p0, sigma=dres, maxfev=10000)
0160 xx=np.linspace(7, 85, 100)
0161 plt.plot(xx, 100*fnc(xx,*coeff), label=f'fit:{100*coeff[0]:.1f}%$\\oplus\\frac{{{100*coeff[1]:.0f}\\%}}{{\\sqrt{{E}}}}$')
0162 plt.legend()
0163 plt.ylim(0)
0164 plt.ylabel("E resolution [%]")
0165 plt.xlabel("E truth [GeV]")
0166 except RuntimeError:
0167 print("fit failed")
0168 plt.sca(axs[2])
0169
0170 plt.errorbar(pvals, 100*np.array(scale), 100*np.array(dscale), ls='', marker='o')
0171 plt.ylabel("energy scale [%]")
0172 plt.xlabel("E truth [GeV]")
0173 plt.axhline(100, color='0.5', alpha=0.5, ls='--')
0174 plt.ylim(0, 110)
0175 plt.tight_layout()
0176 plt.savefig(outdir+"/energy_res.pdf")
0177
0178
0179 fig, axs=plt.subplots(1,2, figsize=(16,8))
0180
0181 partitions=[1.5, 2.0, 2.5, 3.0]
0182 for eta_min, eta_max in zip(partitions[:-1], partitions[1:]):
0183 pvals=[]
0184 res=[]
0185 dres=[]
0186 scale=[]
0187 dscale=[]
0188 for p in arrays_sim:
0189 bins=np.linspace(15*p/20,22*p/20, 50)
0190 eta_truth=arrays_sim[p]['eta_truth']
0191 y,x=np.histogram(ak.flatten(arrays_sim[p][(eta_truth<eta_max)&(eta_truth>eta_min)]['EcalEndcapPClusters.energy']), bins=bins)
0192 bcs=(x[1:]+x[:-1])/2
0193
0194 fnc=gauss
0195 slc=abs(bcs-p)<3
0196 sigma=np.sqrt(y[slc])+0.5*(y[slc]==0)
0197 p0=(100, p, 3)
0198
0199 try:
0200 coeff, var_matrix = curve_fit(fnc, list(bcs[slc]), list(y[slc]), p0=p0, sigma=list(sigma), maxfev=10000)
0201 if abs(coeff[1])>100 or np.sqrt(var_matrix[1][1])>100:
0202 continue
0203 pvals.append(p)
0204 res.append(abs(coeff[2])/coeff[1])
0205 dres.append(np.sqrt(var_matrix[2][2])/coeff[1])
0206 scale.append(abs(coeff[1])/p)
0207 dscale.append(np.sqrt(var_matrix[1][1])/p)
0208 except:
0209 pass
0210 plt.sca(axs[0])
0211 plt.errorbar(pvals, 100*np.array(res), 100*np.array(dres), ls='', marker='o', label=f'${eta_min:.1f}<\\eta<{eta_max:.1f}$')
0212
0213 plt.sca(axs[1])
0214 plt.errorbar(pvals, 100*np.array(scale), 100*np.array(dscale), ls='', marker='o', label=f'${eta_min:.1f}<\\eta<{eta_max:.1f}$')
0215
0216 plt.sca(axs[0])
0217 plt.legend()
0218 plt.ylim(0)
0219 plt.ylabel("E resolution [%]")
0220 plt.xlabel("E truth [GeV]")
0221
0222 plt.sca(axs[1])
0223 plt.ylabel("energy scale [%]")
0224 plt.xlabel("E truth [GeV]")
0225 plt.axhline(100, color='0.5', alpha=0.5, ls='--')
0226 plt.ylim(0, 110)
0227
0228 plt.tight_layout()
0229 plt.savefig(outdir+"/energy_res_eta_partitions.pdf")