codex/biot-savart-finite-wire-geometry.py

biot-savart-finite-wire-geometry.py
"""Original finite-wire diagram. Tested with Python 3.14, matplotlib 3.10, numpy 2.3."""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
import numpy as np


def main():
    plt.rcParams.update({'font.size': 11, 'axes.titlesize': 13})
    blue, red, gray = '#176b9b', '#b33b32', '#626a73'
    fig, (ax, plot) = plt.subplots(1, 2, figsize=(10, 4.8), dpi=130,
                                  gridspec_kw={'width_ratios': [1, 1.1]}, facecolor='white')
    fig.subplots_adjust(left=.055, right=.97, bottom=.16, top=.83, wspace=.3)
    fig.suptitle('Finite straight wire: orientation and the long-wire limit', fontsize=15, y=.96)
    ax.set_title('Geometry at the midpoint', pad=10)
    ax.set_aspect('equal')
    ax.set_xlim(-.045, .12)
    ax.set_ylim(-.155, .155)
    ax.axis('off')
    a, half_length = .05, .12
    ax.plot([0, 0], [-half_length, half_length], color=blue, lw=5)
    ax.annotate('', xy=(0, .075), xytext=(0, .025),
                arrowprops={'arrowstyle': '-|>', 'lw': 2.5, 'color': red})
    ax.text(-.034, .05, r'$I=3\,\mathrm{A}$', color=red, va='center')
    ax.text(-.004, half_length+.01, r'$s_2=+0.12\,\mathrm{m}$', ha='center')
    ax.text(-.004, -half_length-.018, r'$s_1=-0.12\,\mathrm{m}$', ha='center')
    for s in (-half_length, half_length):
        ax.plot([0, a], [s, 0], '--', color=gray, lw=1.2)
    ax.plot([0, a], [0, 0], ':', color=gray)
    ax.annotate('', xy=(a, -.015), xytext=(0, -.015),
                arrowprops={'arrowstyle': '<->', 'color': gray})
    ax.text(a/2, -.032, r'$a=0.05\,\mathrm{m}$', ha='center')
    ax.annotate('', xy=(a, 0), xytext=(0, .058),
                arrowprops={'arrowstyle': '-|>', 'lw': 1.5, 'color': blue})
    ax.text(.033, .048, r'$\mathbf{R}$', color=blue)
    ax.add_patch(Circle((a, 0), .0045, edgecolor=red, facecolor='white', lw=1.7, zorder=5))
    d = .0024
    ax.plot([a-d, a+d], [-d, d], color=red, lw=1.6, zorder=6)
    ax.plot([a-d, a+d], [d, -d], color=red, lw=1.6, zorder=6)
    ax.text(a+.012, .005, 'P', va='center', fontsize=12)
    ax.text(a+.012, -.015, 'B into page', color=red, va='center')
    ax.annotate('', xy=(.09, -.105), xytext=(.06, -.105),
                arrowprops={'arrowstyle': '->', 'color': gray})
    ax.annotate('', xy=(.06, -.075), xytext=(.06, -.105),
                arrowprops={'arrowstyle': '->', 'color': gray})
    ax.text(.094, -.106, 'x', color=gray)
    ax.text(.058, -.069, 'y', color=gray)
    ratio = np.linspace(0, 8, 500)
    plot.plot(ratio, ratio/np.sqrt(1+ratio**2), color=blue, lw=2.6)
    plot.axhline(1, color=gray, ls='--', lw=1.2)
    plot.text(6.1, 1.013, 'infinite wire', color=gray, fontsize=10)
    plot.scatter([2.4], [12/13], color=red, zorder=5)
    plot.annotate(r'$L/a=2.4$'+'\n'+r'$B/B_\infty=12/13$', (2.4, 12/13),
                  xytext=(3.45, .64), arrowprops={'arrowstyle': '->', 'color': red}, color=red)
    plot.set(xlim=(0, 8), ylim=(0, 1.08), xlabel=r'Half-length / distance, $L/a$',
             ylabel=r'Midpoint field ratio, $B/B_\infty$',
             title=r'$B/B_\infty=L/\sqrt{a^2+L^2}$')
    plot.grid(alpha=.2)
    plot.spines[['top', 'right']].set_visible(False)
    fig.text(.5, .025, 'Segment contribution only; add the return path for a complete circuit.',
             ha='center', fontsize=10, color=gray)
    fig.savefig(Path.cwd() / (Path(__file__).stem+'.png'), facecolor='white', transparent=False)
    plt.close(fig)


if __name__ == '__main__':
    main()