codexscanning-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()