Skip to content

GROMACS 2025/2026 patches and kernel: fix the virial with an ENERGY bias, a replica exchange deadlock, COMMITTOR, virtual sites, MTS and shells - #1506

Merged
carlocamilloni merged 10 commits into
plumed:v2.10from
invemichele-peptone:gromacs-native-fixes
Oct 15, 2026
Merged

carlocamilloni merged 10 commits into
plumed:v2.10from
invemichele-peptone:gromacs-native-fixes

Conversation

@invemichele-peptone

@invemichele-peptone invemichele-peptone commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
Description

Follow-up of #1504, which fixed checkpointing in the GROMACS 2025/2026 patches. These are the other bugs I found in those patches, plus one in the PLUMED 2.10 kernel that affects all the GROMACS patches. The bugs in the GROMACS 2020-2024 patches (among them a double-counted PLUMED virial, i.e. a wrong pressure, since the GROMACS 2019 patch) are fixed in #1505 (for v2.9); the GROMACS 2022.5, 2023.5 and 2024.3 patches are identical in v2.9 and v2.10, so they get those fixes when v2.9 is merged here. #1507 ports both PRs to master.

Each commit fixes one bug, with a CHANGES entry. Two of the bugs (the virial, and replica exchange on several ranks) are in the kernel and affect all the GROMACS patches:

Virial with a bias on ENERGY and domain decomposition (kernel, src/core)

On the domains other than the first, the Box input was flagged noforce, so that the virial computed by PLUMED is added only once. But the same flag also stopped ENERGY from rescaling that rank's share of the virial of the MD code, which is spread over all ranks. The pressure was then wrong with any bias on ENERGY (e.g. OPES multithermal-multibaric) and domain decomposition, with all the GROMACS patches. A new flag, forces_added_elsewhere, now only stops adding PLUMED's own forces on those ranks, as PLUMED 2.9 did.

  • Alanine dipeptide, RESTRAINT ARG=ene SLOPE=-0.5, Pres-XX at step 0: 16.92 on 1 rank, 895.6 on 2 ranks and 29.8 on 3 ranks (GROMACS 2023.5 patch); now 16.92 on 1, 2 and 3 ranks, also with the GROMACS 2024.3 and 2026.4 patches.

Replica exchange with more than one rank per replica (kernel, src/core/GREX.cpp)

GREX::savePositions() shares the positions of all atoms, but then waits only for the inputs that are active on the step. When no action needs atoms on an exchange step, the exchange of the domain decomposition was started but never completed: with asynchronous sharing (the default on fewer than 10 ranks), the next exchange waited forever for messages that were never received, or, with small messages, received the positions of an earlier step. PLUMED 2.9 always waited. This affects -replex and -hrex with any GROMACS patch.

  • Two TIP4P water replicas on 2 ranks each, -hrex, a distance printed every 10 steps: hung at the step after the first exchange attempt with the 2.10 kernel (also with the current patches); now runs, with zero exchange energy for identical replicas.

PLUMED asking to stop, e.g. COMMITTOR

The GROMACS 2025/2026 patches ignored the request: the simulation ran to the end. It is now a stop condition of the GROMACS stop handler, registered in runner.cpp: it reaches all ranks and the simulations that share state, and mdrun stops at the next step at which GROMACS communicates signals (every nstglobalcomm steps, and at least every 200 steps between simulations), writing a checkpoint. The modular simulator (md-vv) stops at the next neighbor-search step instead: when asked to stop at another step, it clears the task queue it is running from, and crashes (a GROMACS bug).

  • Committing at step 2332 (leap-frog, 1 rank): ran to step 20000; now stops at step 2341. Also on 2 ranks, with md-vv, and with two walkers (both stop at step 201).

Virtual sites in the energy path

When PLUMED needs the potential energy, it runs at the end of do_force(), after GROMACS has spread the forces on the virtual sites and cleared them. The forces PLUMED applied on virtual sites (e.g. the M site of TIP4P water) were lost. They are now spread with their virial, on the steps when the atoms that PLUMED uses include virtual sites (from createFullList, which is the same on all ranks). The extra spread costs about 45 us per step, i.e. 2% of a GPU step for a 68k-atom TIP4P box (0.6% on CPU), so inputs that only bias the energy, e.g. OPES multithermal, do not pay for it.

  • TIP4P water, restraint between two M sites: adding ENERGY to the input changed the forces on those waters by 6.9e3 kJ/mol/nm; now by 0.001 (1 and 2 ranks). With the restraint between two oxygens there is no extra spread, and the forces are bitwise identical to the run without ENERGY.

