Skip to content

Fix charge correction validation for membrane (SolvatedPDBComponent) systems#1979

Open
slochower wants to merge 1 commit into
OpenFreeEnergy:mainfrom
slochower:fix/membrane-charge-correction
Open

Fix charge correction validation for membrane (SolvatedPDBComponent) systems#1979
slochower wants to merge 1 commit into
OpenFreeEnergy:mainfrom
slochower:fix/membrane-charge-correction

Conversation

@slochower
Copy link
Copy Markdown

When a ChemicalSystem contains a ProteinMembraneComponent (which inherits from SolvatedPDBComponent) but no explicit SolventComponent, the charge correction validation raises:

ValueError: Cannot use explicit charge correction without solvent

This is because the validation only checks stateA.contains(SolventComponent). However, the system is solvated and the water and ions are part of the ProteinMembraneComponent. The system construction code already handles this correctly (hybridtop_units.py line 203 sets solvent_comp = protein_comp for SolvatedPDBComponents), but the validation doesn't use the same logic.

Checklist

  • All new code is appropriately documented (user-facing code must have complete docstrings).
  • Added a news entry, or the changes are not user-facing.
  • Ran pre-commit: you can run pre-commit locally or comment on this PR with pre-commit.ci autofix.

Manual Tests: these are slow so don't need to be run every commit, only before merging and when relevant changes are made (generally at reviewer-discretion).

Developers certificate of origin

Replace the monolithic `_get_ion_and_water_parameters` with three
focused functions that handle ion parameter lookup in order of
preference:

1. Most abundant monovalent ion of the correct charge sign already
   present in the topology.
2. Divalent or wrong-sign ions are skipped by the monovalent filter.
3. If no suitable ion exists (e.g. zero ionic strength or a
   SolvatedPDBComponent without ions), a minimal single-ion system
   is built from the forcefield to obtain NA/CL parameters.

This approach is adapted from OpenFE PR OpenFreeEnergy#1978. The key API change is
that `handle_alchemical_waters` and `_handle_net_charge` now accept
a `forcefield` (from the system generator) instead of a
`solvent_component`, since what we actually need is the ability to
parameterize an ion — not the component metadata.

The mutation only modifies NonbondedForce parameters (charge, sigma,
epsilon), leaving bonded terms untouched. This is safe for rigid water
models (TIP3P, SPC/E) where geometry is enforced by SETTLE/SHAKE
constraints rather than harmonic forces. Added documentation warning
that flexible water models would produce unphysical forces on the
ghost hydrogens.

Also adds SolvatedPDBComponent support to `_validate_charge_difference`
so membrane systems can use explicit charge correction.
@slochower slochower force-pushed the fix/membrane-charge-correction branch from 7ea8f4e to 49e011d Compare May 21, 2026 23:21
@github-actions
Copy link
Copy Markdown

No API break detected ✅

@IAlibay
Copy link
Copy Markdown
Member

IAlibay commented May 22, 2026

@davidslochower thanks for opening this PR - I just wanted to let you know that there is an earlier PR addressing the same thing in #1978 so that will, for now (this may change depending on how things progress), take precedence over this one. That being said, the modifications you made here provide useful insights towards fixing this issue.

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.

3 participants