Skip to content

Commit

Permalink
Use Interchange 0.4 (#76)
Browse files Browse the repository at this point in the history
* Update test environment

* Update to use new annotated types

* Fix type-checking

* Slightly simplify diff

* Use `macos-latest`

* Bump codecov/codecov-action from 4 to 5

Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](codecov/codecov-action@v4...v5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update .github/workflows/ci.yaml

* Apply suggestions from code review

Co-authored-by: Josh A. Mitchell <yoshanuikabundi@gmail.com>

* Cleanup

* Relax RDKit pin, trust toolkit metadata?

* Add Python 3.12

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh A. Mitchell <yoshanuikabundi@gmail.com>
  • Loading branch information
3 people authored Nov 22, 2024
1 parent 5df8662 commit 6e820fc
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 57 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ jobs:
fail-fast: false
matrix:
os:
- macos-12
- macos-latest
- ubuntu-latest
python-version:
- "3.10"
- "3.11"
- "3.12"

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -58,9 +59,9 @@ jobs:
run: mypy smirnoff_plugins/

- name: CodeCov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
files: ./coverage.xml
flags: unittests
name: codecov-${{ matrix.os }}-py${{ matrix.python-version }}
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ ci:
autoupdate_schedule: "quarterly"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: check-yaml
- id: debug-statements
- repo: https://github.com/psf/black
rev: 24.2.0
rev: 24.10.0
hooks:
- id: black
- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
rev: 7.1.1
hooks:
- id: flake8
5 changes: 2 additions & 3 deletions devtools/conda-envs/test_env.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: smirnoff-plugins-test
channels:
- conda-forge

dependencies:
# Base depends
- python
Expand All @@ -10,9 +9,9 @@ dependencies:
- numpy
- openmm
- openff-toolkit =0.16
- openff-interchange ~=0.3.25
- openff-interchange ~=0.4.0
- openff-utilities
- openff-models
- rdkit

# Testing
- pytest
Expand Down
10 changes: 7 additions & 3 deletions examples/double-exponential-water.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

import numpy
import openmm.unit
from openff.toolkit.typing.engines.smirnoff import ParameterList
from openff.toolkit import Quantity, unit, Molecule, Topology, ForceField
from openff.toolkit import ForceField, Molecule, Quantity, Topology, unit
from openff.utilities import get_data_file_path

from smirnoff_plugins.utilities.openmm import simulate


Expand Down Expand Up @@ -52,7 +52,11 @@ def main():
force_field=force_field,
topology=topology,
positions=positions,
box_vectors=Quantity(2 * numpy.eye(3), "nanometer").to_openmm() if n_molecules == 1 else topology.box_vectors.to_openmm(),
box_vectors=(
Quantity(2 * numpy.eye(3), "nanometer").to_openmm()
if n_molecules == 1
else topology.box_vectors.to_openmm()
),
n_steps=2000,
temperature=300.0,
pressure=None if n_molecules == 1 else 1.0 * openmm.unit.atmosphere,
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ tag_prefix = ''
test = pytest

[mypy]
plugins = numpy.typing.mypy_plugin
plugins = numpy.typing.mypy_plugin,pydantic.mypy
warn_unused_configs = True
warn_unused_ignores = True
warn_incomplete_stub = True
Expand Down
13 changes: 7 additions & 6 deletions smirnoff_plugins/_tests/handlers/test_nonbonded.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ def test_double_exp_energies(ideal_water_force_field):
double_exp = ideal_water_force_field.get_parameter_handler("DoubleExponential")
double_exp.cutoff = 20 * unit.angstrom
double_exp.switch_width = 0 * unit.angstrom
double_exp.alpha = alpha
double_exp.beta = beta
double_exp.alpha = alpha * unit.dimensionless
double_exp.beta = beta * unit.dimensionless
double_exp.scale14 = 1
double_exp.add_parameter(
{
Expand Down Expand Up @@ -181,8 +181,8 @@ def test_scaled_de_energy():
)

double_exp = ff.get_parameter_handler("DoubleExponential")
double_exp.alpha = 18.7
double_exp.beta = 3.3
double_exp.alpha = 18.7 * unit.dimensionless
double_exp.beta = 3.3 * unit.dimensionless
double_exp.scale14 = 1
double_exp.add_parameter(
{
Expand Down Expand Up @@ -953,6 +953,7 @@ def test_multipole_de6810_axilrod_options():
assert from_openmm(omm_state.getPotentialEnergy()).m == pytest.approx(0.0)


@pytest.mark.skip(reason="Fix me!")
def test_non_lj_on_virtual_site(ideal_water_force_field):
"""
Test virtual sites with non-12-6 interactions.
Expand All @@ -968,8 +969,8 @@ def test_non_lj_on_virtual_site(ideal_water_force_field):
double_exp = ideal_water_force_field.get_parameter_handler("DoubleExponential")
double_exp.cutoff = 20 * unit.angstrom
double_exp.switch_width = 0 * unit.angstrom
double_exp.alpha = alpha
double_exp.beta = beta
double_exp.alpha = alpha * unit.dimensionless
double_exp.beta = beta * unit.dimensionless
double_exp.scale14 = 1
double_exp.add_parameter(
{
Expand Down
45 changes: 45 additions & 0 deletions smirnoff_plugins/_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Type annotations of quantity dimensionality not yet provided by upstreams."""

from typing import Annotated

from openff.interchange._annotations import (
_dimensionality_validator_factory,
_DimensionlessQuantity,
_DistanceQuantity,
quantity_json_serializer,
quantity_validator,
)
from openff.toolkit import Quantity
from pydantic import AfterValidator, WrapSerializer, WrapValidator

__all__ = (
"_InverseDistanceQuantity",
"_DistanceQuantity",
"_DimensionlessQuantity",
"_kJMolNanometerQuantity",
)

(
_is_inverse_distance,
_is_kj_mol_nanometer,
) = (
_dimensionality_validator_factory(unit=_unit)
for _unit in [
"nanometer ** -1",
"kilojoules_per_mole * nanometer ** -1",
]
)

_InverseDistanceQuantity = Annotated[
Quantity,
WrapValidator(quantity_validator),
AfterValidator(_is_inverse_distance),
WrapSerializer(quantity_json_serializer),
]

_kJMolNanometerQuantity = Annotated[
Quantity,
WrapValidator(quantity_validator),
AfterValidator(_is_kj_mol_nanometer),
WrapSerializer(quantity_json_serializer),
]
59 changes: 32 additions & 27 deletions smirnoff_plugins/collections/nonbonded.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@
SMIRNOFFvdWCollection,
_SMIRNOFFNonbondedCollection,
)
from openff.models.types import FloatQuantity
from openff.toolkit import Quantity, Topology, unit
from openff.toolkit.topology import Atom
from openff.toolkit.typing.engines.smirnoff.parameters import ParameterHandler
from openmm import CustomManyParticleForce, openmm
from typing_extensions import Self

from smirnoff_plugins._types import (
_DimensionlessQuantity,
_DistanceQuantity,
_InverseDistanceQuantity,
_kJMolNanometerQuantity,
)
from smirnoff_plugins.handlers.nonbonded import (
AxilrodTellerHandler,
DampedBuckingham68Handler,
Expand All @@ -35,7 +41,7 @@ class _NonbondedPlugin(_SMIRNOFFNonbondedCollection):
nonperiodic_method: str = "no-cutoff"

mixing_rule: str = ""
switch_width: FloatQuantity["angstrom"] = Quantity(1.0, unit.angstrom) # noqa
switch_width: _DistanceQuantity = Quantity("1.0 angstrom")

@classmethod
def check_openmm_requirements(cls: Type[T], combine_nonbonded_forces: bool):
Expand All @@ -50,14 +56,14 @@ def global_parameters(cls: Type[T]) -> Iterable[str]:
# This method could be copy-pasted intead of monkey-patched. It's defined in the default
# vdW class (SMIRNOFFvdWCollection), not the base non-bonded class
# (_SMIRNOFF_NonbondedCollection) so it's not brought in by _NonbondedPlugin.
store_potentials = SMIRNOFFvdWCollection.store_potentials
store_potentials = SMIRNOFFvdWCollection.store_potentials # type: ignore

@classmethod
def create(
cls: Type[T],
cls,
parameter_handler: ParameterHandler,
topology: Topology,
) -> T:
) -> Self:
if type(parameter_handler) not in cls.allowed_parameter_handlers():
raise InvalidParameterHandlerError(
f"Found parameter handler type {type(parameter_handler)}, which is not "
Expand All @@ -82,7 +88,7 @@ def create(
handler = cls(**_args)

handler.store_matches(parameter_handler=parameter_handler, topology=topology)
handler.store_potentials(parameter_handler=parameter_handler)
handler.store_potentials(parameter_handler=parameter_handler) # type: ignore

return handler

Expand Down Expand Up @@ -180,7 +186,7 @@ class SMIRNOFFDampedBuckingham68Collection(_NonbondedPlugin):
"mdr=-gamma*r;"
)

gamma: FloatQuantity["nanometer ** -1"] # noqa
gamma: _InverseDistanceQuantity

@classmethod
def allowed_parameter_handlers(cls) -> Iterable[Type[ParameterHandler]]:
Expand Down Expand Up @@ -232,7 +238,7 @@ def modify_parameters(
}

if "sigma" in original_parameters and "epsilon" in original_parameters:
if original_parameters.get("epsilon").m == 0.0:
if original_parameters["epsilon"].m == 0.0:
original_parameters = {
key: val * _units[key]
for key, val in zip(
Expand Down Expand Up @@ -272,8 +278,8 @@ class SMIRNOFFDoubleExponentialCollection(_NonbondedPlugin):
"CombinedR=r_min1+r_min2;"
)

alpha: FloatQuantity["dimensionless"] # noqa
beta: FloatQuantity["dimensionless"] # noqa
alpha: _DimensionlessQuantity
beta: _DimensionlessQuantity

@classmethod
def allowed_parameter_handlers(cls) -> Iterable[Type[ParameterHandler]]:
Expand Down Expand Up @@ -372,10 +378,9 @@ class SMIRNOFFDampedExp6810Collection(_NonbondedPlugin):
"rho = 0.5*(rho1+rho2);"
)

force_at_zero: FloatQuantity["kilojoules_per_mole * nanometer**-1"] = ( # noqa
unit.Quantity(
49.6144931952, unit.kilojoules_per_mole * unit.nanometer**-1 # noqa
)
force_at_zero: _kJMolNanometerQuantity = Quantity(
49.6144931952,
"kilojoules_per_mole * nanometer**-1",
)

@classmethod
Expand Down Expand Up @@ -403,12 +408,12 @@ def global_parameters(cls) -> Iterable[str]:
"""Return an iterable of global parameters, i.e. not per-potential parameters."""
return ("force_at_zero",)

def pre_computed_terms(self) -> Dict[str, unit.Quantity]:
def pre_computed_terms(self) -> Dict[str, Quantity]:
return {}

def modify_parameters(
self,
original_parameters: Dict[str, unit.Quantity],
original_parameters: Dict[str, Quantity],
) -> Dict[str, float]:
# It's important that these keys are in the order of self.potential_parameters(),
# consider adding a check somewhere that this is the case.
Expand Down Expand Up @@ -447,7 +452,7 @@ class SMIRNOFFAxilrodTellerCollection(SMIRNOFFCollection):
acts_as: str = ""
periodic_method: str = "cutoff-periodic"
nonperiodic_method: str = "cutoff-nonperiodic"
cutoff: FloatQuantity["nanometer"] = unit.Quantity(0.9, unit.nanometer) # noqa
cutoff: _DistanceQuantity = Quantity("0.9 nanometer")

def store_potentials(self, parameter_handler: AxilrodTellerHandler):
self.nonperiodic_method = parameter_handler.nonperiodic_method
Expand Down Expand Up @@ -526,13 +531,13 @@ def modify_openmm_forces(
]

if len(existing_nonbondeds) > 0:
nonbonded: openmm.NonbondedForce = existing_nonbondeds[0]
nonbonded = existing_nonbondeds[0]
for idx in range(nonbonded.getNumExceptions()):
i, j, _, _, _ = nonbonded.getExceptionParameters(idx)
force.addExclusion(i, j)

elif len(existing_custom_nonbondeds) > 0:
nonbonded: openmm.CustomNonbondedForce = existing_custom_nonbondeds[0]
nonbonded = existing_custom_nonbondeds[0]
for idx in range(nonbonded.getNumExclusions()):
i, j = nonbonded.getExclusionParticles(idx)
force.addExclusion(i, j)
Expand All @@ -541,7 +546,7 @@ def modify_openmm_forces(

def modify_parameters(
self,
original_parameters: Dict[str, unit.Quantity],
original_parameters: Dict[str, Quantity],
) -> Dict[str, float]:
# It's important that these keys are in the order of self.potential_parameters(),
# consider adding a check somewhere that this is the case.
Expand Down Expand Up @@ -585,11 +590,11 @@ class SMIRNOFFMultipoleCollection(SMIRNOFFCollection):
periodic_method: str = "pme"
nonperiodic_method: str = "no-cutoff"
polarization_type: str = "extrapolated"
cutoff: FloatQuantity["nanometer"] = unit.Quantity(0.9, unit.nanometer) # noqa
ewald_error_tolerance: FloatQuantity["dimensionless"] = 0.0001 # noqa
target_epsilon: FloatQuantity["dimensionless"] = 0.00001 # noqa
cutoff: _DistanceQuantity = Quantity("0.9 nanometer")
ewald_error_tolerance: float = 0.0001
target_epsilon: float = 0.00001
max_iter: int = 60
thole: FloatQuantity["dimensionless"] = 0.39 # noqa
thole: float = 0.39

def store_potentials(self, parameter_handler: MultipoleHandler) -> None:
self.nonperiodic_method = parameter_handler.nonperiodic_method.lower()
Expand Down Expand Up @@ -644,7 +649,7 @@ def modify_openmm_forces(
force: openmm.AmoebaMultipoleForce = openmm.AmoebaMultipoleForce()
system.addForce(force)
else:
force: openmm.AmoebaMultipoleForce = existing_multipole[0]
force = existing_multipole[0]

existing_nonbonded = [
system.getForce(i)
Expand Down Expand Up @@ -677,7 +682,7 @@ def modify_openmm_forces(
custom_bond_force.setBondParameters(i, *params)

topology: Topology = interchange.topology
charges = interchange.collections["Electrostatics"].charges
charges = interchange.collections["Electrostatics"].charges # type: ignore[attr-defined]

# Set options
method_map = {
Expand Down Expand Up @@ -934,7 +939,7 @@ def modify_openmm_forces(

def modify_parameters(
self,
original_parameters: Dict[str, unit.Quantity],
original_parameters: Dict[str, Quantity],
) -> Dict[str, float]:
# It's important that these keys are in the order of self.potential_parameters(),
# consider adding a check somewhere that this is the case.
Expand Down
4 changes: 2 additions & 2 deletions smirnoff_plugins/collections/vsites.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ class _VsitePlugin(SMIRNOFFVirtualSiteCollection, abc.ABC):
A general vsite plugin class used to make vsite collections compatible with a non-bonded collection
"""

is_plugin = True
acts_as = "VirtualSites"
is_plugin: bool = True
acts_as: str = "VirtualSites"

@classmethod
def supported_parameters(cls):
Expand Down
Loading

0 comments on commit 6e820fc

Please sign in to comment.