codex/debye-normal-metal-intercept-test.py

debye-normal-metal-intercept-test.py
"""Original normal-metal gamma + beta T² example; no experimental data.

Python 3.14, NumPy 2.3.5, Matplotlib 3.10.7. Run from _media.
"""
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    plt.rcParams.update({"font.size": 11, "figure.facecolor": "white"})
    gamma, beta, sigma = 7e-4, 4e-4, 2e-5
    temperature = np.array([1., 2., 3.])
    x = temperature ** 2
    y = gamma + beta * x
    design = np.column_stack([np.ones(3), x])
    fit = np.linalg.lstsq(design, y, rcond=None)[0]
    covariance = sigma ** 2 * np.linalg.inv(design.T @ design)
    theta = (12 * np.pi ** 4 * 8.31446261815324 / (5 * beta)) ** (1 / 3)
    assert np.allclose(fit, [gamma, beta], rtol=1e-12)
    assert np.isclose(theta, 169.3798102764744)
    assert np.allclose(np.sqrt(np.diag(covariance)), [2e-5, 3.499271061118826e-6])
    fig, (ax, detail) = plt.subplots(1, 2, figsize=(10.5, 4.8),
                                    gridspec_kw={"width_ratios": [1.65, 1]})
    fig.suptitle("Test the lattice T³ term without losing the electrons", fontsize=15)
    xx = np.linspace(1, 9, 300)
    extrap = np.linspace(0, 1, 50)
    ax.plot(xx, gamma + beta * xx, color="#0369a1", lw=2, label="Total: γ + βT²")
    ax.plot(extrap, gamma + beta * extrap, color="#0369a1", ls="--", lw=1.5)
    ax.plot(xx, beta * xx, color="#b45309", lw=2, label="Lattice only: βT²")
    ax.plot(extrap, beta * extrap, color="#b45309", ls="--", lw=1.5)
    ax.axhline(gamma, color="#7c3aed", ls=":", lw=2, label="Electrons only: γ")
    ax.errorbar(x, y, yerr=sigma, fmt="o", color="#0f172a", capsize=4,
                label="Constructed values, assigned 1σ")
    ax.fill_between(xx, beta * xx, gamma + beta * xx, color="#ede9fe", alpha=.7)
    ax.annotate("Electronic intercept\nγ = 0.000700 J mol⁻¹ K⁻²", xy=(0, gamma),
                xytext=(.7, .0027), fontsize=10,
                arrowprops={"arrowstyle": "->", "color": "#7c3aed"})
    ax.axvspan(0, 1, color="#e2e8f0", alpha=.4)
    ax.set(xlabel="Squared temperature T² (K²)", ylabel="Molar Cₚ,ₘ/T (J mol⁻¹ K⁻²)",
           xlim=(0, 9.5), ylim=(0, .0056))
    ax.ticklabel_format(axis="y", style="plain", useOffset=False)
    ax.legend(loc="upper left", fontsize=9, frameon=False)
    ax.grid(alpha=.18)
    detail.axis("off")
    detail.text(0, .98, "Stipulated normal metal", fontsize=13, weight="bold", va="top")
    detail.text(0, .88, "Fit domain: 1 ≤ T ≤ 3 K\nT ≪ ΘD; no superconducting transition\nNo magnetic or Schottky term", linespacing=1.65, fontsize=10, va="top")
    detail.text(0, .59, "Slope β = 0.000400 J mol⁻¹ K⁻⁴\nΘD = 169.38 K (monatomic model)\nElectrons = lattice at T = 1.323 K", linespacing=1.65, fontsize=10, va="top")
    detail.text(0, .34, "Dashed segment: extrapolation to T = 0\nNo measurement at absolute zero", linespacing=1.65, fontsize=10, va="top")
    detail.text(0, .16, "Error bars: u(Cₚ,ₘ/T) = 0.000020\nJ mol⁻¹ K⁻²; temperature error neglected", linespacing=1.65, fontsize=10, va="top")
    fig.text(.5, .025, "Original constructed example, not a fit to the gold experiment  •  "
             "A straight line tests the sum of two distinct contributions", ha="center", fontsize=10)
    fig.tight_layout(rect=(0, .065, 1, .94))
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=150, facecolor="white")
    plt.close(fig)
    print(f"fit={fit.tolist()}; standard_uncertainties={np.sqrt(np.diag(covariance)).tolist()}; theta={theta:.10g} K")


if __name__ == "__main__":
    main()