Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typing abstraction #9

Merged
merged 44 commits into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
8332c40
Add Potential class
mattwthompson May 12, 2020
f691154
Update Potential class
mattwthompson May 13, 2020
b6bfc77
Make barebones system class
mattwthompson May 15, 2020
414453e
Merge branch 'master' into potential-1
mattwthompson May 18, 2020
c88302a
Merge branch 'master' into potential-1
mattwthompson May 18, 2020
f70fb5e
Update conda env
mattwthompson May 18, 2020
9cee3db
Update test structure
mattwthompson May 21, 2020
e9acbb6
Make separate classes for parametrized and un-parametrized potentials
mattwthompson May 21, 2020
09554cd
Store expressions as strings
mattwthompson May 21, 2020
b875977
Validate parameters with sympy and update tests
mattwthompson May 21, 2020
9c8ae08
Let independent_variables be a string
mattwthompson May 21, 2020
2531561
Copy evaluator simtk->pint function from evaluator
mattwthompson May 21, 2020
c92003e
Merge branch 'potential-1' into system-1
mattwthompson May 22, 2020
157b366
Add some templates for a class API
mattwthompson May 27, 2020
4cf3013
Merge remote-tracking branch 'origin/potential-1' into system-1
mattwthompson May 27, 2020
480e3d5
Add some basic classes
mattwthompson May 27, 2020
e575f28
Add a prototype with example
mattwthompson May 29, 2020
4b3fcee
Merge branch 'master' into system-1
mattwthompson May 29, 2020
30667ea
More clearly distinguish between toolkit and system objects and add t…
mattwthompson May 29, 2020
1ed5b1e
Add toolkit dependency
mattwthompson May 29, 2020
a12b9ff
Test constructing directly from toolkit objects
mattwthompson May 29, 2020
69c9260
Don't assume toolkit >0.7.0
mattwthompson Jun 1, 2020
d45af88
Directly use toolit atom
mattwthompson Jun 1, 2020
cd7f2f2
Add SMIRKS attribute
mattwthompson Jun 2, 2020
78710aa
Move System ForceField to PotentialCollection
mattwthompson Jun 2, 2020
b31fce0
Merge branch 'master' into potential-1
mattwthompson Jun 2, 2020
4af5cda
Switch to directly using toolkit topology
mattwthompson Jun 4, 2020
f38542d
Update gitignore
mattwthompson Jun 4, 2020
9a9148d
Rebrand System.forcefield to System.potential_collection
mattwthompson Jun 4, 2020
1732ce4
Start typing module
mattwthompson Jun 4, 2020
3ebf3bf
Remove un-used NumPy dependency
mattwthompson Jun 4, 2020
a33279c
Remove classes that mimic toolkit objects
mattwthompson Jun 4, 2020
e1dfa4a
Move SMIRNOFF-specific things into its own submodule, subclassing thi…
mattwthompson Jun 4, 2020
c8ae196
Astract ForceField into ParameterCollection
mattwthompson Jun 5, 2020
fce9b9a
Lint, fix imports
mattwthompson Jun 5, 2020
d027ed8
Rename and move around functions, fix tests
mattwthompson Jun 5, 2020
ed5d91f
Add SMIRNOFF example
mattwthompson Jun 5, 2020
3befc4b
Use the right notebook
mattwthompson Jun 5, 2020
58b6f2d
Merge branch 'potential-1' into typing-abstraction
mattwthompson Jun 5, 2020
90f2717
Add bond parameter parsing and update examples
mattwthompson Jun 5, 2020
1387fa4
Merge branch 'master' into typing-abstraction
mattwthompson Jun 5, 2020
b64c696
Initialize dicts to empty dicts, not None
mattwthompson Jun 5, 2020
e96a2c9
Assorted fixes
mattwthompson Jun 5, 2020
555ef46
Add ethanol example showing off loading Parsely and inspecting bond p…
mattwthompson Jun 5, 2020
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
33 changes: 33 additions & 0 deletions scratch/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from system import System
from openforcefield.topology import Molecule, Topology
from openforcefield.typing.engines.smirnoff import ForceField


# Load Parsley and populate a dummy topology (ignoring positions for the moment)
openff_forcefield = ForceField('scratch/ar.offxml')

# Create OpenFF Molecule containing only one Argon atom
mol = Molecule.from_smiles('[#18]')
mol.generate_conformers(n_conformers=1)

