Skip to content

Commit

Permalink
Update docstrings, run in CI (#240)
Browse files Browse the repository at this point in the history
* Update docstrings, run in CI

* Do not necessarily assume ff14SB port is installed

* Remove some references to `simtk`

$ grep -r simtk . | wc -l
       0

Co-authored-by: Mike Henry <[email protected]>
  • Loading branch information
mattwthompson and mikemhenry authored Oct 25, 2022
1 parent b12c2e8 commit d78f2b8
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 59 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ jobs:
working-directory: ./charmm

- name: Run docstrings
if: ${{ matrix.latest-openff-toolkit == true }}
continue-on-error: True
run: |
pytest --doctest-modules openmmforcefields --ignore=openmmforcefields/tests
- name: Upload coverage report to CodeCov
uses: codecov/[email protected]
if: ${{ github.repository == 'openmm/openmmforcefields'
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ If you're not familiar with this approach to applying parameters to biomolecular

### Using the AMBER force fields

Once installed, the AMBER force fields will be registered in the `amber/` relative path searched by [`simtk.openmm.app.ForceField`](http://docs.openmm.org/latest/api-python/generated/simtk.openmm.app.forcefield.ForceField.html#simtk.openmm.app.forcefield.ForceField).
Once installed, the AMBER force fields will be registered in the `amber/` relative path searched by [`openmm.app.ForceField`](http://docs.openmm.org/latest/api-python/generated/openmm.app.forcefield.ForceField.html#openmm.app.forcefield.ForceField).

For example, to specify the newer recommended [`ff14SB`](https://pubs.acs.org/doi/abs/10.1021/acs.jctc.5b00255) force field and accompanying recommended ions and solvent models (corresponding to force fields loaded in LEaP with `leaprc.protein.ff14SB`), prepend the `amber` prefix and the `.xml` suffix:
```python
Expand Down Expand Up @@ -67,7 +67,7 @@ forcefield = ForceField('charmm/toppar_all36_prot_model.xml')

## Using AMBER GAFF 1.x and 2.x for small molecules

The `openmmforcefields` package includes a [residue template generator](http://docs.openmm.org/latest/userguide/application.html#adding-residue-template-generators) for [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/simtk.openmm.app.forcefield.ForceField.html#simtk.openmm.app.forcefield.ForceField) that automatically generates OpenMM residue templates for small molecules lacking parameters using [GAFF](http://ambermd.org/antechamber/gaff.html) versions 1 or 2.
The `openmmforcefields` package includes a [residue template generator](http://docs.openmm.org/latest/userguide/application.html#adding-residue-template-generators) for [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/openmm.app.forcefield.ForceField.html#openmm.app.forcefield.ForceField) that automatically generates OpenMM residue templates for small molecules lacking parameters using [GAFF](http://ambermd.org/antechamber/gaff.html) versions 1 or 2.

### Cheminformatics toolkits

Expand All @@ -78,7 +78,7 @@ The OpenEye toolkit is available [for free for academics for non-IP-generating a
### On-the-fly template generation for small molecules

Generation of OpenMM-compatible parameters for small molecules encountered in an OpenMM `Topology` is handled through `openmmforcefields.generators.GAFFTemplateGenerator`.
Because the [OpenMM `Topology` object](http://docs.openmm.org/latest/api-python/generated/simtk.openmm.app.topology.Topology.html#simtk.openmm.app.topology.Topology) used by [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/simtk.openmm.app.forcefield.ForceField.html#simtk.openmm.app.forcefield.ForceField) does not know the precise chemical identity of molecules represented in the topology---which contain only elements and bonds between them, without stereochemical or bond order information---it is necessary to instruct `GAFFTemplateGenerator` which small molecules it will encounter in processing the `Topology` object ahead of time; it then matches these by element and bond pattern.
Because the [OpenMM `Topology` object](http://docs.openmm.org/latest/api-python/generated/openmm.app.topology.Topology.html#openmm.app.topology.Topology) used by [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/openmm.app.forcefield.ForceField.html#openmm.app.forcefield.ForceField) does not know the precise chemical identity of molecules represented in the topology---which contain only elements and bonds between them, without stereochemical or bond order information---it is necessary to instruct `GAFFTemplateGenerator` which small molecules it will encounter in processing the `Topology` object ahead of time; it then matches these by element and bond pattern.

### Specifying molecules

Expand Down Expand Up @@ -112,14 +112,14 @@ molecule = Molecule.from_smiles('c1ccccc1')
from openmmforcefields.generators import GAFFTemplateGenerator
gaff = GAFFTemplateGenerator(molecules=molecule)
# Create an OpenMM ForceField object with AMBER ff14SB and TIP3P with compatible ions
from simtk.openmm.app import ForceField
from openmm.app import ForceField
forcefield = ForceField('amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml')
# Register the GAFF template generator
forcefield.registerTemplateGenerator(gaff.generator)
# You can now parameterize an OpenMM Topology object that contains the specified molecule.
# forcefield will load the appropriate GAFF parameters when needed, and antechamber
# will be used to generate small molecule parameters on the fly.
from simtk.openmm.app import PDBFile
from openmm.app import PDBFile
pdbfile = PDBFile('t4-lysozyme-L99A-with-benzene.pdb')
system = forcefield.createSystem(pdbfile.topology)
```
Expand Down Expand Up @@ -152,7 +152,7 @@ Newly parameterized molecules will be written to the cache, saving time next tim

## Using the Open Force Field Initiative SMIRNOFF small molecule force fields

The `openmmforcefields` package includes a [residue template generator](http://docs.openmm.org/latest/userguide/application.html#adding-residue-template-generators) for [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/simtk.openmm.app.forcefield.ForceField.html#simtk.openmm.app.forcefield.ForceField) that automatically generates OpenMM residue templates for small molecules lacking parameters using the [Open Force Field Initiative](http://openforcefield.org) [SMIRNOFF](https://open-forcefield-toolkit.readthedocs.io/en/0.6.0/smirnoff.html) small molecule force fields.
The `openmmforcefields` package includes a [residue template generator](http://docs.openmm.org/latest/userguide/application.html#adding-residue-template-generators) for [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/openmm.app.forcefield.ForceField.html#openmm.app.forcefield.ForceField) that automatically generates OpenMM residue templates for small molecules lacking parameters using the [Open Force Field Initiative](http://openforcefield.org) [SMIRNOFF](https://open-forcefield-toolkit.readthedocs.io/en/0.6.0/smirnoff.html) small molecule force fields.
This includes the [`openff-1.0.0` ("Parsley")](https://openforcefield.org/news/introducing-openforcefield-1.0/) small molecule force field, as well as [newer versions of this force field](https://github.com/openforcefield/openff-forcefields).

The `SMIRNOFFTemplateGenerator` residue template generator operates in a manner very similar to `GAFFTemplateGenerator`, so we only highlight its differences here.
Expand All @@ -168,7 +168,7 @@ molecule = Molecule.from_smiles('c1ccccc1')
from openmmforcefields.generators import SMIRNOFFTemplateGenerator
smirnoff = SMIRNOFFTemplateGenerator(molecules=molecule)
# Create an OpenMM ForceField object with AMBER ff14SB and TIP3P with compatible ions
from simtk.openmm.app import ForceField
from openmm.app import ForceField
forcefield = ForceField('amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml')
# Register the SMIRNOFF template generator
forcefield.registerTemplateGenerator(smirnoff.generator)
Expand Down Expand Up @@ -210,7 +210,7 @@ Newly parameterized molecules will be written to the cache, saving time next tim

## Using espaloma to generate small molecule force fields

The `openmmforcefields` package includes a [residue template generator](http://docs.openmm.org/latest/userguide/application.html#adding-residue-template-generators) for [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/simtk.openmm.app.forcefield.ForceField.html#simtk.openmm.app.forcefield.ForceField) that can automatically generate OpenMM residue templates for small molecules lacking parameters using [espaloma](https://github.com/choderalab/espaloma) via one of its released force fields, provided `espaloma` and its dependencies are installed.
The `openmmforcefields` package includes a [residue template generator](http://docs.openmm.org/latest/userguide/application.html#adding-residue-template-generators) for [the OpenMM `ForceField` class](http://docs.openmm.org/latest/api-python/generated/openmm.app.forcefield.ForceField.html#openmm.app.forcefield.ForceField) that can automatically generate OpenMM residue templates for small molecules lacking parameters using [espaloma](https://github.com/choderalab/espaloma) via one of its released force fields, provided `espaloma` and its dependencies are installed.
`espaloma` uses a [graph convolutional model](https://arxiv.org/abs/2010.01196) to generate both valence parameters and fast partial charges.

The `EspalomaTemplateGenerator` residue template generator operates in a manner very similar to `GAFFTemplateGenerator`, so we only highlight its differences here.
Expand All @@ -228,7 +228,7 @@ molecule = Molecule.from_smiles('c1ccccc1')
from openmmforcefields.generators import EspalomaTemplateGenerator
espaloma = EspalomaTemplateGenerator(molecules=molecule, forcefield='espaloma-0.2.2')
# Create an OpenMM ForceField object with AMBER ff14SB and TIP3P with compatible ions
from simtk.openmm.app import ForceField
from openmm.app import ForceField
forcefield = ForceField('amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml')
# Register the SMIRNOFF template generator
forcefield.registerTemplateGenerator(espaloma.generator)
Expand Down Expand Up @@ -264,8 +264,8 @@ The `openmmforcefields` package provides the `openmmforcefields.generators.Syste
Here's an example that uses GAFF 2.11 along with the new `ff14SB` generation of AMBER force fields (and compatible solvent models) to generate an OpenMM `System` object from an [Open Force Field `Topology`](https://open-forcefield-toolkit.readthedocs.io/en/latest/api/generated/openff.toolkit.topology.Topology.html#openff.toolkit.topology.Topology) object:
```python
# Define the keyword arguments to feed to ForceField
from simtk import unit
from simtk.openmm import app
from openmm import unit
from openmm import app
forcefield_kwargs = { 'constraints' : app.HBonds, 'rigidWater' : True, 'removeCMMotion' : False, 'hydrogenMass' : 4*unit.amu }
# Initialize a SystemGenerator using GAFF
from openmmforcefields.generators import SystemGenerator
Expand All @@ -282,7 +282,7 @@ Parameters for multiple force fields can be held in the same cache file.
By default, `SystemGenerator` will use `PME` for periodic systems and `NoCutoff` for non-periodic systems.
You can modify this behavior with the optional `periodic_forcefield_kwargs` and `nonperiodic_forcefield_kwargs` arguments, which are used to update `forcefield_kwargs` depending on whether the system is periodic or non-periodic:
```python
from simtk.openmm import app
from openmm import app
system_generator = SystemGenerator(forcefields=['amber/ff14SB.xml', 'amber/tip3p_standard.xml'],
periodic_forcefield_kwargs={'nonbondedMethod' : app.LJPME},
nonperiodic_forcefield_kwargs={'nonbondedMethod' : app.CutoffNonPeriodic})
Expand Down
5 changes: 3 additions & 2 deletions charmm/energy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from __future__ import print_function
import sys
import parmed as pmd
from simtk import openmm as mm, unit as u
from simtk.openmm import app
import openmm as mm
from openmm import unit as u
from openmm import app
import numpy as np
import time
import os, re
Expand Down
18 changes: 9 additions & 9 deletions charmm/test_charmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from collections import OrderedDict
import hashlib
import os
import simtk.openmm.app as app
import simtk.openmm as mm
import simtk.unit as u
import openmm.app as app
import openmm as mm
import openmm.unit as u
import argparse
import csv
import logging
Expand Down Expand Up @@ -100,7 +100,7 @@ def write_serialized_system(filename, system):
----------
filename : str
The name of the file to be written
system : simtk.openmm.System
system : openmm.System
The System object to be written
"""
Expand Down Expand Up @@ -129,7 +129,7 @@ def read_box_vectors(filename):
Returns
-------
box_vectors : simtk.unit.Quantity with shape [3,3] and units of Angstroms
box_vectors : openmm.unit.Quantity with shape [3,3] and units of Angstroms
Box vectors
"""
with open(filename, 'r') as infile:
Expand Down Expand Up @@ -162,14 +162,14 @@ def compute_potential(system, positions):
Parameters
----------
system : simtk.openmm.System
system : openmm.System
System
positions : simtk.unit.Quantity of shape [nparticles,3] with units compatible with angstroms
positions : openmm.unit.Quantity of shape [nparticles,3] with units compatible with angstroms
Positions
Returns
-------
potential : simtk.unit.Quantity with units of kJ/mol
potential : openmm.unit.Quantity with units of kJ/mol
The potential energy
"""
Expand Down Expand Up @@ -202,7 +202,7 @@ def compare_energies(system_name, pdb_filename, psf_filename, ffxml_filenames, t
Keyword arguments to pass to CharmmPsfFile.createSystem() and ForceField.CreateSystem() when constructing System objects for energy comparison
tolerance : float, optional, default=1e-5
Relative energy discrepancy tolerance
units : simtk.unit.Unit
units : openmm.unit.Unit
Unit to use for energy comparison
write_serialized_xml : bool, optional, default=False
If True, will write out serialized System XML files for OpenMM systems to aid debugging.
Expand Down
9 changes: 7 additions & 2 deletions openmmforcefields/generators/system_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,22 @@ def __init__(self, forcefields=None, small_molecule_forcefield='openff-1.0.0', f
If the ``cache`` argument is specified, parameterized molecules are cached in the corresponding file.
>>> cache = 'db.json'
>>> system_generator = SystemGenerator(forcefields=forcefields, small_molecule_forcefield='gaff-2.11', forcefield_kwargs=forcefield_kwargs, cache=cache)
>>> system_generator = SystemGenerator(forcefields=amber_forcefields, small_molecule_forcefield='gaff-2.11', forcefield_kwargs=forcefield_kwargs, cache=cache) # doctest: +SKIP
To use a barostat, you need to define a barostat whose parameters will be copied into each system (with a different random number seed):
>>> import openmm
>>> from openmm import unit
>>> pressure = 1.0 * unit.atmospheres
>>> temperature = 298.0 * unit.kelvin
>>> frequency = 25 # steps
>>> system_generator.barostat = openmm.MonteCarloBarostat(pressure, temperature, frequency)
Now, you can create an OpenMM ``System`` object from an OpenMM ``Topology`` object and a list of OpenFF ``Molecule`` objects
>>> from openff.toolkit import Molecule, Topology
>>> molecules = [Molecule.from_smiles(smiles) for smiles in ["CCO", "c1ccccc1"]]
>>> openmm_topology = Topology.from_molecules(molecules).to_openmm()
>>> system = system_generator.create_system(openmm_topology, molecules=molecules)
Parameters for multiple force fields can be held in the same cache file.
Expand All @@ -145,7 +150,7 @@ def __init__(self, forcefields=None, small_molecule_forcefield='openff-1.0.0', f
simply change the ``small_molecule_forcefield`` parameter to one of the supported ``GAFFTemplateGenerator.INSTALLED_FORCEFIELDS``:
>>> small_molecule_forcefield = 'openff-1.0.0'
>>> system_generator = SystemGenerator(forcefields=forcefields, small_molecule_forcefield=small_molecule_forcefield, forcefield_kwargs=forcefield_kwargs)
>>> system_generator = SystemGenerator(forcefields=amber_forcefields, small_molecule_forcefield=small_molecule_forcefield, forcefield_kwargs=forcefield_kwargs)
For debugging convenience, you can also turn _off_ specific interactions during system creation, such as particle charges:
Expand Down
Loading

0 comments on commit d78f2b8

Please sign in to comment.