codex/past-exam-of-the-quantum-condensed-matter-course-of-the-university-of-cambridge/2021-q3-alternating-springs.py

past-exam-of-the-quantum-condensed-matter-course-of-the-university-of-cambridge/2021-q3-alternating-springs.py
"""Original equal-mass alternating-spring normal modes; write PNG to cwd.

Tested with Python 3.14, NumPy and Matplotlib; see root pyproject.toml.
The displacement arrows are mode patterns, not time-evolution trajectories.
"""

from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np


def main():
    weak = 0.06
    q_scaled = np.linspace(-1, 1, 1501)
    qa = np.pi * q_scaled / 2
    split = np.sqrt((1 - weak)**2 + 4 * weak * np.cos(qa)**2)
    acoustic = np.sqrt(np.maximum(1 + weak - split, 0))
    optical = np.sqrt(1 + weak + split)
    fig, axes = plt.subplots(1, 2, figsize=(9.6, 4.2),
                             gridspec_kw={"width_ratios": [1.05, 1]}, facecolor="white")
    ax = axes[0]
    ax.plot(q_scaled, acoustic, lw=2, color="#1768ab", label="Acoustic")
    ax.plot(q_scaled, optical, lw=2, color="#bd6426", label="Optical")
    ax.axhspan(np.sqrt(2 * weak), np.sqrt(2), color="#e7ebef")
    for edge in (-1, 1):
        ax.axvline(edge, color="#687580", ls=":", lw=1)
    ax.set(xlim=(-1.08, 1.08), ylim=(0, 1.65),
           xlabel=r"$q/[π/(2a)]$", ylabel=r"$\omega/\sqrt{K/m}$")
    ax.set_xticks([-1, 0, 1])
    ax.set_title(r"Two-atom cell: $\kappa/K=0.06$", fontsize=11)
    ax.text(0, .85, "Frequency gap", ha="center", color="#586572")
    ax.legend(loc="center right", frameon=False, fontsize=10)

    ax = axes[1]
    patterns = [(1, 1, 1, 1), (1, -1, 1, -1),
                (1, 1, -1, -1), (1, -1, -1, 1)]
    labels = [r"$q=0$: acoustic", r"$q=0$: optical",
              r"$q=\pi/(2a)$: acoustic", r"$q=\pi/(2a)$: optical"]
    for row, (pattern, label) in enumerate(zip(patterns, labels)):
        y = 3.4 - row
        ax.text(-.25, y + .29, label, fontsize=10)
        for bond in range(3):
            strong = bond % 2 == 0
            ax.plot([bond, bond + 1], [y, y], color="#8b969e",
                    lw=3 if strong else 1.4, ls="-" if strong else "--", zorder=0)
        ax.scatter(range(4), [y]*4, s=72, facecolor="white", edgecolor="#263d4b", zorder=2)
        for site, direction in enumerate(pattern):
            ax.annotate("", xy=(site + .34*direction, y + .15), xytext=(site, y + .15),
                        arrowprops={"arrowstyle": "->", "lw": 1.6,
                                    "color": "#1768ab" if row % 2 == 0 else "#bd6426"})
    ax.plot([.1, .65], [-.42, -.42], lw=3, color="#8b969e")
    ax.text(.78, -.42, r"strong $K$", va="center", fontsize=9)
    ax.plot([1.85, 2.4], [-.42, -.42], lw=1.4, ls="--", color="#8b969e")
    ax.text(2.52, -.42, r"weak $\kappa$", va="center", fontsize=9)
    ax.set(xlim=(-.35, 3.8), ylim=(-.65, 4.05))
    ax.set_title("Relative displacements", fontsize=11)
    ax.axis("off")
    axes[0].spines[["top", "right"]].set_visible(False)
    fig.tight_layout(w_pad=2)
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=125, facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()