# Generate an OpenFF Topology from 10 Argon "molecules"
openff_topology = Topology.from_molecules(10 * [mol])
#
# Construct an OpenFF System with the force field and topology
openff_system = System(
toolkit_topology=openff_topology,
toolkit_forcefield=openff_forcefield,
positions=None,
box=None
)

openff_system.populate_from_toolkit_data()

stuff_to_print = {
'openff_system.forcefield': openff_system.forcefield,
'openff_system.forcefield["n1"]': openff_system.forcefield['n1'],
'openff_system.forcefield["n1"].expression': openff_system.forcefield['n1'].expression,
'openff_system.forcefield["n1"].parameters': openff_system.forcefield['n1'].parameters,
}
for key, val in stuff_to_print.items():
print(f'Calling {key}:\n\treturns {val}\n')
88 changes: 75 additions & 13 deletions system/system.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from typing import Set
from typing import Iterable, Set

import numpy as np
from pydantic import BaseModel
from pydantic import BaseModel, validator
import pint

from openforcefield.typing.engines.smirnoff import ForceField as ToolkitForceField
from openforcefield.topology import Topology as ToolkitTopology
from openforcefield.topology.molecule import Atom as ToolkitAtom

from .potential import ParametrizedAnalyticalPotential as Potential
from .utils import simtk_to_pint


u = pint.UnitRegistry()
Expand All @@ -16,23 +18,35 @@
class Topology:

def __init__(self, toolkit_topology):
self._atoms = [Atom(atom.atomic_number) for atom in toolkit_topology.topology_atoms]

self.atoms = [Atom(atom.atomic_number) for atom in toolkit_topology.topology_atoms]

class ForceField:

types: Set[Potential]


class Atom:
class Atom(ToolkitAtom):

def __init__(self, atomic_number):
self._atomic_number = atomic_number
def __init__(self, atomic_number, atom_type=None):
super().__init__(
atomic_number=atomic_number,
formal_charge=0,
is_aromatic=False,
)
self._atom_type = atom_type

@property
def atomic_number(self):
return self._atomic_number

@property
def atom_type(self):
return self._atom_type

@atom_type.setter
def atom_type(self, potential):
self._atom_type = potential


class System(BaseModel):
"""The OpenFF System object."""
Expand All @@ -41,19 +55,67 @@ class System(BaseModel):
toolkit_topology: ToolkitTopology = None
topology: Topology = None
forcefield: ForceField = None
positions: Iterable = None
box: Iterable = None

def create_system_from_toolkit_stuff(self):
"""Construct a System from provided ForceField and Topology."""
self.box = [10, 10, 10] * u.nm

self.positions = np.random.random((self.topology.n_topology_atoms, 3)) * u.nm

@validator("*")
def dummy_validator(cls, val):
return val

class Config:
arbitrary_types_allowed = True

def to_file(self):
raise NotImplementedError()

def populate_from_toolkit_data(self):
"""Construct a System from provided ForceField and Topology."""
self.box = [10, 10, 10] * u.nm

self.positions = np.random.random((self.toolkit_topology.n_topology_atoms, 3)) * u.nm

self.topology = Topology(self.toolkit_topology)

self.forcefield = dict()

# Only doing on vdW for now
matches = self.toolkit_forcefield.get_parameter_handler('vdW').find_matches(self.toolkit_topology)


lj_map = {}

for atom_key, atom_match in matches.items():
atom_idx = atom_key[0]

lj_type = atom_match.parameter_type

if lj_type.sigma is None:
sigma = 2. * lj_type.rmin_half / (2.**(1. / 6.))
else:
sigma = lj_type.sigma
sigma = simtk_to_pint(sigma)
epsilon = simtk_to_pint(lj_type.epsilon)

potential = Potential(
name=lj_type.id,
expression='4*epsilon*((sigma/r)**12-(sigma/r)**6)',
independent_variables={'r'},
parameters={'sigma': sigma, 'epsilon': epsilon},
)

lj_map[atom_idx] = potential.name

self.forcefield[potential.name] = potential

for key, val in lj_map.items():
self.topology.atoms[key].atom_type = self.forcefield[val]


def from_file(self):
raise NotImplementedError()

def to_parmed(self):
raise NotImplementedError()

def to_openmm(self):
raise NotImplementedError()