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 all 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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ ENV/
.spyderproject
.spyproject

# PyCharm
.idea

# Rope project settings
.ropeproject

Expand All @@ -100,3 +103,5 @@ ENV/

# mypy
.mypy_cache/

scratch/
4 changes: 4 additions & 0 deletions devtools/conda-envs/test_env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ dependencies:
# Base depends
- python
- pip
- pydantic
- pint
- sympy

# Testing
- pytest
Expand All @@ -15,3 +18,4 @@ dependencies:
- sympy
- pint
- openmm
- openforcefield
3 changes: 3 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Examples

Jupyter notebooks demonstrating use cases
361 changes: 361 additions & 0 deletions examples/smirnoff_argon.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,361 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from openforcefield.typing.engines.smirnoff import ForceField\n",
"from openforcefield.topology.molecule import Molecule\n",
"from openforcefield.topology.topology import Topology\n",
"\n",
"from system.typing.smirnoff import build_smirnoff_map, build_smirnoff_collection\n",
"from system.collections import PotentialHandler, PotentialCollection\n",
"from system.system import System\n",
"from system.utils import get_test_file_path"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Load in a minimal SMIRNOFF forcefield and Argon topology\n",
"argon_ff = ForceField(get_test_file_path('ar.offxml'))\n",
"\n",
"mol = Molecule.from_smiles('[#18]')\n",
"mol.generate_conformers(n_conformers=1)\n",
"\n",
"argon_top = Topology.from_molecules(10 * [mol])"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'vdW': {(0,): '[#18:1]',\n",
" (1,): '[#18:1]',\n",
" (2,): '[#18:1]',\n",
" (3,): '[#18:1]',\n",
" (4,): '[#18:1]',\n",
" (5,): '[#18:1]',\n",
" (6,): '[#18:1]',\n",
" (7,): '[#18:1]',\n",
" (8,): '[#18:1]',\n",
" (9,): '[#18:1]'}}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Generate a mapping of topology slots and SMIRNOFF SMIRKS\n",
"smirks_map = build_smirnoff_map(forcefield=argon_ff, topology=argon_top)\n",
"# {\n",
"# handler_name1: {\n",
"# {\n",
"# slot1: SMIRKS1,\n",
"# slot2: SMIRKS2,\n",
"# slot3: SMIRKS3,\n",
"# ...,\n",
"# slotN: SMIRKSN,\n",
"# },\n",
"# handler_name2: { ... },\n",
"# handler_name3: { ... },\n",
"# ...\n",
"# handler_nameN: { ... },\n",
"# }\n",
"smirks_map"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"smirnoff_collection = build_smirnoff_collection(forcefield=argon_ff)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"argon_system = System(\n",
" potential_collection=smirnoff_collection,\n",
" topology=argon_top,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"openforcefield.topology.topology.Topology"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# The topology attribute simply stores the toolkit topology\n",
"type(argon_system.topology)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"system.collections.PotentialCollection"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# The potential_collection is effectively a force field for SMIRNOFF systems,\n",
"# but is more flexible for future typing schemes that are much less \"1:1\" than\n",
"# traiditional atom-typing or SMIRNOFF, which generally map 1 parameter to a slot\n",
"type(argon_system.potential_collection)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"dict_keys(['vdW'])"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# A PotentialCollection object stores \"types\" of potentials, i.e. one section for vdW,\n",
"# one section for bonds, etc. in order to separate parameters from instructions; defining\n",
"# a SMIRKS pattern and a slot is not sufficient instructions to apply the corresponding \n",
"# parameter. This system only has vdW, but this dict is intended to store other non-bonded\n",
"# terms, valence terms, wild cross-coupling terms, etc.\n",
"argon_system.potential_collection.handlers.keys()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\\[0.3\\ nanometer\\]"
],
"text/latex": [
"$0.3\\ \\mathrm{nanometer}$"
],
"text/plain": [
"0.3 <Unit('nanometer')>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# A PotentialCollection is more or less nested dictionaries, so you can drill down\n",
"# to find the value of a particular parameter in a potential, returning a \n",
"# unit-bearing quantity (via pint).\n",
"argon_system.potential_collection['vdW'].potentials['[#18:1]'].parameters['sigma']\n",
"# The path is convoluted, but goes something like this\n",
"# sys_name.potential_collection['vdW'].potentials[smirks].parameters['sigma']\n",
"# ^ ^ ^ ^\n",
"# | | | | \n",
"# | | | | \n",
"# | \"type\" (?) of potential | finally, the actual param\n",
"# | |\n",
"# system I care about SMIRKS key, mapping to a potential"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ParametrizedAnalyticalPotential(name='n1', smirks='[#18:1]', expression='4*epsilon*((sigma/r)**12-(sigma/r)**6)', independent_variables={'r'}, parameters={'sigma': <Quantity(0.3, 'nanometer')>, 'epsilon': <Quantity(0.1, 'kilojoule / mole')>})"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# There's other information included in each potential, notably the\n",
"# analytical expression of the potential and the SMIRKS\n",
"argon_system.potential_collection['vdW'].potentials['[#18:1]']"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{(0,): '[#18:1]',\n",
" (1,): '[#18:1]',\n",
" (2,): '[#18:1]',\n",
" (3,): '[#18:1]',\n",
" (4,): '[#18:1]',\n",
" (5,): '[#18:1]',\n",
" (6,): '[#18:1]',\n",
" (7,): '[#18:1]',\n",
" (8,): '[#18:1]',\n",
" (9,): '[#18:1]'}"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Going back to the smirks_map, which is a dictionary mapping \"slots\" to potentials\n",
"# In the simple case, this is just atom indicies : SMKIRKS\n",
"smirks_map['vdW']"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ParametrizedAnalyticalPotential(name='n1', smirks='[#18:1]', expression='4*epsilon*((sigma/r)**12-(sigma/r)**6)', independent_variables={'r'}, parameters={'sigma': <Quantity(0.3, 'nanometer')>, 'epsilon': <Quantity(0.1, 'kilojoule / mole')>})"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# The smirks_map and potential_collection can be used to look up potentials\n",
"# using the 'vdW' and SMIRKS as sufficient information\n",
"argon_system.potential_collection['vdW'][smirks_map['vdW'][(7,)]]"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'topology': <openforcefield.topology.topology.Topology at 0x11f658f50>,\n",
" 'potential_collection': {'handlers': {'vdW': {'name': 'vdW',\n",
" 'potentials': {'[#18:1]': {'name': 'n1',\n",
" 'smirks': '[#18:1]',\n",
" 'expression': '4*epsilon*((sigma/r)**12-(sigma/r)**6)',\n",
" 'independent_variables': {'r'},\n",
" 'parameters': {'sigma': 0.3 <Unit('nanometer')>,\n",
" 'epsilon': 0.1 <Unit('kilojoule / mole')>}}}}}},\n",
" 'positions': None,\n",
" 'box': None,\n",
" 'slots_map': None}"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Being built off of pydantic, we get a serializable representation for free,\n",
"# caveats being that some components are not actually serializable now\n",
"argon_system.dict()"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'name': 'n1',\n",
" 'smirks': '[#18:1]',\n",
" 'expression': '4*epsilon*((sigma/r)**12-(sigma/r)**6)',\n",
" 'independent_variables': {'r'},\n",
" 'parameters': {'sigma': 0.3 <Unit('nanometer')>,\n",
" 'epsilon': 0.1 <Unit('kilojoule / mole')>}}"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Being a nested dictionary, you could also grab a component and make that a dict\n",
"argon_system.potential_collection.handlers['vdW'].potentials['[#18:1]'].dict()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading