Inspiration

Every computational materials scientist has the same story. You run your first phonon calculation, you plot the dispersion, and there it is: a branch dipping below zero near $\Gamma$. Negative frequency means imaginary $\omega$, which means $\omega^2 < 0$, which means the restoring force is negative, which means your material is unstable.

Most of the times materials are perfectly stable, but you have not taken into account the acoustic sum rule, or used a supercell too small to contain the force constants, or converged your forces too loosely. The physics is fine. The calculation is broken, and nothing in the output tells you what is the cause. At first sight, my material was dynamically unstable. I was wrong, and I had no way of knowing what was the cause.

There is a second thing that bothered me, and it is pedagogical. Solid-state physics teaches electronic band structure in one chapter and phonon dispersion in another, and almost nobody says the obvious thing out loud: they are the same problem.

$$H(\mathbf{k})\,\psi_{n\mathbf{k}} = \varepsilon_{n\mathbf{k}}\,\psi_{n\mathbf{k}} \qquad\qquad D(\mathbf{q})\,\mathbf{e}{\nu\mathbf{q}} = \omega{\nu\mathbf{q}}^{2}\,\mathbf{e}_{\nu\mathbf{q}}$$

One lattice. One Brillouin zone. One eigenvalue problem, solved twice with two different matrices. Once you see it, band structure stops being two disconnected pieces and becomes a single idea.

Phonon & Fermion visualization is the tool I wish I'd had, built around a tutor that is structurally incapable of lying to me.

What it does

Phonon & Fermion puts electrons and phonons side by side, on the same $\Gamma!-!M!-!K!-!\Gamma$ path, for graphene.

The left panel shows the electronic bands from a nearest-neighbour tight-binding Hamiltonian. The right panel shows the phonon bands from the dynamical matrix built out of real force constants. The axes are aligned. You can see, physically, that they are the same operation. Additionally, an AI based on GPT-5.6 assisting.

Then you get sliders, and each one is a lesson:

  • $\delta$ — the sublattice mass term. Push it above zero and watch the Dirac cone at $K$ split. It does not move. It does not tilt. It opens a gap of exactly $2\delta$, because the two carbon sublattices are no longer equivalent and the off-diagonal term $f(\mathbf{K})$ can no longer vanish by symmetry. This is graphene becoming hBN, live.
  • ASR violation. Inject a controlled residual into the acoustic sum rule, $\sum_{\kappa'}\Phi_{\alpha\beta}(\kappa,\kappa') \neq 0$, and watch a spurious imaginary branch appear below zero.
  • Rotational invariance. Break it, and the flexural ZA branch quietly changes from $\omega \sim |q|^2$ to $\omega \sim |q|$. The sum rule still passes. The spectrum still looks plausible. Nothing warns you — except us.

Underneath all of it sits the thing that makes this project different: a deterministic physics oracle.

Before the AI tutor is allowed to say anything, core/invariants.py runs a battery of hand-written numerical checks — space group via spglib, vacuum thickness, ASR residual, acoustic modes at $\Gamma$, imaginary-mode triage, ZA exponent, supercell convergence. Each check returns a verdict that licenses or revokes specific physics claims. The tutor's prompt is assembled from the licensed set.

The consequence is the demo I care most about. Drag the ASR slider to $0.005$. A branch dives to $-0.31$ THz, clearly visible, clearly imaginary. Ask the tutor whether graphene is unstable, and it answers:

The force constants failed the sum-rule check, so the sign of the low-frequency modes carries no physical information. Stability is not a question this calculation can answer yet — in either direction.

Note what it does not do. It does not say the material is unstable. It also does not say it is stable. It says the question is not yet askable, and it names the number standing in the way. A failed check does not grant the negation. That single asymmetry is the whole architecture.

How we built it

The project was built with Codex and GPT-5.6.

Codex acted as developer. Codex read a binding AGENTS.md containing hard prohibitions written before a single line of application code existed:

  • Never enable force-constant symmetrization by default. The ASR residual must be measurable before it is enforced — that measurement is the product.
  • Never sanitize imaginary frequencies. phonopy reports them as negative; the sign is data, not a bug.
  • Never add a silent fallback. A failed calculation propagates as a failure. A tutor that teaches from a fallback is teaching a lie.
  • core/invariants.py is hand-written and authoritative. No agent may touch it.

At run time, the same split lives inside the product: an architect turns the learner's question into a concrete calculation plan, a Codex developer agent writes and repairs the simulation code, the physics runs, and the oracle gates what the tutor may assert.

The stack:

layer technology
Physics core Python 3.11, NumPy, phonopy, spglib, ASE
Oracle hand-written invariants, pytest with deliberately broken fixtures
API FastAPI, Pydantic, signed frequencies preserved through JSON
Frontend Next.js 15, TypeScript, Tailwind, Plotly
Agents Codex CLI, GPT-5.6

