Repository navigation
Conversation
In mode ts the sweep scales the potential to λU but held the barostat at the full target pressure p for every λ. Under the RS/NPT mapping, sampling λU at (T0, λp) is the real system at (T0/λ, p), so the scaled system has to be barostatted at λp for the recorded volumes to lie on the isobar that integrate_rs assumes when it adds the constant p·V term. The routine already computed pf = lf*p and never used it; at p = 0 the two targets coincide, which is why the error went unnoticed. With |p| > 0 the swept volumes were too small and the free energy off by up to ~10 meV/atom in the reported campaign. fix npt only ramps its target linearly over a run, so the sweep re-issues the COM-constrained npt fix immediately before the sweep run with the ramp p -> lf*p (forward) and lf*p -> p (backward), re-attaching the COM temperature compute the redefinition drops. The middle equilibration of the backward leg, which runs the lf-scaled potential, now also sits at lf*p. The ramp matches λp exactly for the linear lambda schedule; for uniform_temperature it only interpolates λp between the end points, so a warning is logged at finite pressure and the docs say to use linear. The mirror-image slips in the real-thermostat ramps are fixed too: mode tscale and the pre-flight temperature scan ramped the barostat p -> lf*p while ramping the real thermostat with the unscaled potential, where the barostat has to stay at p. The tscale backward sweep also held the thermostat at t0 instead of ramping tf -> t0 as its log claimed. Goldens (all at p = 0) gain the re-issued fix lines and the corrected tscale backward thermostat. New tests at 50 kbar pin the barostat targets of every block in ts, tscale and the prescan. Closes #3 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy
pyscal3 4.0.0 (on PyPI since the last green run on main) removed the top-level System class that calphy.input imports, so every test module fails at collection with an unpinned install. Pin the 3.x series in pyproject.toml and the conda environment files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy
|
CI status on this PR, for the record: All four One more pre-existing failure will remain once collection works: df = pd.DataFrame(data=datadict)
df["error_code"] = df["error_code"].astype(object).where(df["error_code"].notna(), None)Happy to push it here or open a separate PR, whichever you prefer. Generated by Claude Code |
Review suggestion on the backward-sweep comment; applied to the matching forward-sweep comment as well. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy
|
Verified by MD against independent references. The fix holds on both signs of pressure, and it also recovers runs that used to crash. Tested at System: bcc Fe, SNAP, 5488 atoms, 32 ranks, The patched path is what ranFrom the LAMMPS logs — the sweep barostat ramps, the equilibrations stay pinned:
ResultsReferences are independent of the sweep: a single-temperature
The volume row is the cleanest of these: it is a state function, so it needs no anchor, no alignment and no stitching convention, and It also retires a separate explanationChunk-A runs at negative pressure had been dying with It was the barostat. The −2.5 GPa run above uses the 100 → 800 K window that had produced no complete RS iteration unpatched; patched, it completed in 18 h. The mechanism is the same as the free-energy error: at Caveats on this evidence
One note on test design, if it is usefulThe decisive gate was not +5 GPa, where the error is 9.8 meV/atom — a fix is hard to get wrong there. It was −2.5 GPa, where the error is 0.6 meV/atom: a patch that overshoots, or that gets the sense of λ backwards, passes the large-error test and fails the small one. Both predictions were fixed in writing before either job was submitted. |
…t barostat chords The uniform_temperature schedule makes T0/lambda linear in the MD step, so lambda is a hyperbola in the step. No LAMMPS barostat accepts a variable target (fix npt, nph, press/berendsen and press/langevin all reject v_name) and fix npt only ramps linearly over one run, so the previous commit could only interpolate lambda*p between the sweep end points and warn: the barostat overshot lambda*p mid-sweep by 8 % for a 400 -> 700 K sweep, 33 % for 1000 -> 3000 K and 153 % for 100 -> 800 K. Instead of approximating lambda*p by a chord, make the schedule itself piecewise linear. _sweep_segments splits the sweep into up to SWEEP_MAX_SEGMENTS sub-runs whose end points lie on the exact hyperbola; _run_sweep redefines the lambda variable as ramp() between them before each sub-run and re-issues the integrator fix with the chord p*lambda_a -> p*lambda_b. Within a run lambda is then linear in the step, so the barostat equals lambda*p at every step and the free-energy integral, taken over the recorded lambda grid, is exact. The only approximation left is in the sampling density, which deviates from "uniform in T" by O(1/K^2), 0.2 % at K = 20 for 1000 -> 3000 K. Each segment boundary zeroes the barostat velocity when the fix is re-issued, so segments are kept at least ten damping times long; short sweeps fall back to fewer segments, down to a single linear ramp. The runtime warning is removed. The ts_uniform_temperature golden now shows the five 1000-step segments of the 5000-step B6 sweep. New tests check both sweep directions: contiguous lambda chain, every chord equal to p*lambda at both ends, boundaries on the hyperbola, step counts summing to the sweep length, and the segment-count bounds. The linear- schedule tests additionally assert that no run sits between the re-issued fix and the sweep run. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy
…ith exact barostat chords" This reverts commit 0793c34.
A barostatted reversible-scaling sweep has to hold the scaled system at lambda*p, and fix npt can only ramp its target linearly over a run (no LAMMPS barostat accepts a variable target). That equals lambda*p for the linear schedule only; uniform_temperature makes lambda a hyperbola in the step, so the barostat would overshoot lambda*p mid-sweep by 8 % for 400 -> 700 K and 153 % for 100 -> 800 K. Rather than run that knowingly wrong behind a warning, reject the combination at input validation. p = 0 (where the ramp is 0 -> 0) and npt: false stay allowed. A piecewise-linear segmented schedule that makes the combination exact follows in a separate change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy
…dule Review: comments that point at each other across the file are unreadable. Every comment this PR added now states its own reason in place, without "see X" pointers. The tscale comment takes the reviewer's wording. The reversible_scaling docstring gains a flowchart of the thermostat and barostat targets through one cycle, and the helper docstring explains why fixedpoint stays at the centre of mass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy
Review: neither belongs in the code. The fixedpoint keyword stays, matching the other npt fixes in the sweep routines; the pressure schedule chart lives in the PR discussion. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy
|
Closing: superseded by upstream. ICAMS/calphy PR ICAMS#283 (merged 2026-09-29, in main from 2.2.1) contains the same fix: the sweep barostat ramps λ·P in both directions via Not covered upstream and still open: #5. Generated by Claude Code |
Closes #3.
What was wrong
In
mode: tsthe sweep scales the potential to λU but pinned the barostat at the full target pressurepfor every λ. Sampling λU at (T₀, λp) is the real system at (T₀/λ, p), so the scaled system has to be held at λp for the swept volumes to lie on the isobar thatintegrate_rsassumes when it adds its constantp·Vterm.pf = lf * piwas computed and only ever logged. Atp = 0the two targets coincide, which is why every existing golden passed.Changes
mode: ts(_reversible_scaling_forward/_backward)fix nptonly ramps linearly over arun, so a new helper_rs_sweep_barostatre-issues the COM-constrainedf1fix immediately before the sweep run withiso p → lf·p(forward) andiso lf·p → p(backward), and re-attachesfix_modify f1 temp tcm, which the redefinition drops.lf·pinstead ofp.lambda_schedule: uniform_temperatureis refused at finite pressure at input validation (p = 0 andnpt: falsestay allowed). λ is a hyperbola in the step under that schedule, and no LAMMPS barostat accepts a variable target, so a linear ramp cannot track λp. The schedule is deprecated upstream, so this refusal is the final behaviour rather than a stopgap.mode: tscaleand the pre-flight scan (the mirror-image slips flagged in the issue)pinstead of rampingp → lf·p.t0; it now rampstf → t0as its log message already claimed.Tests / goldens
p = 0) gain the re-issued fix lines and the corrected tscale backward thermostat; nothing else in the streams moved.Pstart/Pstopof every NPT block in ts forward/backward (and that norunsits between the re-issued fix and the sweep), theuniform_temperaturerefusal, tscale and the prescan. They fail onmain.Housekeeping
pyscal3<4pinned: 4.0.0 removed theSystemclass calphy imports and broke test collection onmaintoo.Verification
MD, against independent references (bcc Fe SNAP, 5488 atoms,
mode: ts100 → 800 K, details in this comment):F(500 K, +5 GPa)mode: fe)V(500 K, +5 GPa)Vover 100 → 800 KF(500 K, −2.5 GPa)Residuals sit inside the runs' own RS dissipation (0.22 and 0.26 meV/atom, single iteration each). The LAMMPS logs confirm the sweep barostat ramps
50000 → 6250and-25000 → -3125bar while the equilibrations stay pinned. The fix also recovers the negative-pressure wide-window runs that previously died withDomain too large: that was the full pressure applied to a potential scaled to 0.125·U, not the λ-span itself.An independent review with short 256-atom Cu EAM runs (+50 kbar heating, −20 kbar cooling) confirmed
presstracks λp to within 1 % along the sweep, volumes match true NPT values, and the fix re-issue causes no transient beyond the one already present onmain.Not MD-tested:
tscale, covered at the command-stream level.Unit tests:
tests/test_golden_streams.pyand the full suite pass locally. One pre-existing failure is unrelated:test_damaged_sweep_file_does_not_abort_the_gatherfails onmaintoo under pandas 3 (NaN vsNone).Out of scope, filed separately: #5 (
integrate_rsaddsp·Vundernpt: False).🤖 Generated with Claude Code
https://claude.ai/code/session_01JgUx1cRgji82mZBoX7UDCy