diff --git a/benchmarks/neutron/analysis/neutron_plots.py b/benchmarks/neutron/analysis/neutron_plots.py index 41583b9c9e592e96b2aee498cbda9e8a14355b2d..fc1d5b30e6249a1ee5cc9ee51a1b1cce4225f238 100644 --- a/benchmarks/neutron/analysis/neutron_plots.py +++ b/benchmarks/neutron/analysis/neutron_plots.py @@ -21,7 +21,6 @@ for p in 20,30,40,50,60,70,80: arrays_sim[p] = ur.open(f'sim_output/neutron/{config}_rec_neutron_{p}GeV.edm4hep.root:events')\ .arrays() -#get reconstructed theta, eta, and E def gauss(x, A,mu, sigma): return A * np.exp(-(x-mu)**2/(2*sigma**2)) @@ -41,7 +40,8 @@ for array in arrays_sim.values(): array['eta_truth']=1/2*np.log((p+pzp)/(p-pzp)) array['theta_truth']=np.arccos(pzp/p) -#weighted avg of theta of cluster centers, by energy +# +# get reconstructed theta as avg of theta of cluster centers, weighted by energy for array in arrays_sim.values(): tilt=-0.025 x=array['HcalEndcapPInsertClusters.position.x'] @@ -59,14 +59,9 @@ for array in arrays_sim.values(): array['theta_recon']=np.sum(np.arccos(zp/r)*w, axis=-1)/np.sum(w, axis=-1) array['eta_recon']=-np.log(np.tan(array['theta_recon']/2)) - - array['E_Hcal']=np.sum(array['HcalEndcapPInsertClusters.energy'], axis=-1)#*20/12.5 - array['E_Ecal']=np.sum(array['EcalEndcapPInsertClusters.energy'], axis=-1)#*27/20 - - array['E_recon']=array['E_Hcal']/(0.70-.30/np.sqrt(array['E_Hcal']))\ - +array['E_Ecal']/(0.82-0.35/np.sqrt(array['E_Ecal'])) #plot theta residuals: +print("making theta recon plot") from scipy.optimize import curve_fit fig, axs=plt.subplots(1,2, figsize=(16,8)) @@ -91,7 +86,7 @@ plt.xlabel("$\\theta_{rec}-\\theta_{truth}$ [mrad]") plt.ylabel("events") plt.title(f"$p={p}$ GeV, ${eta_min}<\\eta<{eta_max}$") -r=[3.0,3.2,3.4,3.6,3.8] +r=[3.2,3.4,3.6,3.8,4.0] for eta_min, eta_max in zip(r[:-1],r[1:]): xvals=[] sigmas=[] @@ -122,54 +117,165 @@ plt.legend() plt.tight_layout() plt.savefig(outdir+"neutron_theta_recon.pdf") -fig, axs=plt.subplots(1,2, figsize=(16,8)) -plt.sca(axs[0]) -p=50 -eta_min=3.4; eta_max=3.6 -y,x,_=plt.hist(((arrays_sim[p]['E_recon']-arrays_sim[p]['E_truth'])/arrays_sim[p]['E_truth'])\ - [(arrays_sim[p]['eta_truth']>eta_min)&(arrays_sim[p]['eta_truth']<eta_max)&(arrays_sim[p]['E_Hcal']>0)], bins=50, - range=(-.5,.5), histtype='step') -bc=(x[1:]+x[:-1])/2 -slc=abs(bc)<0.4 -# try: -p0=(100, 0, 0.3) -fnc=gauss -sigma=np.sqrt(y[slc])+(y[slc]==0) -coeff, var_matrix = curve_fit(fnc, list(bc[slc]), list(y[slc]), p0=p0,sigma=list(sigma)) -xx=np.linspace(-.5,.5,100) -plt.plot(xx,fnc(xx,*coeff)) -# except: -# pass -plt.xlabel("$(E_{rec}-E_{truth})/E_{truth}$") -plt.ylabel("events") -plt.title(f"$p={p}$ GeV, ${eta_min}<\\eta<{eta_max}$") +#now determine the energy recon parameters +pvals=[] +resvals=[] +reserrs=[] +wvals=[] +svals=[] +Euncorr=[] -r=[3.0,3.2,3.4,3.6,3.8] -for eta_min, eta_max in zip(r[:-1],r[1:]): - xvals=[] - sigmas=[] - dsigmas=[] - for p in 20,30,40, 50, 60, 70, 80: - y,x=np.histogram(((arrays_sim[p]['E_recon']-arrays_sim[p]['E_truth'])/arrays_sim[p]['E_truth'])\ - [(arrays_sim[p]['eta_truth']>eta_min)&(arrays_sim[p]['eta_truth']<eta_max)], bins=50, range=(-.5,.5)) - bc=(x[1:]+x[:-1])/2 - slc=abs(bc)<0.5 +print("determining the energy recon correction parameters") +fig,axs=plt.subplots(1,2, figsize=(20,10)) +eta_min=3.4;eta_max=3.6 +for p in 20, 30,40,50,60,70, 80: + best_res=1000 + res_err=1000 + best_s=1000 + wrange=np.linspace(30, 70, 41)*0.0257 + coeff_best=None + + wbest=0 + a=arrays_sim[p] + h=np.sum(a[f'HcalEndcapPInsertClusters.energy'], axis=-1) + e=np.sum(a[f'EcalEndcapPInsertClusters.energy'], axis=-1) + for w in wrange: + + r=(e/w+h)[(h>0)&(a['eta_truth']>eta_min)&(a['eta_truth']<eta_max)] + y,x=np.histogram(r,bins=50) + bcs=(x[1:]+x[:-1])/2 fnc=gauss - p0=(100, 0, 0.3) - #print(bc[slc],y[slc]) - sigma=np.sqrt(y[slc])+(y[slc]==0) + slc=abs(bcs-np.mean(r)*1.25)<2*np.std(r) + sigma=np.sqrt(y[slc])+0.5*(y[slc]==0) + p0=(100, np.mean(r), np.std(r)) try: - coeff, var_matrix = curve_fit(fnc, list(bc[slc]), list(y[slc]), p0=p0,sigma=list(sigma)) - sigmas.append(np.abs(coeff[2])) - dsigmas.append(np.sqrt(var_matrix[2][2])) - xvals.append(p) - except: - pass - plt.sca(axs[1]) - plt.errorbar(xvals, sigmas, dsigmas, ls='', marker='o', label=f"${eta_min}<\\eta<{eta_max}$") -plt.xlabel("$p_{n}$ [GeV]") -plt.ylabel("$\\sigma[E]/E$") -plt.ylim(0) + coeff, var_matrix = curve_fit(fnc, list(bcs[slc]), list(y[slc]), p0=p0,sigma=list(sigma)) + res=np.abs(coeff[2]/coeff[1]) + + if res<best_res: + best_res=res + coeff_best=coeff + res_err=res*np.hypot(np.sqrt(var_matrix[2][2])/coeff[2], np.sqrt(var_matrix[1][1])/coeff[1]) + wbest=w + best_s=np.hypot(p,0.9406)/coeff[1] + Euncorr_best=coeff[1] + except : + print("fit failed") + + if p==50: + r=(e/wbest+h)[(h>0)&(a['eta_truth']>3.4)&(a['eta_truth']<3.6)] + plt.sca(axs[0]) + y, x, _= plt.hist(r, histtype='step', bins=50) + xx=np.linspace(20, 55, 100) + plt.plot(xx,fnc(xx, *coeff_best), ls='-') + plt.xlabel("$E_{uncorr}=E_{Hcal}+E_{Ecal}/w$ [GeV]") + plt.title(f"p=50 GeV, ${eta_min}<\\eta<{eta_max}$, w={wbest:.2f}") + plt.axvline(np.sqrt(50**2+.9406**2), color='g', ls=':') + plt.text(40, max(y)*0.9, "generated\nenergy", color='g', fontsize=20) + + Euncorr.append(Euncorr_best) + resvals.append(best_res) + reserrs.append(res_err) + pvals.append(p) + svals.append(best_s) + wvals.append(wbest) + +pvals=np.array(pvals) +svals=np.array(svals) +Euncorr=np.array(Euncorr) +plt.sca(axs[1]) +plt.plot(Euncorr,wvals, label="w") +w_avg=np.mean(wvals) +plt.axhline(w_avg, label=f'w avg: {w_avg:.2f}', ls=':') +plt.plot(Euncorr,svals, label="s") +m=(np.sum(svals*Euncorr)*len(Euncorr)-np.sum(Euncorr)*np.sum(svals))/(np.sum(Euncorr**2)*len(Euncorr)-np.sum(Euncorr)**2) +b=np.mean(svals)-np.mean(Euncorr)*m +plt.plot(Euncorr,Euncorr*m+b, label=f"s fit: ${m:.4f}E_{{uncorr}}+{b:.2f}$", ls=':') + +plt.xlabel("$E_{uncorr}=E_{Hcal}+E_{Ecal}/w$ [GeV]") +plt.title("$E_{n,recon}=s\\times(E_{Hcal}+E_{Ecal}/w)$") +plt.ylabel('parameter values') plt.legend() +plt.ylim(0) +plt.savefig(outdir+"neutron_energy_params.pdf") + +#now make the energy plot +print("making energy recon plot") +fig, axs=plt.subplots(1,3, figsize=(24,8)) +partitions=[3.2,3.4, 3.6, 3.8, 4.0] +for eta_min, eta_max in zip(partitions[:-1],partitions[1:]): + pvals=[] + resvals=[] + reserrs=[] + scalevals=[] + scaleerrs=[] + for p in 20, 30,40,50,60,70, 80: + best_res=1000 + res_err=1000 + + + wrange=np.linspace(30, 70, 30)*0.0257 + + w=w_avg + a=arrays_sim[p] + h=np.sum(a[f'HcalEndcapPInsertClusters.energy'], axis=-1) + e=np.sum(a[f'EcalEndcapPInsertClusters.energy'], axis=-1) + #phi=a['phi_truth'] + uncorr=(e/w+h) + s=-0.0064*uncorr+1.80 + r=uncorr*s #reconstructed energy with correction + r=r[(h>0)&(a['eta_truth']>eta_min)&(a['eta_truth']<eta_max)]#&(abs(phi)>np.pi/2)] + y,x=np.histogram(r,bins=50) + bcs=(x[1:]+x[:-1])/2 + fnc=gauss + slc=abs(bcs-np.mean(r)*1.25)<2*np.std(r) + sigma=np.sqrt(y[slc])+0.5*(y[slc]==0) + p0=(100, np.mean(r), np.std(r)) + try: + coeff, var_matrix = curve_fit(fnc, list(bcs[slc]), list(y[slc]), p0=p0,sigma=list(sigma)) + res=np.abs(coeff[2]/coeff[1]) + + if res<best_res: + best_res=res + res_err=res*np.hypot(np.sqrt(var_matrix[2][2])/coeff[2], np.sqrt(var_matrix[1][1])/coeff[1]) + wbest=w + scale=coeff[1]/np.sqrt(p**2+0.9406**2) + dscale=np.sqrt(var_matrix[1][1]/np.sqrt(p**2+0.9406**2)) + except : + print("fit failed") + if p==50 and eta_min==3.4: + plt.sca(axs[0]) + plt.errorbar(bcs, y, np.sqrt(y)+(y==0),marker='o', ls='', ) + plt.title(f'p={p} GeV, ${eta_min}<\\eta<{eta_max}$') + plt.xlabel("$E_{recon}$ [GeV]") + plt.ylabel("events") + #plt.ylim(0) + xx=np.linspace(40, 70, 50) + plt.plot(xx, fnc(xx, *coeff)) + resvals.append(best_res) + reserrs.append(res_err) + scalevals.append(scale) + scaleerrs.append(dscale) + pvals.append(p) + plt.sca(axs[1]) + plt.errorbar(pvals, resvals, reserrs, marker='o', ls='', label=f"${eta_min}<\\eta<{eta_max}$") + #plt.ylim(0) + plt.ylabel("$\\sigma[E]/\\mu[E]$") + plt.xlabel("$p_{n}$ [GeV]") + + plt.sca(axs[2]) + plt.errorbar(pvals, scalevals, scaleerrs, marker='o', ls='', label=f"${eta_min}<\\eta<{eta_max}$") + + + plt.ylabel("$\\mu[E]/E$") + + +axs[2].set_xlabel("$p_n$ [GeV]") +axs[2].axhline(1, ls='--', color='0.5', alpha=0.7) +axs[0].set_ylim(0) +axs[1].set_ylim(0, 0.35) +axs[2].set_ylim(0) +axs[1].legend() +axs[2].legend() plt.tight_layout() plt.savefig(outdir+"neutron_energy_recon.pdf")