def plot_temporal_distribution(self, fname=None): fname = self._fname(fname) figname = 'temps1.Simulation.plot_temporal_distribution.' + fname.replace( " ", "_") fig, axs = plt.subplots(2, 1, num=figname, clear=True, figsize=[6.4, 7.19]) axs[0].set_title( f'{fname.capitalize()} filter\nTemporal distribution of S1 candidates' ) ax = axs[0] ax.set_xlabel('Time relative to true S1 location [ns]') ax.set_ylabel('Inverse of neighbor temporal gap [ns$^{-1}$]') for k in ['all', 'dcr']: time = self.times[fname][k] time = np.sort(time) ddecdf = 1 / np.diff(time) x = time - self.s1loc y = np.concatenate([ddecdf, ddecdf[-1:]]) ax.plot(x, y, drawstyle='steps-post', **self.plotkw[k]) ax.axvspan(-self.deadradius, self.deadradius, color='#eee', zorder=-9, label='$\\pm$ dead radius') ax.axvspan(-self.matchdist, self.matchdist, color='#ccc', zorder=-8, label='$\\pm$ match dist.') ax.legend(loc='upper right') ax.set_xlim(3.5 * max(2 * self.matchdist, self.deadradius) * np.array([-1, 1])) ax.set_yscale('log') ax.minorticks_on() ax.grid(True, which='major', linestyle='--') ax.grid(True, which='minor', linestyle=':') ax = axs[1] ax.set_xlabel('Time relative to true S1 location [ns]') ax.set_ylabel('Histogram bin density [ns$^{-1}$]') times1 = self.hits1.reshape(-1) - self.s1loc time = self.times[fname]['all'] - self.s1loc time_match = time[np.abs(time) < self.matchdist] idx = np.argsort(np.abs(time)) time_close = time[idx][:self.nmc] # t = np.linspace(..., ..., 1000) # ax.plot(t, pS1.p_S1_gauss(t, self.VL, self.tauV, self.tauL, self.tres), label='S1 pdf') histkw = dict(bins='auto', density=True, histtype='step', zorder=10) ax.hist(times1, label=f'S1 photons ({len(times1)})', linestyle=':', **histkw) ax.hist( time_close, label= f'{self.nmc} closest candidates ($\\sigma_q$={qsigma.qsigma(time_close):.3g})', linestyle='--', **histkw) ax.hist( time_match, label= f'matching candidates ($\\sigma_q$={qsigma.qsigma(time_match):.3g})', **histkw) ax.axvspan(0, self.deadradius, color='#eee', zorder=-9, label='dead radius') ax.axvspan(0, self.matchdist, color='#ccc', zorder=-8, label='match dist.') textbox.textbox(ax, self.infotext(), loc='upper left', zorder=11) ax.legend(loc='upper right', fontsize='small') ax.set_yscale('log') linthreshx = 10**np.ceil(np.log10(15 * qsigma.qsigma(time_match))) ax.set_xscale('symlog', linthreshx=linthreshx) ax.minorticks_on() ax.xaxis.set_minor_locator( symloglocator.MinorSymLogLocator(linthreshx)) ax.grid(True, which='major', linestyle='--') ax.grid(True, which='minor', linestyle=':') fig.tight_layout() return fig
def simulation( DCR=250e-9, # (ns^-1) Dark count rate per PDM, 25 or 250 Hz VL=3, # fast/slow ratio, ER=0.3, NR=3 tauV=7, # (ns) fast component tau tauL=1600, # (ns) slow component tau T_target=4e6, # (ns) time window T_sim=100e3, # (ns) actually simulated time window npdm=8280, # number of PDMs nphotons=10, # (2-100) number of photons in the S1 signal tres=3, # (ns) temporal resolution (3-10) nmc=10, # number of simulated events deadradius=4000, # (ns) for selecting S1 candidates in filter output matchdist=2000, # (ns) for matching a S1 candidate to the true S1 generator=None # random generator ): info = f"""\ total DCR = {DCR * npdm * 1e3:.2g} $\\mu$s$^{{-1}}$ T (target) = {T_target * 1e-6:.1f} ms T (sim.) = {T_sim * 1e-6:.3f} ms fast/slow = {VL:.1f} nphotons = {nphotons} $\\tau$ = ({tauV:.1f}, {tauL:.0f}) ns temporal res. = {tres:.1f} ns dead radius = {deadradius:.0f} ns match dist. = {matchdist:.0f} ns nevents = {nmc}""" hits1 = pS1.gen_S1((nmc, nphotons), VL, tauV, tauL, tres, generator) hitdcr = dcr.gen_DCR(nmc, T_sim, DCR * npdm, generator) s1loc = T_sim / 2 hitall = np.concatenate([hits1 + s1loc, hitdcr], axis=-1) hitd = dict(all=hitall, dcr=hitdcr) plotkw = { 'all': dict(label='Single S1 events'), 'dcr': dict(label='No S1 events', linestyle='--') } filt = { k: filters.filters(hits, VL, tauV, tauL, tres, midpoints=1, pbar_batch=None) for k, hits in hitd.items() } figs = [] for fname in filt['all'].dtype.names: times = {} values = {} for k, fhits in filt.items(): time = fhits[fname]['time'] value = fhits[fname]['value'] times[k], values[k] = clustersort(time, value, deadradius) figname = 'temps1.simulation_' + fname.replace(" ", "_") fig, axs = plt.subplots(2, 1, num=figname, figsize=[6.4, 7.19], clear=True, sharex=True) figs.append(fig) axs[0].set_title( f'{fname.capitalize()} filter detection performance\n(with explicit threshold)' ) ax = axs[0] ax.set_ylabel('Mean number of S1 candidates per event') xy = { k: [v, (1 + np.arange(len(v)))[::-1] / nmc] for k, v in values.items() } interpkw = dict(kind='next', assume_sorted=True, copy=False, bounds_error=False) interp = { k: interpolate.interp1d(x, y, fill_value=(y[0], 0), **interpkw) for k, (x, y) in xy.items() } x = np.sort(np.concatenate([xy['all'][0], xy['dcr'][0]])) xy['all'][0] = x xy['all'][1] = interp['all']( x) + interp['dcr'](x) * (T_target / T_sim - 1) xy['dcr'][1] *= T_target / T_sim for k, (x, y) in xy.items(): x = np.concatenate([x, x[-1:]]) y = np.concatenate([y, [0]]) ax.plot(x, y, drawstyle='steps-pre', **plotkw[k]) if fname == 'sample mode': ax.set_xscale('log') ax.set_yscale('log') ax.minorticks_on() ax.grid(True, which='major', linestyle='--') ax.grid(True, which='minor', linestyle=':') ax.legend(loc='upper right') ax = axs[1] ax.set_ylabel('True S1 detection probability') ax.set_xlabel('Threshold on filter output') time, value = times['all'], values['all'] close = np.abs(time - s1loc) < matchdist s1value = value[close] x = np.concatenate([s1value, s1value[-1:]]) y = np.arange(len(x))[::-1] / nmc ax.plot(x, y, drawstyle='steps-pre', **plotkw['all']) textbox.textbox(ax, info) ax.minorticks_on() ax.grid(True, which='major', linestyle='--') ax.grid(True, which='minor', linestyle=':') ax.set_ylim(0, max(1, np.max(y))) figname = 'temps1.simulation_' + fname.replace(" ", "_") + '_combined' fig, ax = plt.subplots(num=figname, clear=True) figs.append(fig) ax.set_title(f'{fname.capitalize()} filter detection performance') ax.set_xlabel('S1 candidates per event') ax.set_ylabel('S1 loss probability') time, value = times['all'], values['all'] close = np.abs(time - s1loc) < matchdist xs1 = value[close] ys1 = 1 - (1 + np.arange(len(xs1)))[::-1] / nmc fs1 = interpolate.interp1d(xs1, ys1, fill_value=(1 - ys1[0], 1), **interpkw) x, y = xy['all'] sel = (xs1[0] <= x) & (x <= xs1[-1]) x = x[sel] y = y[sel] s1cand = y s1prob = fs1(x) ax.plot(s1cand, s1prob, **plotkw['all']) textbox.textbox(ax, info) ax.minorticks_on() ax.set_xscale('log') ax.set_yscale('log') ax.grid(True, which='major', linestyle='--') ax.grid(True, which='minor', linestyle=':') l, r = ax.get_xlim() ax.set_xlim(max(0.1, l), r) b, _ = ax.get_ylim() ax.set_ylim(b, max(1, np.max(s1prob))) autolinscale(ax) figname = 'temps1.simulation_' + fname.replace(" ", "_") + '_time' fig, axs = plt.subplots(2, 1, num=figname, clear=True, figsize=[6.4, 7.19]) figs.append(fig) axs[0].set_title( f'{fname.capitalize()} filter\nTemporal distribution of S1 candidates' ) ax = axs[0] ax.set_xlabel('Time relative to true S1 location [ns]') ax.set_ylabel('Inverse of neighbor temporal gap [ns$^{-1}$]') for k, time in times.items(): time = np.sort(time) ddecdf = 1 / np.diff(time) x = time - s1loc y = np.concatenate([ddecdf, ddecdf[-1:]]) ax.plot(x, y, drawstyle='steps-post', **plotkw[k]) ax.axvspan(-deadradius, deadradius, color='#eee', zorder=-9, label='$\\pm$ dead radius') ax.axvspan(-matchdist, matchdist, color='#ccc', zorder=-8, label='$\\pm$ match dist.') ax.legend(loc='upper right') # ax.set_xscale('symlog', linthreshx=deadradius, linscalex=2) ax.set_xlim(3.5 * max(2 * matchdist, deadradius) * np.array([-1, 1])) ax.set_yscale('log') ax.minorticks_on() ax.grid(True, which='major', linestyle='--') ax.grid(True, which='minor', linestyle=':') ax = axs[1] ax.set_xlabel('Time relative to true S1 location [ns]') ax.set_ylabel('Histogram bin density [ns$^{-1}$]') times1 = hits1.reshape(-1) time = times['all'] - s1loc time_match = time[np.abs(time) < matchdist] idx = np.argsort(np.abs(time)) time_close = time[idx][:nmc] # t = np.linspace(left, right, 1000) # ax.plot(t, pS1.p_S1_gauss(t, VL, tauV, tauL, tres), label='S1 pdf') histkw = dict(bins='auto', density=True, histtype='step', zorder=10) ax.hist(times1, label=f'S1 photons ({len(times1)})', linestyle=':', **histkw) ax.hist( time_close, label= f'{nmc} closest candidates ($\\sigma_q$={qsigma.qsigma(time_close):.3g})', linestyle='--', **histkw) ax.hist( time_match, label= f'matching candidates ($\\sigma_q$={qsigma.qsigma(time_match):.3g})', **histkw) ax.axvspan(0, deadradius, color='#eee', zorder=-9, label='dead radius') ax.axvspan(0, matchdist, color='#ccc', zorder=-8, label='match dist.') textbox.textbox(ax, info, loc='upper left', zorder=11) ax.legend(loc='upper right', fontsize='small') ax.set_yscale('log') linthreshx = 10**np.ceil(np.log10(15 * qsigma.qsigma(time_match))) ax.set_xscale('symlog', linthreshx=linthreshx) ax.minorticks_on() ax.xaxis.set_minor_locator( symloglocator.MinorSymLogLocator(linthreshx)) ax.grid(True, which='major', linestyle='--') ax.grid(True, which='minor', linestyle=':') for fig in figs: fig.tight_layout() return figs