Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1a2e0fe
add more checks
atravitz Oct 10, 2025
6bc5904
make precommit manual
atravitz Oct 10, 2025
c10c9b0
apply formatting to pyproject.toml
atravitz Oct 10, 2025
5d33800
add TODO
atravitz Oct 10, 2025
2fd16d4
remove unneeded, add a few more
atravitz Oct 10, 2025
172cedf
add ruff, but turn everything off
atravitz Oct 10, 2025
4b259d9
add openfe known first party
atravitz Oct 10, 2025
c5a9cda
format highest-level files
atravitz Oct 21, 2025
7c402f3
first half of openfe protocols
atravitz Oct 21, 2025
dd10e03
second half of openfe protocols
atravitz Oct 22, 2025
b0a4966
openfe protocols formatting, with alyssa's fmt skips
atravitz Oct 22, 2025
5830ddc
add ruff formatter to precommit
atravitz Oct 22, 2025
8766819
fmt: off all vendored _rfe_utils code
atravitz Oct 22, 2025
73b4307
addressing review comments
atravitz Oct 22, 2025
2036dd3
Merge branch 'main' into ci/add-ruff-format
atravitz Oct 22, 2025
67ab0ab
Merge branch 'main' into ci/add-ruff-format
atravitz Oct 22, 2025
97fd543
format openfe/utils
atravitz Oct 22, 2025
517bf0d
format openfe/setup
atravitz Oct 22, 2025
fbf1645
first batch of cli formatting
atravitz Oct 22, 2025
8b937c2
second batch of cli formatting
atravitz Oct 22, 2025
bbac0b7
formatting the rest of openfecli commands
atravitz Oct 22, 2025
f74a648
format openfecli/parameters
atravitz Oct 22, 2025
dac8bbd
Merge branch 'main' of github.com:OpenFreeEnergy/openfe into ci/add-r…
atravitz Oct 22, 2025
fdbc1c8
format openfe/storage
atravitz Oct 22, 2025
f2adb83
run precommit
atravitz Oct 22, 2025
5c55920
Merge branch 'main' into ci/add-ruff-format-part2
atravitz Oct 24, 2025
cbb8b71
Update openfecli/commands/gather.py
atravitz Oct 24, 2025
f30d66c
update example notebooks branch for v1.7.0 docs changes (#1615)
atravitz Oct 24, 2025
219005e
remove colab button, point to updated example notebooks, reorg landin…
atravitz Oct 24, 2025
26571c9
Merge branch 'main' of github.com:OpenFreeEnergy/openfe into ci/add-r…
atravitz Oct 24, 2025
dce18fc
Merge branch 'main' into ci/add-ruff-format-part2
atravitz Oct 24, 2025
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
16 changes: 10 additions & 6 deletions openfe/setup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
# For details, see https://github.com/OpenFreeEnergy/openfe


from .atom_mapping import (LigandAtomMapping,
LigandAtomMapper,
LomapAtomMapper, lomap_scorers,
PersesAtomMapper, perses_scorers,
KartografAtomMapper,)
from .atom_mapping import (
LigandAtomMapping,
LigandAtomMapper,
LomapAtomMapper,
lomap_scorers,
PersesAtomMapper,
perses_scorers,
KartografAtomMapper,
)

from gufe import LigandNetwork
from . import ligand_network_planning

from .alchemical_network_planner import RHFEAlchemicalNetworkPlanner, RBFEAlchemicalNetworkPlanner
from .alchemical_network_planner import RHFEAlchemicalNetworkPlanner, RBFEAlchemicalNetworkPlanner
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
ChemicalSystem,
)
from gufe import (
SmallMoleculeComponent, ProteinComponent, SolventComponent,
SmallMoleculeComponent,
ProteinComponent,
SolventComponent,
LigandNetwork,
)
from openff.units import unit
Expand Down Expand Up @@ -41,16 +43,14 @@
}


class RelativeAlchemicalNetworkPlanner(
AbstractAlchemicalNetworkPlanner, abc.ABC
):
class RelativeAlchemicalNetworkPlanner(AbstractAlchemicalNetworkPlanner, abc.ABC):
_chemical_system_generator: AbstractChemicalSystemGenerator

