Skip to content

Phonons at temperature: the 0 K stability answer is often the wrong one - #14

Merged
Starlitnightly merged 2 commits into
mainfrom
hiphive-scph
Aug 3, 2026
Merged

Phonons at temperature: the 0 K stability answer is often the wrong one#14
Starlitnightly merged 2 commits into
mainfrom
hiphive-scph

Conversation

@Starlitnightly

Copy link
Copy Markdown
Contributor

mv.prop.phonon_at_temperature fits, through hiphive, the effective harmonic force constants that best describe the potential energy surface sampled at a temperature — rather than expanding about the 0 K minimum.

obs["dynamically_stable_{level}"] from mv.prop.phonon is a statement about 0 K, and a great many real materials fail it and exist anyway. bcc metals and cubic perovskites are unstable in the harmonic approximation and held up by anharmonicity at the temperature they are actually used at. A screen that discarded them on the 0 K answer would be discarding the answer.

Three lattices, three answers

50 K 300 K 600 K 900 K verdict
bcc Cu 4 0 0 0 stabilised at 300 K
fcc Cu 0 0 0 0 nothing to stabilise
sc Cu 21 21 21 21 never stabilised in range

stabilisation_temperature is NaN for both fcc and sc, for opposite reasons, so uns[...]["verdict"] says which. A NaN meaning two opposite things is worse than no column, and a test asserts the two verdicts differ.

I nearly shipped a wrong conclusion

Lattice.cubic(2.9) with one atom is simple cubic, not bcc. On that structure the method looked erratic — 72 imaginary modes at 50 K, and a stabilisation temperature that moved from 900 K to 300 K on iteration count alone. I was about to report the method as unreliable.

It was the input that was wrong. With the real bcc primitive the answer is identical at 8 and 20 iterations, and a test now asserts that, so a genuine convergence failure would be visible rather than inferred.

Two diagnostics, because both change the answer silently

  • n_free_parameters — the cluster space size. A strongly unstable cell with four gave imaginary modes reappearing at higher temperature (not physics); eleven did not. Fewer than six warns. On well-behaved cases both cutoffs agree exactly, so a small cluster space is a risk, not a guaranteed error — the note says that rather than overclaiming.
  • convergence_drift — how far the parameters were still moving over the last five iterations. This is a fixed-point iteration run for a fixed step count, so it does not report its own convergence.

The cutoff is checked against half the shortest supercell dimension up front rather than failing deep inside the fit. hiphive's stdout reporting is captured — a library should not print into the middle of somebody else's loop — and a test asserts it.

A CI job of its own

hiphive reaches numba through trainstation, and numba caps numpy < 2.5. Adding it to the existing extras would quietly downgrade numpy on the 3.12 leg — which exists precisely to test the newest numpy. The extra would be covered at the cost of no longer covering what that leg is for, so it gets its own job.

The tutorial says plainly that its cell prints a fallback in the rendered docs (the docs environment runs numpy 2.5) and that the table beside it is what the cell produces where hiphive is installed.

Verification

  • 948 pass on py3.12 without hiphive; 846 on py3.10; the 9 self-consistent-phonon tests pass in an environment with hiphive and numpy 2.4.6.
  • Contract-verified rate stays 165/165. All 16 notebooks execute. Docs build.

🤖 Generated with Claude Code

https://claude.ai/code/session_016wh5NzNE9Wn49nuUm7zg2a

Zehua Zeng and others added 2 commits August 2, 2026 22:40
mv.prop.phonon_at_temperature fits, through hiphive, the effective harmonic
force constants that best describe the potential energy surface sampled *at* a
temperature, rather than expanding about the 0 K minimum.

obs['dynamically_stable_{level}'] from mv.prop.phonon is a statement about 0 K,
and a great many real materials fail it and exist anyway: bcc metals and cubic
perovskites are unstable in the harmonic approximation and held up by
anharmonicity at the temperature they are used at. A screen that discarded them
on the 0 K answer would be discarding the answer.

Three copper lattices give the three answers this can return, and the suite
asserts each:

  bcc  4 imaginary modes at 50 K, none from 300 K   -> stabilised at 300 K
  fcc  none at any temperature                      -> nothing to stabilise
  sc   21 at every temperature                      -> never stabilised

