Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-01 09:34:06

0001 """Reproduce the single uncalibrated CALOROC energy-response plot."""
0002 
0003 import argparse
0004 
0005 import matplotlib.pyplot as plt
0006 import numpy as np
0007 from scipy.optimize import curve_fit
0008 
0009 from script.common import (
0010     LOAD_CHUNK_SIZE,
0011     SliceResult,
0012     applyPlotStyle,
0013     boundsCrystalBallPositive,
0014     buildSliceHistogramFromChunks,
0015     crystal_ball,
0016     curveFitReducer,
0017     loadData,
0018     maskPositiveAboveThreshold,
0019     nERecoBins,
0020     nETruthBins,
0021     p0CrystalBall,
0022     plotThetaDistribution,
0023     reduceSlices,
0024 )
0025 
0026 
0027 applyPlotStyle()
0028 
0029 
0030 def linear(x, a, b):
0031     return a * x + b
0032 
0033 
0034 def main(chunk_iter, output, title, e_truth_min, e_truth_max, e_reco_min,
0035          e_reco_max, txt=None, ytitle=''):
0036     """Accumulate response histograms, fit each truth-energy slice, and plot."""
0037     e_truth_bins = np.linspace(e_truth_min, e_truth_max, nETruthBins)
0038     e_reco_bins = np.linspace(e_reco_min, e_reco_max, nERecoBins)
0039     theta_bins = np.linspace(0, 180, 180)
0040 
0041     hist = np.zeros((len(e_truth_bins) - 1, len(e_reco_bins) - 1))
0042     theta_counts = np.zeros(len(theta_bins) - 1)
0043     for chunk in chunk_iter:
0044         h, _, _ = np.histogram2d(
0045             chunk['ETruth'], chunk['EReco'], bins=(e_truth_bins, e_reco_bins)
0046         )
0047         hist += h
0048         tc, _ = np.histogram(chunk['theta'], bins=theta_bins)
0049         theta_counts += tc
0050 
0051     err = hist / np.sqrt(hist)
0052     xc = 0.5 * (e_truth_bins[1:] + e_truth_bins[:-1])
0053     yc = 0.5 * (e_reco_bins[1:] + e_reco_bins[:-1])
0054     mean, _, std, _ = reduceSlices(
0055         xc, yc, hist, err,
0056         reducer=curveFitReducer(
0057             crystal_ball, p0CrystalBall, boundsCrystalBallPositive
0058         ),
0059         sliceMask=maskPositiveAboveThreshold(0.05, 0.4),
0060     )
0061 
0062     x, y = np.meshgrid(e_truth_bins, e_reco_bins)
0063     fig, (ax, ax2) = plt.subplots(ncols=2, figsize=(14, 7))
0064     pc = ax.pcolormesh(x, y, hist.T, cmap='magma_r')
0065     ax.errorbar(xc, mean, yerr=np.abs(std), marker='o')
0066     try:
0067         finite = np.isfinite(mean) & np.isfinite(std)
0068         popt, _ = curve_fit(
0069             linear, xc[finite], mean[finite], sigma=np.abs(std[finite]),
0070             absolute_sigma=True, p0=[1, 0]
0071         )
0072         fine_bins = np.linspace(e_truth_bins[0], e_truth_bins[-1], 100)
0073         ax.plot(
0074             fine_bins, linear(fine_bins, *popt),
0075             label='y = %.3e x + %.3e' % (popt[0], popt[1])
0076         )
0077     except Exception:
0078         pass
0079     ax.legend(frameon=False)
0080 
0081     if txt is not None:
0082         np.savetxt(txt, np.column_stack((xc, mean, np.abs(std))), fmt='%.6f')
0083     ax.set_ylim(e_reco_min, e_reco_max)
0084     try:
0085         fig.colorbar(pc, ax=ax)
0086     except Exception:
0087         pass
0088     ax.set_xlabel(r'$E_{truth}$ (GeV)')
0089     ax.set_ylabel(ytitle)
0090     plotThetaDistribution(ax2, theta_counts, theta_bins)
0091     fig.suptitle(title)
0092     plt.tight_layout(rect=[0, 0, 1, 0.95])
0093     plt.savefig(output)
0094 
0095 
0096 if __name__ == '__main__':
0097     parser = argparse.ArgumentParser()
0098     parser.add_argument('output')
0099     parser.add_argument('data')
0100     parser.add_argument('pdg', type=int)
0101     parser.add_argument('title')
0102     parser.add_argument('--eTruthMin', type=float, required=True)
0103     parser.add_argument('--eTruthMax', type=float, required=True)
0104     parser.add_argument('--eRecoMin', type=float, required=True)
0105     parser.add_argument('--eRecoMax', type=float, required=True)
0106     parser.add_argument('--ytitle')
0107     parser.add_argument('--txt', default=None)
0108     args = parser.parse_args()
0109     columns = [
0110         'mcId', 'PDG', 'theta', 'EReco', 'ETruth', 'PhiReco', 'EtaReco',
0111         'PhiTruth', 'EtaTruth', 'status', 'nevent'
0112     ]
0113     main(
0114         loadData(args.data, args.pdg, columns), args.output, args.title,
0115         args.eTruthMin, args.eTruthMax, args.eRecoMin, args.eRecoMax,
0116         args.txt, args.ytitle
0117     )