Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
49ede96
move the protocols results to a single file and deduplicate
IAlibay Jan 1, 2026
6b504a8
rename base units file
IAlibay Jan 1, 2026
8abf04f
fix some imports
IAlibay Jan 1, 2026
a3e228f
import fix
IAlibay Jan 1, 2026
efcee64
fix some more imports
IAlibay Jan 1, 2026
d11ab5a
update some docstring
IAlibay Jan 1, 2026
65bfb04
some changes
IAlibay Jan 1, 2026
aa42720
Store for a second
IAlibay Jan 1, 2026
f72c23d
udpate system_generator getter
IAlibay Jan 1, 2026
d0c1889
Some progress
IAlibay Jan 1, 2026
b2e266f
Add a few things
IAlibay Jan 2, 2026
7091102
Some sampler stuff
IAlibay Jan 2, 2026
696b806
some more things
IAlibay Jan 2, 2026
9bc47f1
some more progress
IAlibay Jan 2, 2026
312d19e
finish analysis unit
IAlibay Jan 2, 2026
7aa9930
Migrate some things along
IAlibay Jan 3, 2026
889ea7c
Hook up multi-units to the protocols
IAlibay Jan 3, 2026
c745599
some fixes
IAlibay Jan 3, 2026
fbcef69
fix tokenization tests
IAlibay Jan 3, 2026
ba716b6
fix various tokenization things
IAlibay Jan 3, 2026
e914d56
fix gather tests
IAlibay Jan 3, 2026
9198e9e
some more progress
IAlibay Jan 3, 2026
4cf4d66
various fixes
IAlibay Jan 4, 2026
a802eac
various more AHFE test fixes
IAlibay Jan 4, 2026
1665431
some test fixes
IAlibay Jan 4, 2026
58b9fcd
fix everything
IAlibay Jan 4, 2026
7c3d5c3
fix energies tests
IAlibay Jan 4, 2026
2443250
various fixes for the abfe tests
IAlibay Jan 4, 2026
5fcacaf
remove extra run parameter
IAlibay Jan 5, 2026
a119264
fix some ahfe slow tests
IAlibay Jan 5, 2026
78bbefc
change check
IAlibay Jan 5, 2026
58d3363
fix up some tests
IAlibay Jan 6, 2026
2e3e1dc
fix test
IAlibay Jan 7, 2026
035c6fb
undo rerun comment
IAlibay Jan 7, 2026
aec87dd
Merge branch 'main' into multi-unit-afe
IAlibay Jan 7, 2026
42f4521
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 7, 2026
6021928
Add news item
IAlibay Jan 7, 2026
ba1e9cd
add PR number to news item
IAlibay Jan 7, 2026
a2b69fb
try nanometer array quantity instead
IAlibay Jan 7, 2026
281adb5
mypy fixes
IAlibay Jan 7, 2026
ff7f934
Merge branch 'main' into multi-unit-afe
IAlibay Jan 15, 2026
7e0dd9f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 15, 2026
c7afc70
migrate fix from rfe protocol
IAlibay Jan 15, 2026
c3b915f
fix that one test
IAlibay Jan 15, 2026
4743e56
Move docs around
IAlibay Jan 16, 2026
4a33014
Various fixes
IAlibay Jan 16, 2026
f805e33
Merge branch 'main' into multi-unit-afe
IAlibay Jan 16, 2026
5716ea4
fix ignore statement
IAlibay Jan 16, 2026
20c991d
Merge branch 'multi-unit-afe' of github.com:OpenFreeEnergy/openfe int…
IAlibay Jan 16, 2026
a6846b0
Merge branch 'main' into multi-unit-afe
IAlibay Jan 21, 2026
91ff574
Merge branch 'main' into multi-unit-afe
IAlibay Jan 22, 2026
30bf063
Add phase to AHFE legs
IAlibay Jan 22, 2026
6a1b887
Add info on how to reassign velocities
IAlibay Jan 22, 2026
385f773
move patching to a single fixture
IAlibay Jan 22, 2026
fa9f745
move patching to a fixture
IAlibay Jan 22, 2026
d84aaea
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 22, 2026
1f07ae5
fix test
IAlibay Jan 22, 2026
0e59c43
Merge branch 'multi-unit-afe' of github.com:OpenFreeEnergy/openfe int…
IAlibay Jan 22, 2026
9b10e4c
Fix CLI for new abfe multi-unit (no tests)
IAlibay Jan 22, 2026
e629a95
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions docs/reference/api/openmm_binding_afe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ Protocol API specification
:toctree: generated/

