codex/scanning-tunneling-height-electronic-contrast.py

scanning-tunneling-height-electronic-contrast.py
"""Compare two exactly degenerate STM toy surfaces.

Python 3.14, numpy 2.3.5, matplotlib 3.10.7. Run from _media.
All distances below are in nm; all profiles and scales are chosen, not measured.
"""

from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    x = np.linspace(0, 2, 801)
    kappa, a, s0 = 10.0, 0.020, 0.50
    q = np.cos(2 * np.pi * x)
    h_a, h_b = a * q, np.zeros_like(x)
    rho_a, rho_b = np.ones_like(x), np.exp(2 * kappa * a * q)
    z_a = h_a + np.log(rho_a) / (2 * kappa) + s0
    z_b = h_b + np.log(rho_b) / (2 * kappa) + s0
    i0 = np.exp(-2 * kappa * s0)
    current_a = rho_a * np.exp(-2 * kappa * (s0 - h_a)) / i0
    current_b = rho_b * np.exp(-2 * kappa * (s0 - h_b)) / i0
    np.testing.assert_allclose(z_a, z_b, atol=1e-14)
    np.testing.assert_allclose(current_a, current_b, atol=1e-14)
    assert np.all(rho_b > 0) and np.all(z_b - h_b > 0)
    plt.rcParams.update({"font.size": 11, "font.family": "DejaVu Sans"})
    fig, axs = plt.subplots(2, 2, figsize=(10, 7), dpi=120, facecolor="white")
    blue, orange = "#23629a", "#bf5719"

    def pair(ax, ya, yb):
        ax.plot(x, ya, color=blue, lw=2.8, label="A: corrugated, ρ = 1")
        ax.plot(x, yb, color=orange, lw=2.0, ls="--", label="B: flat, varying ρ")

    pair(axs[0, 0], h_a, h_b)
    axs[0, 0].set(title="Chosen geometric heights", ylabel="h (nm)", ylim=(-0.027, 0.033))
    axs[0, 0].legend(loc="upper right", fontsize=9)
    pair(axs[0, 1], rho_a, rho_b)
    axs[0, 1].set(title="Chosen electronic factors", ylabel="ρ (dimensionless)", ylim=(0.58, 1.62))
    pair(axs[1, 0], z_a, z_b)
    axs[1, 0].set(title="Same recorded height at constant current", ylabel="z (nm)", ylim=(0.472, 0.535))
    axs[1, 0].text(0.5, 0.92, "Both: z = 0.50 + 0.020 cos(2πx)",
                   transform=axs[1, 0].transAxes, ha="center", fontsize=9)
    pair(axs[1, 1], current_a, current_b)
    axs[1, 1].axhline(1, color="#555555", ls=":", lw=1.4)
    axs[1, 1].text(0.5, 0.92, "At fixed z = 0.50 nm: both exp[0.4 cos(2πx)]",
                   transform=axs[1, 1].transAxes, ha="center", fontsize=9)
    axs[1, 1].text(0.5, 0.025, "Dotted: feedback holds I / I₀ = 1",
                   transform=axs[1, 1].transAxes, ha="center", fontsize=9)
    axs[1, 1].set(title="Same current contrast at fixed height", ylabel="I / I₀", ylim=(0.55, 1.65))
    for ax in axs.flat:
        ax.set(xlabel="Lateral position x (nm)", xlim=(0, 2))
        ax.grid(alpha=0.2)
        ax.spines[["top", "right"]].set_visible(False)
    fig.suptitle("An STM height map does not uniquely determine geometric height", fontsize=15, y=0.98)
    fig.text(0.5, 0.027, "Chosen toy model: I = C ρ exp[−2κ(z−h)],  κ = 10 nm⁻¹,  I₀ / C = exp(−10)\n"
             "ρB = exp[0.4 cos(2πx)] > 0; constant barrier, low fixed bias; no measured data",
             ha="center", va="center", fontsize=10)
    fig.subplots_adjust(left=0.085, right=0.98, bottom=0.14, top=0.88, hspace=0.52, wspace=0.28)
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()