Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ci:
files: ^pyproject.toml|openff|(^examples/((?!deprecated).)*$)|^docs|(^utilities/((?!deprecated).)*$)
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.9
rev: v0.15.10
hooks:
- id: ruff-format
- id: ruff-check
Expand Down
30 changes: 13 additions & 17 deletions openff/toolkit/typing/engines/smirnoff/forcefield.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from openff.interchange import Interchange

from openff.toolkit import Molecule
from openff.toolkit.topology.topology import Topology, ValenceDict
from openff.toolkit.topology.topology import ImproperDict, Topology, ValenceDict
from openff.toolkit.utils.base_wrapper import ToolkitWrapper
from openff.toolkit.utils.toolkit_registry import ToolkitRegistry

Expand Down Expand Up @@ -1228,47 +1228,42 @@ def create_interchange(
allow_nonintegral_charges=allow_nonintegral_charges,
)

def label_molecules(self, topology: "Topology") -> list[dict[str, "ValenceDict"]]:
def label_molecules(self, topology: "Topology") -> list[dict[str, Union[dict, "ValenceDict", "ImproperDict"]]]:
"""
Return labels for a list of molecules corresponding to parameters from this force field.
Return a list of labels storing parameters applied from each handler to each molecule in the topology.

For each molecule, a dictionary of force types is returned, and for each force type,
each force term is provided with the atoms involved, the parameter id assigned, and the corresponding SMIRKS.
For each molecule, there is a dictionary of mapping handler names (keys) to valence dicts (values,
type `ValenceDict`, `ImproperDict`, or `dict` depending on the handler). Each valence dict maps
tuples of atom indices (keys) to applied parameter types (values).

.. todo::
What is the most useful API for this method?

- Should we instead accept :class:`Molecule` objects as input and
individually return labels?
- Should we attach the labels to the :class:`Molecule` object?
- Or should we label all interactions in a :class:`Topology` instead
of just labeling its ``unique_molecules``?

Parameters
----------
topology
A Topology object containing one or more unique molecules to be labeled
A `Topology` object containing molecule(s) to be labeled

Returns
-------
molecule_labels
List of labels for unique molecules. Each entry in the list
corresponds to one unique molecule in the Topology and is a
dictionary keyed by force type, i.e., ``molecule_labels[0]
['HarmonicBondForce']`` gives details for the harmonic bond
parameters for the first molecule. Each element is a list of the
form: ``[ ( [ atom1, ..., atomN], parameter_id, SMIRKS), ... ]``.
List of labels for molecules. Each entry in the list corresponds to one molecule in the
`Topology` and is a dictionary mapping a handler name to a valence dict. Each valence
dict maps tuples of atom indices to applied parameter types.
"""
from openff.toolkit.typing.engines.smirnoff.parameters import VirtualSiteHandler

# Loop over molecules and label
molecule_labels = list()
molecule_labels: list[dict[str, dict | ValenceDict | ImproperDict]] = list()

# TODO: This was previously ... enumerate(topology.reference_molecules). It's currently
# unclear if this should be topology.unique_molecules instead, since that might be faster
# (if also modifying this to label _all_ duplicates of each unique molecule)
for molecule in topology.molecules:
current_molecule_labels = dict()
current_molecule_labels: dict[str, dict | ValenceDict | ImproperDict] = dict()
for tag, parameter_handler in self._parameter_handlers.items():
param_is_list = False

Expand Down Expand Up @@ -1300,6 +1295,7 @@ def label_molecules(self, topology: "Topology") -> list[dict[str, "ValenceDict"]
current_molecule_labels[tag] = parameter_matches

molecule_labels.append(current_molecule_labels)

return molecule_labels

def _get_parameter_handler_class(self, tagname: str) -> type[ParameterHandler]:
Expand Down
30 changes: 13 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ classifiers = [
"Programming Language :: Python :: 3.14",
"Topic :: Utilities",
]

dynamic = [ "version" ]
urls = { Homepage = "https://github.com/openforcefield/openff-toolkit" }

[tool.setuptools.packages.find]
include = [ 'openff.toolkit*' ]
[tool.setuptools]
packages.find.include = [ "openff.toolkit*" ]

[tool.ruff]
line-length = 119
exclude = [ "examples/deprecated/", "utilities/deprecated" ]

lint.select = [ "E", "F", "I", "NPY", "RUF", "UP", "W" ]
lint.ignore = [ "D105", "D107", "D200", "D203", "D212", "E721", "RUF012" ]
lint.per-file-ignores."docs/users/molecule_cookbook.ipynb" = [ "E402", "F821" ]
Expand All @@ -44,19 +42,6 @@ lint.isort.known-first-party = [ "openff.toolkit" ]
# https://docs.astral.sh/ruff/settings/#lint_isort_known-third-party
lint.isort.known-third-party = [ "openff.interchange", "openff.utilities", "openff.units" ]

[tool.coverage.run]
omit = [
"*/*/_tests/*",
]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"raise NotImplementedError",
"@overload",
]

[tool.mypy]
python_version = 3.12
plugins = "numpy.typing.mypy_plugin"
Expand Down Expand Up @@ -92,4 +77,15 @@ module = [
]
ignore_missing_imports = true

[tool.coverage]
run.omit = [
"*/*/_tests/*",
]
report.exclude_lines = [
"@overload",
"if TYPE_CHECKING:",
"pragma: no cover",
"raise NotImplementedError",
]

[tool.versioningit]