obs['stabilisation_temperature_{level}'] is NaN for both fcc and sc, for
opposite reasons, so uns[...]['verdict'] says which. A NaN meaning two opposite
things is worse than no column.

I nearly shipped a wrong conclusion here. Lattice.cubic(2.9) with one atom is
simple cubic, not bcc, and on that structure the method looked erratic - 72
imaginary modes at 50 K and a stabilisation temperature that moved from 900 K
to 300 K on iteration count alone. It was the input that was wrong. With the
real bcc primitive the answer is identical at 8 and 20 iterations, and a test
now asserts that so a genuine convergence failure would be visible rather than
inferred.

Two diagnostics are recorded because both change the answer silently.
n_free_parameters is the size of the cluster space: a strongly unstable cell
with four of them gave imaginary modes reappearing at a higher temperature,
which is not physics, and eleven did not. Fewer than six now warns. Note that
on well-behaved cases the two cutoffs agree exactly, so a small cluster space is
a risk rather than a guaranteed error, and the note says so rather than
overclaiming. convergence_drift is how far the parameters were still moving over
the last five iterations, because a fixed-point iteration run for a fixed number
of steps does not report its own convergence.

The cutoff is checked against half the shortest supercell dimension up front,
rather than left to a confusing failure deep inside the fit. hiphive's stdout
reporting is captured, because a library should not print into the middle of
somebody else's loop, and a test asserts it.

hiphive reaches numba through trainstation and numba caps numpy below 2.5, so
matverse[anharmonic] gets a CI job of its own. Adding it to the existing extras
would quietly downgrade numpy on the 3.12 leg, which exists precisely to test
the newest numpy - the extra would be covered at the cost of no longer covering
what that leg is for.

The tutorial says plainly that its cell prints a fallback in the rendered docs,
because the environment that builds them runs numpy 2.5 and hiphive cannot, and
that the table beside it is what the cell produces where hiphive is installed.

948 pass on py3.12 without hiphive, 846 on py3.10, and the nine
self-consistent-phonon tests pass in an environment with hiphive and numpy
2.4.6. Contract-verified rate stays 165/165, all 16 notebooks execute, docs
build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wh5NzNE9Wn49nuUm7zg2a
…them

CI caught what one machine could not. The anharmonic job reported 22 imaginary
modes for bcc copper at 300 K where there should be none, on a solve whose
drift diagnostic had already flagged it as unconverged. Locally the same
settings gave the right answer on five different seeds with a worst drift of
0.023. The stochastic sampling differs with the BLAS underneath, so a setting
that converges on the machine it was tuned on is not a setting that converges.

Defaults raised from 10 iterations and 15 structures to 20 and 25, which brings
the worst drift across those seeds from 0.023 to 0.007.

Chasing that turned up a worse mistake in the test rather than the code. With
proper convergence bcc copper came back *stable* at 50 K, which looked like the
method destroying the very effect it exists to detect. It was not: the
transition sits between 25 K and 100 K, and 50 K is on it. Scanning 5, 25, 50,
100 and 200 K shows four imaginary modes at 5 and 25 K under both 8 and 30
iterations, and the only thing convergence moves is where in that window the
crossing lands - 100 K at 8 iterations, 50 K at 30.

So the test was asserting the resolution limit and calling it physics. It now
brackets the transition instead, asserting instability at 5 K and 25 K and
stability at 300 K and 600 K, and leaving the boundary alone. The notes and the
tutorial say that the crossing is resolved no better than the spacing scanned
and that it moves with convergence, rather than quoting a number as if it were
sharp.

A test that runs first asserts the fixture converged at all, so a convergence
failure is named as one instead of surfacing as the physics being wrong. The
fixture deliberately runs past the defaults, because these tests assert a
specific physical outcome and so have to be somewhere it has converged.

948 pass on py3.12 without hiphive; the ten self-consistent-phonon tests pass
with hiphive on numpy 2.4.6. Contract-verified rate stays 165/165, all 16
notebooks execute, docs build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wh5NzNE9Wn49nuUm7zg2a
@Starlitnightly
Starlitnightly merged commit 41b58cc into main Aug 3, 2026
5 checks passed
@Starlitnightly
Starlitnightly deleted the hiphive-scph branch August 3, 2026 06:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant