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

Add workaround function for applying nbfixes #268

Merged
merged 4 commits into from
Oct 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 57 additions & 0 deletions foyer/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import numpy as np
import parmed as pmd
import pytest

from foyer import Forcefield
from foyer.tests.utils import get_fn
from foyer.utils.nbfixes import apply_nbfix


def test_apply_nbfix():
opls = Forcefield(name='oplsaa')
ethane = pmd.load_file(get_fn('ethane.mol2'), structure=True)
ethane = opls.apply(ethane)
ethane_tweaked = apply_nbfix(
struct=ethane,
atom_type1='opls_135',
atom_type2='opls_140',
sigma=0.4,
epsilon=50.0,
)

assert not ethane.has_NBFIX()
assert ethane_tweaked.has_NBFIX()

# 0.44898.... is rmin, which parmed uses internally in place of sigma
for atom in ethane_tweaked:
if atom.atom_type.name == 'opls_135':
assert np.allclose(
atom.atom_type.nbfix['opls_140'][:2],
[0.44898481932374923, 50.0]
)
elif atom.atom_type.name == 'opls_140':
assert np.allclose(
atom.atom_type.nbfix['opls_135'][:2],
[0.44898481932374923, 50.0]
)

def test_apply_nbfix_bad_atom_type():
opls = Forcefield(name='oplsaa')
ethane = pmd.load_file(get_fn('ethane.mol2'), structure=True)
ethane = opls.apply(ethane)
with pytest.raises(ValueError):
apply_nbfix(
struct=ethane,
atom_type1='opls__typo_135',
atom_type2='opls_140',
sigma=0.4,
epsilon=50.0,
)
with pytest.raises(ValueError):
apply_nbfix(
struct=ethane,
atom_type1='opls_135',
atom_type2='opls_141',
sigma=0.4,
epsilon=50.0,
)
45 changes: 45 additions & 0 deletions foyer/utils/nbfixes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from copy import deepcopy


def apply_nbfix(struct, atom_type1, atom_type2, sigma, epsilon):
"""Apply a single nbfix to a particular interaction.

Parameters
----------
struct : parmed.structure.Structure
The ParmEd structure to which this nbfix will be applied.
atom_type1 : str
The name of the first atom type in the nbfix pair
atom_type2 : str
The name of the second atom type in the nbfix pair
sigma : float
The sigma of the cross-interaction in kcal/mol
epsilon : float
The epsilon of the cross-interaction in Angstroms

Returns
-------
struct : parmed.structure.Structure
The input structure with the nbfix applied.
"""
struct_copy = deepcopy(struct)

atom_types = list({a.atom_type for a in struct_copy.atoms})
for atom_type in sorted(atom_types, key=lambda a: a.name):
if atom_type.name == atom_type1:
a1 = atom_type
if atom_type.name == atom_type2:
a2 = atom_type
try:
a1
a2
except:
raise ValueError('Atom types {} and {} not found '
'in structure.'.format(atom_type1, atom_type2))

# Calculate rmin from sigma because parmed uses it internally
rmin = sigma * 2 ** (1 / 6)
a1.add_nbfix(a2.name, rmin, epsilon)
a2.add_nbfix(a1.name, rmin, epsilon)

return struct_copy