def __init__(
self,
name: str = "easy_rfe_calculation", # TODO: remove 'easy'
mappers: Optional[Iterable[LigandAtomMapper]] = None,
mapping_scorer: Callable[[LigandAtomMapping], float] = default_lomap_score,
mapping_scorer: Callable[[LigandAtomMapping], float] = default_lomap_score,
ligand_network_planner: Callable = generate_minimal_spanning_network,
protocol: Optional[Protocol] = None,
):
Expand All @@ -72,27 +72,29 @@ def __init__(
FE graph, by default RelativeHybridTopologyProtocol( RelativeHybridTopologyProtocol._default_settings() )
"""
if protocol is None:
protocol = RelativeHybridTopologyProtocol(RelativeHybridTopologyProtocol.default_settings())
protocol = RelativeHybridTopologyProtocol(
RelativeHybridTopologyProtocol.default_settings()
)
if mappers is None:
mappers = [LomapAtomMapper(time=20,
threed=True,
max3d=1.0,
element_change=True,
shift=False,
)]
mappers = [
LomapAtomMapper(
time=20,
threed=True,
max3d=1.0,
element_change=True,
shift=False,
)
]

self.name = name
self._mappers = mappers
self._mapping_scorer = mapping_scorer
self._ligand_network_planner = ligand_network_planner
self._protocol = protocol
self._chemical_system_generator_type = PROTOCOL_GENERATOR[
protocol.__class__
]
self._chemical_system_generator_type = PROTOCOL_GENERATOR[protocol.__class__]

@abc.abstractmethod
def __call__(self, *args, **kwargs) -> AlchemicalNetwork:
... # -no-cov-
def __call__(self, *args, **kwargs) -> AlchemicalNetwork: ... # -no-cov-

@property
def mappers(self) -> Iterable[LigandAtomMapper]:
Expand All @@ -116,9 +118,7 @@ def chemical_system_generator_type(
) -> Type[AbstractChemicalSystemGenerator]:
return self._chemical_system_generator_type

def _construct_ligand_network(
self, ligands: Iterable[SmallMoleculeComponent]
) -> LigandNetwork:
def _construct_ligand_network(self, ligands: Iterable[SmallMoleculeComponent]) -> LigandNetwork:
ligand_network = self._ligand_network_planner(
ligands=ligands, mappers=self.mappers, scorer=self.mapping_scorer
)
Expand Down Expand Up @@ -166,13 +166,9 @@ def _build_transformations(
end_state_nodes.extend([stateA_env, stateB_env])

# Todo: make the code here more stable in future: Name doubling check
all_transformation_labels = list(
map(lambda x: x.name, transformation_edges)
)
all_transformation_labels = list(map(lambda x: x.name, transformation_edges))

if len(all_transformation_labels) != len(
set(all_transformation_labels)
):
if len(all_transformation_labels) != len(set(all_transformation_labels)):
raise ValueError(
"There were multiple transformations with the same edge label! This might lead to overwriting your files. \n labels: "
+ str(len(all_transformation_labels))
Expand Down Expand Up @@ -215,9 +211,7 @@ def _build_transformation(
if "vacuum" in transformation_name:
protocol_settings.forcefield_settings.nonbonded_method = "nocutoff"

transformation_protocol = transformation_protocol.__class__(
settings=protocol_settings
)
transformation_protocol = transformation_protocol.__class__(settings=protocol_settings)

return Transformation(
stateA=stateA,
Expand All @@ -241,7 +235,7 @@ def __init__(
self,
name: str = "rhfe",
mappers: Optional[Iterable[LigandAtomMapper]] = None,
mapping_scorer: Callable[[LigandAtomMapping], float] = default_lomap_score,
mapping_scorer: Callable[[LigandAtomMapping], float] = default_lomap_score,
ligand_network_planner: Callable = generate_minimal_spanning_network,
protocol: Optional[Protocol] = None,
):
Expand Down Expand Up @@ -278,7 +272,8 @@ def __call__(

# Prepare system generation
self._chemical_system_generator = self._chemical_system_generator_type(
solvent=solvent, do_vacuum=True,
solvent=solvent,
do_vacuum=True,
)

# Build transformations
Expand All @@ -299,11 +294,12 @@ class RBFEAlchemicalNetworkPlanner(RelativeAlchemicalNetworkPlanner):
network planning scheme, then call it on a collection of ligands, protein,
solvent, and co-factors to create the network.
"""

def __init__(
self,
name: str = "rbfe",
mappers: Optional[Iterable[LigandAtomMapper]] = None,
mapping_scorer: Callable[[LigandAtomMapping], float] = default_lomap_score,
mapping_scorer: Callable[[LigandAtomMapping], float] = default_lomap_score,
ligand_network_planner: Callable = generate_minimal_spanning_network,
protocol: Optional[Protocol] = None,
):
Expand Down Expand Up @@ -332,15 +328,16 @@ def _build_transformation(
if isinstance(transformation_protocol, RelativeHybridTopologyProtocol):
# adaptive transformation settings are only supported for RelativeHybridTopologyProtocol currently
protocol_settings = transformation_protocol._adaptive_settings(
stateA=stateA, stateB=stateB, mapping=ligand_mapping_edge, initial_settings=protocol_settings
stateA=stateA,
stateB=stateB,
mapping=ligand_mapping_edge,
initial_settings=protocol_settings,
)

if "vacuum" in transformation_name:
protocol_settings.nonbonded_method = "nocutoff"

transformation_protocol = transformation_protocol.__class__(
settings=protocol_settings
)
transformation_protocol = transformation_protocol.__class__(settings=protocol_settings)

return Transformation(
stateA=stateA,
Expand All @@ -350,7 +347,6 @@ def _build_transformation(
protocol=transformation_protocol,
)


def __call__(
self,
ligands: Iterable[SmallMoleculeComponent],
Expand Down Expand Up @@ -382,7 +378,9 @@ def __call__(

# Prepare system generation
self._chemical_system_generator = self._chemical_system_generator_type(
solvent=solvent, protein=protein, cofactors=cofactors,
solvent=solvent,
protein=protein,
cofactors=cofactors,
)

# Build transformations
Expand Down
16 changes: 10 additions & 6 deletions openfe/setup/atom_mapping/ligandatommapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ class LigandAtomMapper(gufe.AtomMapper):
Subclasses will typically implement the ``_mappings_generator`` method,
which returns an iterable of :class:`.LigandAtomMapping` suggestions.
"""

@abc.abstractmethod
def _mappings_generator(self,
componentA: SmallMoleculeComponent,
componentB: SmallMoleculeComponent
) -> Iterable[dict[int, int]]:
def _mappings_generator(
self,
componentA: SmallMoleculeComponent,
componentB: SmallMoleculeComponent,
) -> Iterable[dict[int, int]]:
"""
Suggest mapping options for the input molecules.

Expand All @@ -35,8 +37,10 @@ def _mappings_generator(self,
"""
...

def suggest_mappings(self, componentA: SmallMoleculeComponent,
componentB: SmallMoleculeComponent
def suggest_mappings(
self,
componentA: SmallMoleculeComponent,
componentB: SmallMoleculeComponent,
) -> Iterable[LigandAtomMapping]:
"""
Suggest :class:`.LigandAtomMapping` options for the input molecules.
Expand Down
1 change: 1 addition & 0 deletions openfe/setup/atom_mapping/lomap_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
The MCS class from Lomap shamelessly wrapped and used here to match our API.

"""

from lomap import LomapAtomMapper
1 change: 0 additions & 1 deletion openfe/setup/atom_mapping/lomap_scorers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,3 @@
transmuting_methyl_into_ring_score,
transmuting_ring_sizes_score,
) # looks like we gotta make it detailed for mypy and RTD

30 changes: 16 additions & 14 deletions openfe/setup/atom_mapping/perses_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@
from openff.units.openmm import to_openmm

from ...utils.silence_root_logging import silence_root_logging

try:
with silence_root_logging():
from perses.rjmc.atom_mapping import (
AtomMapper, InvalidMappingException
)
from perses.rjmc.atom_mapping import AtomMapper, InvalidMappingException
except ImportError:
pass # Don't throw error, will happen later
pass # Don't throw error, will happen later

from .ligandatommapper import LigandAtomMapper

Expand All @@ -35,10 +34,8 @@ def _to_dict(self) -> dict:
"allow_ring_breaking": self.allow_ring_breaking,
"preserve_chirality": self.preserve_chirality,
"use_positions": self.use_positions,
"coordinate_tolerance": self.coordinate_tolerance.m_as(
unit.angstrom
),
"_tolerance_unit": "angstrom"
"coordinate_tolerance": self.coordinate_tolerance.m_as(unit.angstrom),
"_tolerance_unit": "angstrom",
}

@classmethod
Expand All @@ -53,10 +50,13 @@ def _defaults(cls):
return {}

@requires_package("perses")
def __init__(self, allow_ring_breaking: bool = True,
preserve_chirality: bool = True,
use_positions: bool = True,
coordinate_tolerance: Quantity = 0.25 * unit.angstrom):
def __init__(
self,
allow_ring_breaking: bool = True,
preserve_chirality: bool = True,
use_positions: bool = True,
coordinate_tolerance: Quantity = 0.25 * unit.angstrom,
):
"""
Suggest atom mappings with the Perses atom mapper.

Expand Down Expand Up @@ -84,12 +84,14 @@ def _mappings_generator(self, componentA, componentB):
_atom_mapper = AtomMapper(
use_positions=self.use_positions,
coordinate_tolerance=to_openmm(self.coordinate_tolerance),
allow_ring_breaking=self.allow_ring_breaking)
allow_ring_breaking=self.allow_ring_breaking,
)

# Try generating a mapping
try:
_atom_mappings = _atom_mapper.get_all_mappings(
old_mol=componentA.to_openff(), new_mol=componentB.to_openff())
old_mol=componentA.to_openff(), new_mol=componentB.to_openff()
)
except InvalidMappingException:
return

Expand Down
Loading