The force constants come from a Born–von Kármán model constructed so that the sum rules are satisfied by construction — and can be broken on demand, by a known amount. That is what makes the failures teachable instead of accidental.

Challenges we ran into

Designing an AI to refuse. This was by far the hardest part, and it is not a prompting problem. You cannot instruct a model into epistemic honesty; you have to make dishonesty structurally impossible. The Verdict schema carries both licenses and revokes, and revocation always beats licensing — so a single optimistic check cannot override the sum rule. Getting that algebra right took longer than the physics.

Testing inverted. The test fixtures are deliberately broken calculations, and they are the ground truth. If a broken fixture starts passing, the oracle has regressed — you fix the oracle, never the fixture. This inverts the usual relationship between tests and code, and it caught a real bug: OracleReport.misconceptions was harvesting only FAIL verdicts and silently dropping INCONCLUSIVE ones — which is exactly where the most important misconception ("imaginary means unstable") lives. The central teaching moment of the app was being filtered out by a one-line if.

Getting a negative number to survive a round trip. phonopy's sign convention for imaginary modes is fragile in a way nothing warns you about. Every layer — NumPy, Pydantic, JSON, Plotly — offers a helpful-looking way to abs(), clamp, or drop it, and every one of those "fixes" destroys the demo. There is now an explicit test asserting that a $-0.31$ THz frequency arrives at the client with its sign intact.

Rotational invariance is not the acoustic sum rule. The ASR is translational invariance, and it is the only sum rule most people are taught. The quadratic ZA branch requires rotational invariance, an independent condition that no standard code enforces by default and almost nobody checks. Building a fixture that satisfies one and violates the other — and verifying the ZA exponent flips cleanly from $1.999$ to $1.000$ — took real physics work.

Accomplishments that we're proud of

The safety property is demonstrable end-to-end, through HTTP and JSON, with a test asserting it. Post an ASR violation of $0.005$ to the API. The response contains a frequency of $-0.31$ THz. The licensed claim set contains structure_is_graphene and slab_is_isolated — and contains neither dynamically_stable nor dynamically_unstable. That is not a prompt. That is not a guardrail bolted on afterward. It is an architectural property, and it holds.

The physics is real, not decorative. The Dirac point closes to $2.5\times10^{-15}$ eV — machine precision. The $\Gamma$-point optical modes land at 910 cm$^{-1}$ (ZO) and 1609 cm$^{-1}$ — the graphene Raman G band, within 2% of experiment, from a hand-rotated bond-frame tensor.

And there is a misconception taxonomy (docs/misconceptions.yaml) written by a practising computational materials scientist, mapping each invariant violation to the false belief it indicates, why that belief is seductive to a smart person, and the Socratic question to ask instead of giving the answer.

What we learned

Epistemic honesty is an architecture, not a prompt. Every attempt to make an LLM say "I don't know" by asking it nicely fails under pressure. Give it a deterministic oracle that revokes claims, and it cannot do otherwise.

A failed check does not license the negation. This is the sentence I'd put on the wall. An unconverged calculation supports neither conclusion, and a tutor that treats "not stable" as "unstable" has taught the student something false while appearing rigorous.

Grounding beats scale. The tutor is not smarter than a chatbot. It just has something to be wrong against.

Codex is at its best when it is fenced. The agent respected every hard prohibition in AGENTS.md, refused to install packages when the sandbox had no network, and — when a test dependency was missing — stopped and reported it rather than working around it. The fence is what made the autonomy safe.

What's next for Phonon & Fermion visualization

More materials. Graphene is the hero case because everything is analytic and every failure is legible. The core is structure-agnostic: a tight-binding $H(\mathbf{k})$ from a symmetry-derived neighbour list and a phonopy $D(\mathbf{q})$ generalize immediately to hBN and MoS$_2$ .

Real DFT in the loop. The oracle does not care where the force constants come from. Wiring in Quantum ESPRESSO — and universal machine-learned interatomic potentials for near-DFT forces at millisecond latency — turns this from a teaching tool into a diagnostic one.

More invariants. k-point convergence, SCF residual, force–energy consistency, Born effective charges and LO–TO splitting. Every invariant added is a class of silent error made loud.

The taxonomy is the real artifact. Seven misconceptions are live; there are twenty more I have watched people make. Published on its own, mapped to the checks that catch each one, it would be useful to every group teaching electronic structure by apprenticeship — which is to say, all of them.

And the pattern generalizes. LLM + executable oracle + invariant checker is not specific to lattice dynamics. It applies to any domain where the answer can be computed and the model can be graded against it. Density functional theory is simply the hardest instance I know.

Built With

Share this project:

Updates