Energy on MTS fast steps

With multiple time stepping, the slow forces and their energy are computed only every mts-level2-factor steps, so the energy passed to PLUMED on the other steps lacked the slow terms (650-1250 kJ/mol in a water test). mdrun now stops with an error if PLUMED needs the energy on such a step.

Shell (polarizable) particles

The shell relaxation calls do_force() again for each iteration, passing step 1: PLUMED calculated and updated on each of them, as step 1 (e.g. PRINT printed extra lines at step 1). PLUMED now uses the step from prepareStep(), and only recalculates its forces (performCalcNoUpdate) when called again on the same MD step (only in MD: the frames of a rerun can share a step, and CG minimization passes step -1).

  • SW water dimer, METAD + PRINT every step, 21 steps: COLVAR had 44 lines, with extra lines at step 1; now 21, and the same 6 hills.

Smaller fixes

  • In reruns, a stop request (e.g. COMMITTOR) was ignored: GROMACS overwrites the stop decision with the result of reading the next frame. rerun.cpp is now patched, as in the GROMACS 2020-2024 patches.
  • Errors raised on purpose by the PLUMED module (e.g. NotImplementedError for replica exchange with a bias) were caught and reported as internal errors ("bug"); their type and message are now kept.
  • GROMACS 2025: gmx_multisim_t was forward-declared as a class but defined as a struct.

Docs

The list of MD codes said that GROMACS 2025 and later have limited support, without saying what the patches add. It now has a table of what the PLUMED module of GROMACS 2025 and later, the patches for GROMACS 2025/2026 and the patches for GROMACS 2022-2024 support: ENERGY, multiple walkers, checkpoints, stop requests, shells, replica exchange with a bias, and lambda dynamics. The table follows the results of the regression tests below. The descriptions of the 2025/2026 patches (plumed patch --info) also list stop requests and shells.

Tests

