"""Illustrative sequential photon arrivals convolved with a Gaussian response. Tested with Python 3.14, NumPy 2.3.5 and Matplotlib 3.10.7. """ from pathlib import Path import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt def arrival_density(t, transfer_time, lower_lifetime=100.0): t = np.asarray(t) a, b = 1.0 / transfer_time, 1.0 / lower_lifetime u = np.maximum(t, 0.0) p = a * b / (a - b) * (np.exp(-b * u) - np.exp(-a * u)) return np.where(t >= 0, p, 0.0) def response(t, sigma=25.0): return np.exp(-0.5 * (np.asarray(t) / sigma)**2) / (sigma * np.sqrt(2 * np.pi)) def traces(): dt = 0.2 t = np.arange(-200, 1400 + dt / 2, dt) lag = np.arange(-125, 125 + dt / 2, dt) g = response(lag) g /= np.sum(g) * dt return t, [(tau, arrival_density(t, tau), np.convolve(arrival_density(t, tau), g, mode='same') * dt) for tau in (2.0, 10.0)] def main(): t, curves = traces() fig, axes = plt.subplots(1, 2, figsize=(9, 4.1), dpi=100, facecolor='white') colors = ['#225eaa', '#c65d24'] for (tau, ideal, measured), color in zip(curves, colors): for ax, y in zip(axes, [ideal, measured]): ax.plot(t, y, color=color, lw=2, label=f'Transfer time {tau:g} ps') for ax, title, limits in zip(axes, ['Intrinsic arrival density', 'After Gaussian instrument response'], [(-10, 170), (-70, 230)]): ax.set_facecolor('white') ax.set(title=title, xlabel='Time after excitation (ps)', xlim=limits, ylim=(0, 0.0105)) ax.grid(alpha=0.15) ax.legend(fontsize=9) axes[0].set_ylabel('Photon-arrival density (per ps)') fig.suptitle('Instrument broadening can obscure a fast population transfer', fontsize=13) fig.text(0.5, 0.015, 'Original models: lower-state lifetime 100 ps; response standard deviation 25 ps. No experimental data.', ha='center', fontsize=9) fig.tight_layout(rect=(0, 0.04, 1, 0.95)) fig.savefig(Path('sequential-kinetics-response-broadening.png'), facecolor='white') plt.close(fig) if __name__ == '__main__': main()