AbsoluteBindingProtocol
AbsoluteBindingComplexUnit
AbsoluteBindingSolventUnit
ABFEComplexAnalysisUnit
ABFEComplexSetupUnit
ABFEComplexSimUnit
ABFESolventAnalysisUnit
ABFESolventSetupUnit
ABFESolventSimUnit
AbsoluteBindingProtocolResult

Protocol Settings
Expand Down
8 changes: 6 additions & 2 deletions docs/reference/api/openmm_solvation_afe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ Protocol API specification
:toctree: generated/

AbsoluteSolvationProtocol
AbsoluteSolvationVacuumUnit
AbsoluteSolvationSolventUnit
AHFESolventAnalysisUnit
AHFESolventSetupUnit
AHFESolventSimUnit
AHFEVacuumAnalysisUnit
AHFEVacuumSetupUnit
AHFEVacuumSimUnit
AbsoluteSolvationProtocolResult

Protocol Settings
Expand Down
26 changes: 26 additions & 0 deletions news/multi-unit-afe.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
**Added:**

* <news item>

**Changed:**

* The absolute free energy protocols have been broken into multiple
protocol units, allowing for setup, run, and analysis to happen
separately in the future when relevant changes to protocol execution are
made (PR #1776).

**Deprecated:**

* <news item>

**Removed:**

* <news item>

**Fixed:**

* <news item>

**Security:**

* <news item>
32 changes: 24 additions & 8 deletions openfe/protocols/openmm_afe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@
"""

from .abfe_units import (
AbsoluteBindingComplexUnit,
AbsoluteBindingSolventUnit,
ABFEComplexAnalysisUnit,
ABFEComplexSetupUnit,
ABFEComplexSimUnit,
ABFESolventAnalysisUnit,
ABFESolventSetupUnit,
ABFESolventSimUnit,
)
from .afe_protocol_results import (
AbsoluteBindingProtocolResult,
AbsoluteSolvationProtocolResult,
)
from .ahfe_units import (
AbsoluteSolvationSolventUnit,
AbsoluteSolvationVacuumUnit,
AHFESolventAnalysisUnit,
AHFESolventSetupUnit,
AHFESolventSimUnit,
AHFEVacuumAnalysisUnit,
AHFEVacuumSetupUnit,
AHFEVacuumSimUnit,
)
from .equil_binding_afe_method import (
AbsoluteBindingProtocol,
Expand All @@ -30,11 +38,19 @@
"AbsoluteSolvationProtocol",
"AbsoluteSolvationSettings",
"AbsoluteSolvationProtocolResult",
"AbsoluteVacuumUnit",
"AbsoluteSolventUnit",
"AHFESolventSetupUnit",
"AHFESolventSimUnit",
"AHFESolventAnalysisUnit",
"AHFEVacuumSetupUnit",
"AHFEVacuumSimUnit",
"AHFEVacuumAnalysisUnit",
"AbsoluteBindingProtocol",
"AbsoluteBindingSettings",
"AbsoluteBindingProtocolResult",
"AbsoluteBindingComplexUnit",
"AbsoluteBindingSolventUnit",
"ABFEComplexSetupUnit",
"ABFEComplexSimUnit",
"ABFEComplexAnalysisUnit",
"ABFESolventSetupUnit",
"ABFESolventSimUnit",
"ABFESolventAnalysisUnit",
]
97 changes: 72 additions & 25 deletions openfe/protocols/openmm_afe/abfe_units.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# This code is part of OpenFE and is licensed under the MIT license.
# For details, see https://github.com/OpenFreeEnergy/openfe
# This code is part of OpenFE and is licensed under the MIT license.
# For details, see https://github.com/OpenFreeEnergy/openfe
"""ABFE Protocol Units --- :mod:`openfe.protocols.openmm_afe.abfe_units`
========================================================================
This module defines the ProtocolUnits for the
Expand All @@ -23,7 +21,7 @@
from openmm import System
from openmm import unit as ommunit
from openmm.app import Topology as omm_topology
from openmmtools.states import GlobalParameterState, ThermodynamicState
from openmmtools.states import ThermodynamicState
from rdkit import Chem

from openfe.protocols.openmm_afe.equil_afe_settings import (
Expand All @@ -36,18 +34,16 @@
from openfe.protocols.restraint_utils.openmm import omm_restraints
from openfe.protocols.restraint_utils.openmm.omm_restraints import BoreschRestraint

from .base_afe_units import BaseAbsoluteUnit
from .base_afe_units import (
BaseAbsoluteMultiStateAnalysisUnit,
BaseAbsoluteMultiStateSimulationUnit,
BaseAbsoluteSetupUnit,
)

logger = logging.getLogger(__name__)


class AbsoluteBindingComplexUnit(BaseAbsoluteUnit):
"""
Protocol Unit for the complex phase of an absolute binding free energy
"""

simtype = "complex"

class ComplexComponentsMixin:
def _get_components(self):
"""
Get the relevant components for a complex transformation.
Expand Down Expand Up @@ -75,7 +71,9 @@ def _get_components(self):
# Similarly we don't need to check prot_comp
return alchem_comps, solv_comp, prot_comp, off_comps

def _handle_settings(self) -> dict[str, SettingsBaseModel]:

class ComplexSettingsMixin:
def _get_settings(self) -> dict[str, SettingsBaseModel]:
"""
Extract the relevant settings for a complex transformation.

Expand All @@ -97,7 +95,7 @@ def _handle_settings(self) -> dict[str, SettingsBaseModel]:
* output_settings: MultiStateOutputSettings
* restraint_settings: BaseRestraintSettings
"""
prot_settings = self._inputs["protocol"].settings
prot_settings = self._inputs["protocol"].settings # type: ignore[attr-defined]

settings = {}
settings["forcefield_settings"] = prot_settings.forcefield_settings
Expand All @@ -116,6 +114,15 @@ def _handle_settings(self) -> dict[str, SettingsBaseModel]:

return settings


class ABFEComplexSetupUnit(ComplexComponentsMixin, ComplexSettingsMixin, BaseAbsoluteSetupUnit):
"""
Setup unit for the complex phase of absolute binding free energy
transformations.
"""

simtype = "complex"

@staticmethod
def _get_mda_universe(
topology: omm_topology,
Expand Down Expand Up @@ -261,7 +268,6 @@ def _add_restraints(
comp_resids: dict[Component, npt.NDArray],
settings: dict[str, SettingsBaseModel],
) -> tuple[
GlobalParameterState,
Quantity,
System,
geometry.HostGuestRestraintGeometry,
Expand Down Expand Up @@ -295,9 +301,6 @@ def _add_restraints(

Returns
-------
restraint_parameter_state : RestraintParameterState
A RestraintParameterState object that defines the control
parameter for the restraint.
correction : openff.units.Quantity
The standard state correction for the restraint.
system : openmm.System
Expand Down Expand Up @@ -380,10 +383,7 @@ def _add_restraints(
rest_geom,
)

# Get the GlobalParameterState for the restraint
restraint_parameter_state = omm_restraints.RestraintParameterState(lambda_restraints=1.0)
return (
restraint_parameter_state,
correction,
# Remove the thermostat, otherwise you'll get an
# Andersen thermostat by default!
Expand All @@ -392,13 +392,28 @@ def _add_restraints(
)


class AbsoluteBindingSolventUnit(BaseAbsoluteUnit):
class ABFEComplexSimUnit(
ComplexComponentsMixin, ComplexSettingsMixin, BaseAbsoluteMultiStateSimulationUnit
):
"""
Protocol Unit for the solvent phase of an absolute binding free energy
Multi-state simulation (e.g. multi replica methods like Hamiltonian
replica exchange) unit for the complex phase of absolute binding
free energy transformations.
"""

simtype = "solvent"
simtype = "complex"


class ABFEComplexAnalysisUnit(ComplexSettingsMixin, BaseAbsoluteMultiStateAnalysisUnit):
"""
Analysis unit for multi-state simulations with the complex phase
of absolute binding free energy transformations.
"""

simtype = "complex"


class SolventComponentsMixin:
def _get_components(self):
"""
Get the relevant components for a solvent transformation.
Expand Down Expand Up @@ -426,7 +441,9 @@ def _get_components(self):
# Similarly we don't need to check prot_comp just return None
return alchem_comps, solv_comp, None, off_comps

def _handle_settings(self) -> dict[str, SettingsBaseModel]:

class SolventSettingsMixin:
def _get_settings(self) -> dict[str, SettingsBaseModel]:
"""
Extract the relevant settings for a solvent transformation.

Expand All @@ -447,7 +464,7 @@ def _handle_settings(self) -> dict[str, SettingsBaseModel]:
* simulation_settings : MultiStateSimulationSettings
* output_settings: MultiStateOutputSettings
"""
prot_settings = self._inputs["protocol"].settings
prot_settings = self._inputs["protocol"].settings # type: ignore[attr-defined]

settings = {}
settings["forcefield_settings"] = prot_settings.forcefield_settings
Expand All @@ -464,3 +481,33 @@ def _handle_settings(self) -> dict[str, SettingsBaseModel]:
settings["output_settings"] = prot_settings.solvent_output_settings

return settings


class ABFESolventSetupUnit(SolventComponentsMixin, SolventSettingsMixin, BaseAbsoluteSetupUnit):
"""
Setup unit for the solvent phase of absolute binding free energy
transformations.
"""

simtype = "solvent"


class ABFESolventSimUnit(
SolventComponentsMixin, SolventSettingsMixin, BaseAbsoluteMultiStateSimulationUnit
):
"""
Multi-state simulation (e.g. multi replica methods like Hamiltonian
replica exchange) unit for the solvent phase of absolute binding
free energy transformations.
"""

simtype = "solvent"


class ABFESolventAnalysisUnit(SolventSettingsMixin, BaseAbsoluteMultiStateAnalysisUnit):
"""
Analysis unit for multi-state simulations with the solvent phase
of absolute binding free energy transformations.
"""

simtype = "solvent"
12 changes: 8 additions & 4 deletions openfe/protocols/openmm_afe/afe_protocol_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ def get_replica_state(nc, chk):
for key in [self.bound_state, self.unbound_state]:
for pus in self.data[key].values(): # type: ignore[attr-defined]
states = get_replica_state(
pus[0].outputs["nc"],
pus[0].outputs["last_checkpoint"],
pus[0].outputs["trajectory"],
pus[0].outputs["checkpoint"],
)
replica_states[key].append(states)

Expand Down Expand Up @@ -295,7 +295,9 @@ def selection_indices(self) -> dict[str, list[Optional[npt.NDArray]]]:


class AbsoluteSolvationProtocolResult(gufe.ProtocolResult, AbsoluteProtocolResultMixin):
"""Dict-like container for the output of a AbsoluteSolvationProtocol"""
"""
Protocol results with the output of a AbsoluteSolvationProtocol
"""

bound_state = "solvent"
unbound_state = "vacuum"
Expand Down Expand Up @@ -375,7 +377,9 @@ def _get_stdev(estimates):


class AbsoluteBindingProtocolResult(gufe.ProtocolResult, AbsoluteProtocolResultMixin):
"""Dict-like container for the output of a AbsoluteBindingProtocol"""
"""
Protocol results with the output of a AbsoluteBindingProtocol.
"""

bound_state = "complex"
unbound_state = "solvent"
Expand Down
Loading
Loading