codex/josephson-escape-switching-readout.py

josephson-escape-switching-readout.py
"""Draw an original escape/readout model. Python 3.14; NumPy 2.3.5; Matplotlib 3.10.7.

Run from _media; writes this script's basename.png to the current directory.
All plotted curves are stipulated constant-hazard calculations, not measurements.
"""
from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch


def main():
    plt.rcParams.update({'font.size': 12, 'axes.spines.top': False,
                         'axes.spines.right': False, 'figure.facecolor': 'white'})
    fig = plt.figure(figsize=(10.5, 6.5), dpi=100, facecolor='white')
    flow = fig.add_axes([.03, .61, .94, .25]); flow.axis('off'); flow.set_xlim(-.025, 1.025)
    labels = [r'Reset trapped phase' + '\n' + r'Ramp current: $dI/dt=r$',
              'Escape from phase well\nMay retrap: no event yet',
              'Sustained phase advance\nVoltage event → record $I_{sw}$']
    for x, label in zip([.01, .35, .69], labels):
        box = FancyBboxPatch((x, .30), .29, .60, boxstyle='round,pad=0.012',
                             ec='#3b5d79', fc='#f1f6fa', lw=1.5)
        flow.add_patch(box)
        flow.text(x + .145, .60, label, ha='center', va='center', fontsize=11,
                  linespacing=1.6)
    for start, end in [(.302, .345), (.642, .685)]:
        flow.annotate('', (end, .60), (start, .60),
                      arrowprops={'arrowstyle': '->', 'lw': 1.8, 'color': '#3b5d79'})
    flow.text(.5, .06, 'Repeat preparation → distribution of switching currents → escape rate',
              ha='center', va='center', color='#3b5d79', fontsize=12)
    left = fig.add_axes([.09, .16, .36, .34])
    right = fig.add_axes([.60, .16, .36, .34])
    t_ms = np.linspace(0, 4, 501)
    left.plot(t_ms, np.exp(-t_ms), color='#1565a8', lw=2.5)
    median = np.log(2)
    left.plot([0, median, median], [.5, .5, 0], '--', color='#a3631f', lw=1.4)
    left.text(1.2, .63, 'Half remain at\n0.693147 ms', fontsize=11, color='#94561a')
    left.set(xlim=(0, 4), ylim=(0, 1.04), xlabel='Elapsed time (ms)',
             ylabel='Trapped fraction S(t)', title='Survival at fixed escape rate')
    di_na = np.linspace(0, 4, 501)
    right.plot(di_na, np.exp(-di_na), color='#267f73', lw=2.5)
    right.fill_between(di_na[di_na <= median], np.exp(-di_na[di_na <= median]),
                       color='#267f73', alpha=.20)
    right.axvline(1, color='#a3631f', ls='--', lw=1.4)
    right.text(1.3, .68, 'Mean increment\n1 nA', color='#94561a', fontsize=11)
    right.text(.12, .13, 'Area ≈ 1/2', fontsize=10, color='#267f73')
    right.set(xlim=(0, 4), ylim=(0, 1.04), xlabel=r'Current increment $I-I_0$ (nA)',
              ylabel=r'Density p(I) (per nA)', title='Current distribution under a ramp')
    for ax in [left, right]:
        ax.grid(alpha=.18)
    fig.suptitle('Escape becomes a voltage event; statistics recover a rate', y=.96, fontsize=16)
    fig.text(.5, .555, 'Chosen model: Γ = 1000 s⁻¹, r = 1 μA/s • perfect detection • no retrapping',
             ha='center', fontsize=11, color='#555555')
    fig.text(.5, .045, r'$p(I)=\Gamma(I)S(I)/r$     •     synthetic curves, not historical data',
             ha='center', fontsize=12, color='#444444')
    fig.savefig(Path.cwd() / (Path(__file__).stem + '.png'), facecolor='white', transparent=False)
    plt.close(fig)


if __name__ == '__main__':
    main()