The CI does not build GROMACS, so I wrote regression tests for PLUMED with GROMACS, and proposed them to the PLUMED testcenter in plumed-testcenter/plumed-testcenter#95, where they would run every week on all the GROMACS versions that PLUMED can patch. They compare PLUMED with references that do not depend on the versions (e.g. a RESTRAINT against the GROMACS pull code, or the same run on 1, 2 and 3 ranks), so the same tests run on any combination of GROMACS, patch and kernel. With GROMACS 2025.0 and 2026.4, they fail where described above with v2.10 and all pass with this branch; the replica exchange deadlock was found by them. They also show what the GROMACS 2025/2026 patches add to the PLUMED module of GROMACS: GROMACS 2025 without patches fails the tests of ENERGY, checkpoints, COMMITTOR, shells and replica exchange with a bias. I also tested by hand, with GROMACS 2025.0 and 2026.4 (MPI build) patched with this branch and with v2.10, and the PLUMED kernel of this branch:

  • the tests above, which fail with v2.10 and pass with this branch;
  • the checkpoint tests of GROMACS 2025/2026 patches: tell PLUMED about checkpoints before the force calculation (alternative to #1430) #1504 still pass (1 and 2 ranks, STATE files written at the checkpoint steps);
  • ENERGY still equals the GROMACS potential energy, and -replex with a PLUMED input that only prints still runs;
  • the kernel virial fix also with the GROMACS 2023.5 and 2024.3 patches, and with the kernel of master (where the same fix applies cleanly);
  • basic regtests: only the two failures that v2.10 already has (rt-average, rt-output-colvar-multi-dd);
  • patching a clean GROMACS tree gives exactly the files of this branch.
Target release

I would like my code to appear in release v2.10

Type of contribution
  • changes to code or doc authored by PLUMED developers, or additions of code in the core or within the default modules
  • changes to a module not authored by you
  • new module contribution or edit of a module authored by you
Copyright
  • I agree to transfer the copyright of the code I have written to the PLUMED developers or to the author of the code I am modifying.
  • the module I added or modified contains a COPYRIGHT file with the correct license information. Code should be released under an open source license. I also used the command cd src && ./header.sh mymodulename in order to make sure the headers of the module are correct.
Tests
  • I added a new regtest or modified an existing regtest to validate my changes.
  • I verified that all regtests are passed successfully on GitHub Actions.

🤖 Generated with Claude Code

invemichele-peptone and others added 10 commits October 14, 2026 16:44
On the domains other than the first, the Box input was flagged noforce, so
that the virial computed by PLUMED is added only once. But the same flag
also stopped ENERGY from rescaling that rank's share of the virial of the
MD code, which is spread over all ranks. The pressure was then wrong with
any bias on ENERGY and domain decomposition: in a GROMACS test, the virial
at step 0 was -725.7 on 2 ranks instead of 5.457. PLUMED 2.9 rescaled the
virial on all ranks.

A new flag, forces_added_elsewhere, now only stops adding PLUMED's forces
on those ranks. rescale_force skips a buffer the MD code did not pass, as
PLUMED 2.9 did for the virial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The patches passed setStopFlag to PLUMED but never read the flag, so
COMMITTOR could not stop mdrun. The GROMACS 2024 patch set bLastStep after
the force calculation, which with simulations that share state (e.g.
WALKERS_MPI) stops one simulation and deadlocks the others.

The force provider now reports the request with requestsStop(), and
runner.cpp registers it as a stop condition with the StopHandlerBuilder.
GROMACS then passes it to all ranks and to the simulations that share
state, in the legacy and in the modular simulator, and mdrun stops at the
next step at which GROMACS communicates signals (every nstglobalcomm steps,
and at least every 200 steps between simulations), writing a checkpoint,
with exit code 0. Only the main rank signals, since the flag is the same on all ranks.

The modular simulator stops at the next neighbor-search step instead: when
a stop is signalled for another step, it clears the task queue it is
running from, and crashes (seen with md-vv).

Tested on ala2 with COMMITTOR: the run stops 4-9 steps after committing
with leap-frog on 1 and 2 ranks, 13-25 steps after with md-vv, and two
walkers stop together. Before, all ran to the end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he energy path

When PLUMED needs the potential energy, it runs at the end of do_force(),
after GROMACS has spread the forces on the virtual sites and cleared them.
The forces PLUMED applied on virtual sites were then lost. They are now
spread like the other forces with an explicit virial in postProcessForces(),
on the steps when the atoms that PLUMED uses include virtual sites:
applyAfterPotentialEnergy() now returns whether they do. That list is the
same on all ranks, so that all take the same decision. The extra spread
costs about 45 us per step (2% of a GPU step for a 68k-atom TIP4P box), so
inputs that only bias the energy, e.g. OPES multithermal, do not pay for it.

Tested on TIP4P water with a restraint between two M sites: adding ENERGY
to the input changed the forces on those waters by 6.9e3 kJ/mol/nm, now by
0.001 on 1 rank and by 0 on 2 ranks. With the restraint between two oxygens
the forces do not change and there is no extra spread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fast step

With multiple time stepping, the slow forces and their energies are
computed only every mts-level2-factor steps. If PLUMED needed the energy on
another step, it got an energy without the slow terms: in a TIP4P test with
mts-level2-factor 2, ENERGY was off by 650-1250 kJ/mol on the odd steps.
mdrun now stops with an error, which says to need the energy only on the
slow steps (e.g. no bias on ENERGY) or not to use multiple time stepping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The force provider rethrew every exception as an InternalError, so GROMACS
reported e.g. replica exchange with a PLUMED bias as "Internal error (bug)".
GROMACS exceptions now pass unchanged, so this is reported as "Feature not
implemented"; PLUMED errors are still wrapped as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…laxation

With shell (polarizable) particles, relax_shell_flexcon() calls do_force()
again for each shell relaxation iteration, passing step 1. PLUMED then
calculated and updated on each of them, as step 1: e.g. PRINT printed extra
lines at step 1, and actions updating at every step (e.g. PACE=1) were
updated several times per step. PLUMED now uses the step from prepareStep(),
and only recalculates its forces (performCalcNoUpdate) when called again on
the same step. This is limited to MD, where prepareStep() gives the step:
e.g. the frames of a rerun can all have the same step, and the conjugate
gradient minimizer passes step -1. On a SW water dimer, COLVAR now has one line per step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a rerun, GROMACS sets isLastStep from the stop handler at the start of
each frame, but then overwrites it with the result of reading the next
frame: a stop request, e.g. from COMMITTOR through the stop condition of
the PLUMED module, was ignored and the rerun went through all the frames.
rerun.cpp is now patched to keep it, as in the GROMACS 2020-2024 patches.
Found by a regression test: a rerun with COMMITTOR committing at the first
frame went through all 11 frames.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GREX::savePositions() shares the positions of all atoms (shareAll), but
then waits only for the inputs that are active on this step (waitData).
When no action needs atoms on an exchange step, the domain decomposition
started its exchange but never completed it. With asynchronous sharing
(the default on fewer than 10 ranks), the sends were never received: the
next exchange waited for them forever with large messages, and with small
ones the following receives could get the positions of an earlier step.
PLUMED 2.9 always waited. Found by a GROMACS regression test: -hrex with
two TIP4P water replicas on 2 ranks each hung at the step after the first
exchange attempt with the PLUMED 2.10 kernel, and ran with the 2.9 one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A table in the list of MD codes compares the PLUMED module of GROMACS 2025 and later with the patches for
GROMACS 2025/2026 and for the older versions (ENERGY, multiple walkers, checkpoints, stop requests, shells,
replica exchange, lambda dynamics), as tested by the regression tests of the PLUMED testcenter. The
descriptions of the 2025/2026 patches also list stop requests and shells.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@invemichele-peptone

Copy link
Copy Markdown
Contributor Author

Follow-up in #1509: the constraint virial with MTS, shells in reruns and a warning for shells with ENERGY, reruns stopping at the frame that asks, and notes in the docs table. #1508 has the follow-up for v2.9.

🤖 Generated with Claude Code

invemichele-peptone added a commit to invemichele-peptone/plumed2 that referenced this pull request Oct 15, 2026
A table in the list of MD codes of the master manual compares the PLUMED module
of GROMACS 2025 and later with the patches for GROMACS 2025/2026 and for GROMACS
2024 (ENERGY, multiple simulations through MPI, checkpoints, stop requests,
shells, replica exchange, lambda dynamics), as tested by the regression tests of
the PLUMED testcenter, with notes on the limitations. It replaces the sentence
that suggested the patch for GROMACS 2025/2026 for replica exchange and lambda
dynamics, which only the patch for GROMACS 2024 has. v2.10 has the same table in
user-doc/Introduction.md (plumed#1506, plumed#1509).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
carlocamilloni pushed a commit that referenced this pull request Oct 15, 2026
… MTS, shells in reruns and with ENERGY, rerun stop, docs) (#1509)

* GROMACS 2025/2026 patches: with MTS, add PLUMED's forces also to the normal force buffer

When PLUMED needs the energy, it applies its forces after the force calculation,
and with multiple time stepping to the combined MTS buffer, which the update
uses. On the slow steps that compute the virial, GROMACS computes the constraint
virial from the normal buffer (and writes it to the trajectory), which then
lacked the part of PLUMED's forces that the constraints pass on: e.g. 2.7, -0.5
and 3.8 kJ/mol on the virial of a restraint between two water oxygens, against
the GROMACS pull code. The difference PLUMED made to the combined buffer is now
added to the normal one too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* GROMACS 2025/2026 patches: shells in reruns, a warning for shells with ENERGY, and the stop of reruns

- Reruns now call prepareStep() too, and a call is "repeated" when PLUMED already
  calculated since the last prepareStep(), not on the same step number (frames of
  a rerun can share it). With shells, reruns then update PLUMED once per frame, as
  MD does, instead of on each iteration of the shell relaxation, as step 1.
- PLUMED updates on the first force calculation of the step, before the shells
  are relaxed. When the input needs the energy, that energy is the one before the
  relaxation: mdrun now prints a warning, once.
- A rerun stops after the frame on which PLUMED asks for it, as with the GROMACS
  2020-2024 patches, instead of after the next one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Docs: notes on the GROMACS interfaces table, and corrections to CHANGES

- The table now notes that GROMACS 2026.0-2026.3 without patches stop with more
  than one MPI rank, that ENERGY and the checkpoint data need the legacy
  simulator with md-vv (GMX_DISABLE_MODULAR_SIMULATOR=1), that with MTS the
  energy is available on the slow steps only, and the limitation of shells with
  ENERGY. Multiple walkers through files also work without patches: the row is
  about simulations that communicate through MPI.
- CHANGES and patch descriptions: after a stop request, mdrun runs one more step
  after the next communication of signals, which between simulations happens
  every 200 steps or more; \ref links for the doxygen manual of v2.10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
carlocamilloni pushed a commit that referenced this pull request Oct 15, 2026
A table in the list of MD codes of the master manual compares the PLUMED module
of GROMACS 2025 and later with the patches for GROMACS 2025/2026 and for GROMACS
2024 (ENERGY, multiple simulations through MPI, checkpoints, stop requests,
shells, replica exchange, lambda dynamics), as tested by the regression tests of
the PLUMED testcenter, with notes on the limitations. It replaces the sentence
that suggested the patch for GROMACS 2025/2026 for replica exchange and lambda
dynamics, which only the patch for GROMACS 2024 has. v2.10 has the same table in
user-doc/Introduction.md (#1506, #1509).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@invemichele-peptone
invemichele-peptone deleted the gromacs-native-fixes branch October 15, 2026 14:48
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.

2 participants