Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
4bd1066
fix(classical): fix import relationship
WangXinyan940 Mar 1, 2022
c3916bc
Update
WangXinyan940 Mar 1, 2022
12012ba
feat(classical): make HarmonicBond and HarmonicAngle the same as GAFF
WangXinyan940 Mar 2, 2022
356a2e5
feat(classical): Support torsion force
WangXinyan940 Mar 6, 2022
906bd27
fix(classical): use two attributes to save proper/improper dihedral s…
WangXinyan940 Mar 6, 2022
ac5b212
fix(classical): Jax the parameters when creating forces
WangXinyan940 Mar 6, 2022
dfb81ee
fix(classical): fix a typo
WangXinyan940 Mar 6, 2022
e463ac7
fix(classical): use ndarray to save indexes
WangXinyan940 Mar 6, 2022
971f7bc
fix(classical): return sum of energies for torsion
WangXinyan940 Mar 6, 2022
cbd6f4c
feat(classical): support 4th order for torsion
WangXinyan940 Mar 6, 2022
7180f34
feat(classical): Add UT for classical forcefields
WangXinyan940 Mar 7, 2022
e900404
fix(classical): Update PDB structures needed by test cases
WangXinyan940 Mar 7, 2022
3d4604e
fix(classical): Change atomtypes to be consistent with residues
WangXinyan940 Mar 7, 2022
dc71b5d
feat(classical): add reference energies for test cases
WangXinyan940 Mar 7, 2022
9388bb9
fix(classical): decrease the decimal for energy comparision
WangXinyan940 Mar 7, 2022
a06501c
feat(classical): Use the same way of openmm for dihedral typification
WangXinyan940 Mar 7, 2022
53afbd2
fix(classical): remove unused import
WangXinyan940 Mar 7, 2022
8b31953
fix(classical): add order for impropers
WangXinyan940 Mar 7, 2022
17bc59f
fix(classical): use ndarray instead of list for index saving
WangXinyan940 Mar 7, 2022
f87f21d
fix(classical): Add import element
WangXinyan940 Mar 7, 2022
fb34251
fix(classical): fix misusing between torsion.periodicity and torsion.…
WangXinyan940 Mar 7, 2022
0e37099
fix(classical): misusing between periodicity and phase
WangXinyan940 Mar 7, 2022
0f97ba5
fix(classical): Correct bond connection in unit test pdb files
WangXinyan940 Mar 7, 2022
8e0159d
Fix pdb files in unittest
WangXinyan940 Mar 7, 2022
1ec8035
Update proper1.pdb
WangXinyan940 Mar 7, 2022
1a476b3
feat(classical): update reference energy for improper test
WangXinyan940 Mar 7, 2022
827f384
Update api.py
WangXinyan940 Mar 7, 2022
9984974
feat(classical): Add wildcard testcase for improper
WangXinyan940 Mar 7, 2022
8c480a4
Merge pull request #2 from Roy-Kid/devel
WangXinyan940 Mar 7, 2022
4d69d61
Merge pull request #2 from WangXinyan940/devel
Roy-Kid Mar 7, 2022
1173882
Merge branch 'devel' of github.com:Roy-Kid/DMFF into devel
Mar 7, 2022
c6bfede
set up LennardJones framework
Mar 8, 2022
8535aed
feat(classical): Add test case for multiple dihedrals in one molecule
WangXinyan940 Mar 10, 2022
78dce12
fix(classical): change the way of dihedral calculation
WangXinyan940 Mar 10, 2022
f7b45d9
Merge pull request #3 from WangXinyan940/devel
Roy-Kid Mar 10, 2022
53db236
Merge pull request #3 from Roy-Kid/devel
WangXinyan940 Mar 10, 2022
8cafed0
start to write LJ potential
Mar 11, 2022
58dd46a
Merge branch 'devel' of github.com:Roy-Kid/DMFF into devel
Mar 11, 2022
bd01946
fix conflict with kuang
Mar 11, 2022
3c0fc22
Merge pull request #5 from Roy-Kid/devel
WangXinyan940 Mar 11, 2022
76228c4
feat(classical): Implement 12-6 potential without exclusion
WangXinyan940 Mar 13, 2022
b24f0a7
feat(classical): Add exclusion pairs for LJ force
WangXinyan940 Mar 13, 2022
5be3af1
feat(classical): add simple test for LennardJonesForce
WangXinyan940 Mar 13, 2022
47336ba
fix(classical): fix imp of nbfix
WangXinyan940 Mar 13, 2022
a36f3b9
fix(classical): use more reasonable test case
WangXinyan940 Mar 13, 2022
b88519e
fix(classical): add reference energy
WangXinyan940 Mar 13, 2022
70756cd
Merge pull request #4 from WangXinyan940/devel
Roy-Kid Mar 13, 2022
cb2f177
draft for dev lj potential
Mar 13, 2022
aa92a1e
Merge branch 'devel' of github.com:Roy-Kid/DMFF into devel
Mar 13, 2022
6044b9e
fix Zonly typo in api.py:332 which not consistent with line 475
Mar 13, 2022
e4aa292
reduce PME force to point charge calculation
Mar 13, 2022
d4e45b2
get a preliminary result of point charge pme caclulation
Mar 16, 2022
9802546
Merge pull request #6 from Roy-Kid/devel
WangXinyan940 Mar 17, 2022
c36db90
feat(classical): support loading charge from residue card and Nonbond…
WangXinyan940 Mar 19, 2022
e8cd925
correct gradient of coul
Mar 19, 2022
3c02a0e
Merge pull request #5 from WangXinyan940/devel
Roy-Kid Mar 19, 2022
dfe9db4
Merge branch 'devel' of github.com:Roy-Kid/DMFF into devel
Mar 19, 2022
60bd78b
Merge pull request #7 from Roy-Kid/devel
WangXinyan940 Mar 20, 2022
9c75220
feat(classical): Add setting for force switching
WangXinyan940 Mar 20, 2022
43a0d7e
feat(classical): Add noPBC support on LJ potential
WangXinyan940 Mar 20, 2022
e682f25
Merge pull request #6 from WangXinyan940/devel
WangXinyan940 Mar 20, 2022
5c3cb0c
review api.py code
Mar 20, 2022
0a4633d
add covalent_map support in lj and coul
Mar 20, 2022
76526c8
feat(classical): Use covalent map to generate exclusions
WangXinyan940 Mar 20, 2022
526dd17
feat(classical): Call LJ in API
WangXinyan940 Mar 20, 2022
e828858
Merge pull request #7 from WangXinyan940/devel
WangXinyan940 Mar 20, 2022
c4af1ec
Merge branch 'devel' of github.com:Roy-Kid/DMFF into devel
Mar 21, 2022
b96f4f2
fix(classical): bug fix on misusing list and jnp.array
WangXinyan940 Mar 21, 2022
b3baf1a
fix(classical): correctly support NoCutoff
WangXinyan940 Mar 21, 2022
2cdef5c
Merge pull request #8 from WangXinyan940/devel
WangXinyan940 Mar 21, 2022
5648706
fix(classical): fix misusing variables
WangXinyan940 Mar 21, 2022
85d04ba
feat(classical): add a testcase for two LJ molecules
WangXinyan940 Mar 21, 2022
c11b493
fix(classical): correct setting of LJ case
WangXinyan940 Mar 21, 2022
6df767f
feat(classical): add a testcase for large molecule (including 1-4) in…
WangXinyan940 Mar 21, 2022
dac3b8a
feat(classical): Add support for reaction-field and no-cutoff in Coul…
WangXinyan940 Mar 27, 2022
075b615
feat(classical): Support more Coulomb potentials (#9)
WangXinyan940 Mar 27, 2022
6eed9e7
imporve colvalent_map support
Mar 27, 2022
fa20c0e
add coulombforce support in api.py
Mar 27, 2022
be425d6
Merge branch 'devel' into devel
WangXinyan940 Mar 27, 2022
ed1d47f
Update PME code (#8)
WangXinyan940 Mar 27, 2022
19ecdbb
feat(classical): add testcases for NoCutoff Coulomb potential and a l…
WangXinyan940 Mar 27, 2022
abda90f
feat(classical): Support differentiable 1-4 scale
WangXinyan940 Mar 27, 2022
d46576e
Merge branch 'devel' into devel
WangXinyan940 Mar 27, 2022
9baf1a6
Devel (#9)
WangXinyan940 Mar 28, 2022
42eb719
feat(classical): add more GAFF2 test cases.
WangXinyan940 Mar 28, 2022
82ead47
fix(classical): remove unnecessary lines
WangXinyan940 Apr 1, 2022
97055e1
Differentiable classical force field support (#12) (#10)
WangXinyan940 Apr 11, 2022
22321d4
fix(classical): use another way to calc exclusion to increase precision
WangXinyan940 Apr 11, 2022
790e6b0
fix(classical): typo
WangXinyan940 Apr 11, 2022
a491217
fix(classical): bug fix on 14scale
WangXinyan940 Apr 11, 2022
2934358
Update inter.py
WangXinyan940 Apr 11, 2022
528bcec
Update inter.py
WangXinyan940 Apr 11, 2022
77ecfc5
feat(classical): Use more robust 1-4 scale method
WangXinyan940 Apr 11, 2022
423fa0d
feat(render): initialize render method
WangXinyan940 Apr 11, 2022
33691fd
Merge remote-tracking branch 'upstream/devel' into devel
WangXinyan940 Apr 11, 2022
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
122 changes: 87 additions & 35 deletions dmff/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import numpy as np
import jax.numpy as jnp
from collections import defaultdict
import xml.etree.ElementTree as ET
from .admp.disp_pme import ADMPDispPmeForce
from .admp.multipole import convert_cart2harm, rot_local2global
from .admp.pairwise import TT_damping_qq_c6_kernel, generate_pairwise_interaction
Expand All @@ -31,6 +32,39 @@
import sys


class XMLNodeInfo:

class XMLElementInfo:

def __init__(self, name):
self.name = name
self.attributes = {}

def addAttribute(self, key, value):
self.attributes[key] = value


def __init__(self, name):
self.name = name
self.attributes = {}
self.elements = []


def addAttribute(self, key, value):
self.attributes[key] = value


def addElement(self, name, info):
element = self.XMLElementInfo(name)
for k, v in info.items():
element.addAttribute(k, v)
self.elements.append(element)


def modResidue(self, residue, atom, key, value):
pass


def get_line_context(file_path, line_number):
return linecache.getline(file_path, line_number).strip()

Expand All @@ -56,6 +90,15 @@ def build_covalent_map(data, max_neighbor):
return covalent_map


def findAtomTypeTexts(attribs, num):
typetxt = []
for n in range(1, num+1):
for key in ["type%i"%n, "class%i"%n]:
if key in attribs:
typetxt.append((key, attribs[key]))
break
return typetxt

class ADMPDispGenerator:
def __init__(self, hamiltonian):
self.ff = hamiltonian
Expand Down Expand Up @@ -630,10 +673,13 @@ def __init__(self, hamiltonian):
self.params = {"k": [], "length": []}
self._jaxPotential = None
self.types = []
self.typetexts = []

def registerBondType(self, bond):
typetxt = findAtomTypeTexts(bond, 2)
types = self.ff._findAtomTypes(bond, 2)
self.types.append(types)
self.typetexts.append(typetxt)
self.params["k"].append(float(bond["k"]))
self.params["length"].append(float(bond["length"])) # length := r0

Expand All @@ -647,10 +693,9 @@ def parseElement(element, hamiltonian):
<HarmonicBondForce>
<Bond type1="ow" type2="hw" length="0.09572000000000001" k="462750.3999999999"/>
<Bond type1="hw" type2="hw" length="0.15136000000000002" k="462750.3999999999"/>
<\HarminicBondForce>
<\HarmonicBondForce>

"""

generator = HarmonicBondJaxGenerator(hamiltonian)
hamiltonian.registerGenerator(generator)
for bondtype in element.findall("Bond"):
Expand Down Expand Up @@ -700,7 +745,18 @@ def getJaxPotential(self):

def renderXML(self):
# generate xml force field file
pass
finfo = XMLNodeInfo("HarmonicBondForce")
for ntype in range(len(self.types)):
binfo = {}
k1, v1 = self.typetexts[ntype][0]
k2, v2 = self.typetexts[ntype][1]
binfo[k1] = v1
binfo[k2] = v2
for key in self.params.keys():
binfo[key] = "%.8f"%self.params[key][ntype]
finfo.addElement("Bond", binfo)
return finfo



# register all parsers
Expand Down Expand Up @@ -1450,7 +1506,10 @@ def createForce(self, system, data, nonbondedMethod, nonbondedCutoff, args):
self.params[k] = jnp.array(self.params[k])

mscales_coul = jnp.array([0.0, 0.0, 0.0, 1.0, 1.0, 1.0]) # mscale for PME
mscales_coul = mscales_coul.at[2].set(1.0 - self.params["coulomb14scale"][0])
mscales_coul = mscales_coul.at[2].set(self.params["coulomb14scale"][0])
mscales_lj = jnp.array([0.0, 0.0, 0.0, 1.0, 1.0, 1.0]) # mscale for LJ
mscales_lj = mscales_lj.at[2].set(self.params["lj14scale"][0])


# Coulomb: only support PME for now
# set PBC
Expand Down Expand Up @@ -1505,29 +1564,6 @@ def createForce(self, system, data, nonbondedMethod, nonbondedCutoff, args):
map_nbfix = np.array(map_nbfix, dtype=int).reshape((-1, 2))

colv_map = build_covalent_map(data, 6)
map_exclusion = []
scale_14 = []
npair = 0
for ii in range(colv_map.shape[0]):
for jj in range(ii + 1, colv_map.shape[1]):
if colv_map[ii, jj] > 0 and colv_map[ii, jj] < 4:
map_exclusion.append((ii, jj))
if colv_map[ii, jj] == 3:
scale_14.append(npair)
npair += 1

map_exclusion = np.array(map_exclusion, dtype=int)
scale_14 = np.array(scale_14, dtype=int)
scale_lj_exclusion = np.ones((map_exclusion.shape[0],))
scale_coul_exclusion = np.ones((map_exclusion.shape[0],))
scale_lj_exclusion = jnp.array(scale_lj_exclusion)
scale_coul_exclusion = jnp.array(scale_coul_exclusion)
scale_lj_exclusion = scale_lj_exclusion.at[scale_14].set(
1.0 - self.params["lj14scale"][0]
)
scale_coul_exclusion = scale_coul_exclusion.at[scale_14].set(
1.0 - self.params["coulomb14scale"][0]
)

if unit.is_quantity(nonbondedCutoff):
r_cut = nonbondedCutoff.value_in_unit(unit.nanometer)
Expand All @@ -1549,8 +1585,7 @@ def createForce(self, system, data, nonbondedMethod, nonbondedCutoff, args):
r_cut,
map_lj,
map_nbfix,
map_exclusion,
scale_lj_exclusion,
colv_map,
isSwitch=ifSwitch,
isPBC=ifPBC,
isNoCut=isNoCut,
Expand All @@ -1561,14 +1596,10 @@ def createForce(self, system, data, nonbondedMethod, nonbondedCutoff, args):
# do not use PME
if nonbondedMethod in [app.CutoffPeriodic, app.CutoffNonPeriodic]:
# use Reaction Field
coulforce = CoulReactionFieldForce(
r_cut, map_charge, map_exclusion, scale_coul_exclusion, isPBC=ifPBC
)
coulforce = CoulReactionFieldForce(r_cut, map_charge, colv_map, isPBC=ifPBC)
if nonbondedMethod is app.NoCutoff:
# use NoCutoff
coulforce = CoulNoCutoffForce(
map_charge, map_exclusion, scale_coul_exclusion
)
coulforce = CoulNoCutoffForce(map_charge, colv_map)
else:
coulforce = CoulombPMEForce(box, r_cut, self.ethresh, colv_map)

Expand All @@ -1584,6 +1615,7 @@ def potential_fn(positions, box, pairs, params):
params["sigma"],
params["epsfix"],
params["sigfix"],
mscales_lj
)
coulE = coulenergy(positions, box, pairs, params["charge"], mscales_coul)

Expand All @@ -1604,6 +1636,9 @@ def renderXML(self):
class Hamiltonian(app.forcefield.ForceField):
def __init__(self, *xmlnames):
super().__init__(*xmlnames)
# add a function to parse AtomTypes and Residues information
self._atomtypes = None
self._residues = None
self._potentials = []

def createPotential(
Expand All @@ -1629,6 +1664,23 @@ def createPotential(
pass
return [p for p in self._potentials]

def render(self, filename):
root = ET.Element("ForceField")
forceInfos = [g.renderXML() for g in self._forces]
for finfo in forceInfos:
# create xml nodes
if finfo is not None:
node = ET.SubElement(root, finfo.name)
for key in finfo.attributes.keys():
node.set(key, finfo.attributes[key])
for elem in finfo.elements:
subnode = ET.SubElement(node, elem.name)
for key in elem.attributes.keys():
subnode.set(key, elem.attributes[key])

tree = ET.ElementTree(root)
tree.write(filename)


if __name__ == "__main__":
H = Hamiltonian("forcefield.xml")
Expand Down
87 changes: 28 additions & 59 deletions dmff/classical/inter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ def __init__(
r_cut,
map_prm,
map_nbfix,
map_exclusion,
scale_exclusion,
colvmap,
isSwitch=False,
isPBC=True,
isNoCut=False,
Expand All @@ -31,10 +30,9 @@ def __init__(

self.map_prm = map_prm
self.map_nbfix = map_nbfix
self.map_exclusion = map_exclusion
self.scale_exclusion = scale_exclusion
self.ifPBC = isPBC
self.ifNoCut = isNoCut
self.colvmap = colvmap

def generate_get_energy(self):
def get_LJ_energy(dr_vec, sig, eps, box):
Expand All @@ -60,7 +58,7 @@ def get_LJ_energy(dr_vec, sig, eps, box):

return E

def get_energy(positions, box, pairs, epsilon, sigma, epsfix, sigfix):
def get_energy(positions, box, pairs, epsilon, sigma, epsfix, sigfix, mscales):

eps_m1 = jnp.repeat(epsilon.reshape((-1, 1)), epsilon.shape[0], axis=1)
eps_m2 = eps_m1.T
Expand All @@ -74,42 +72,33 @@ def get_energy(positions, box, pairs, epsilon, sigma, epsfix, sigfix):
sig_mat = sig_mat.at[self.map_nbfix[:, 0], self.map_nbfix[:, 1]].set(sigfix)
sig_mat = sig_mat.at[self.map_nbfix[:, 1], self.map_nbfix[:, 0]].set(sigfix)

colv_pair = self.colvmap[pairs[:,0],pairs[:,1]]
mscale_pair = mscales[colv_pair-1] # in mscale vector, the 0th item is 1-2 scale, the 1st item is 1-3 scale, etc...


dr_vec = positions[pairs[:, 0]] - positions[pairs[:, 1]]
prm_pair0 = self.map_prm[pairs[:, 0]]
prm_pair1 = self.map_prm[pairs[:, 1]]
eps = eps_mat[prm_pair0, prm_pair1]
sig = sig_mat[prm_pair0, prm_pair1]

E_inter = get_LJ_energy(dr_vec, sig, eps, box)

# exclusion
dr_excl_vec = (
positions[self.map_exclusion[:, 0]]
- positions[self.map_exclusion[:, 1]]
)
excl_map0 = self.map_prm[self.map_exclusion[:, 0]]
excl_map1 = self.map_prm[self.map_exclusion[:, 1]]
eps_excl = eps_mat[excl_map0, excl_map1]
sig_excl = sig_mat[excl_map0, excl_map1]
eps_scale = eps * mscale_pair

E_excl = get_LJ_energy(dr_excl_vec, sig_excl, eps_excl, box)
E_excl = self.scale_exclusion * E_excl
E_inter = get_LJ_energy(dr_vec, sig, eps_scale, box)

return jnp.sum(E_inter) - jnp.sum(E_excl)
#return jnp.sum(E_inter)
return jnp.sum(E_inter)

return get_energy


class CoulNoCutoffForce:
# E=\frac{{q}_{1}{q}_{2}}{4\pi\epsilon_0\epsilon_1 r}

def __init__(self, map_prm, map_exclusion, scale_exclusion, epsilon_1=1.0) -> None:
def __init__(self, map_prm, colvmap, epsilon_1=1.0) -> None:

self.eps_1 = epsilon_1
self.map_prm = map_prm
self.map_exclusion = map_exclusion
self.scale_exclusion = scale_exclusion
self.colvmap = colvmap

def generate_get_energy(self):
def get_coul_energy(dr_vec, chrgprod, box):
Expand All @@ -121,30 +110,21 @@ def get_coul_energy(dr_vec, chrgprod, box):
return E

def get_energy(positions, box, pairs, charges, mscales):

colv_pair = self.colvmap[pairs[:,0],pairs[:,1]]
mscale_pair = mscales[colv_pair-1]

chrg_map0 = self.map_prm[pairs[:, 0]]
chrg_map1 = self.map_prm[pairs[:, 1]]
charge0 = charges[chrg_map0]
charge1 = charges[chrg_map1]
chrgprod = charge0 * charge1
chrgprod_scale = chrgprod * mscale_pair
dr_vec = positions[pairs[:, 0]] - positions[pairs[:, 1]]

E_inter = get_coul_energy(dr_vec, chrgprod, box)

# exclusion
dr_excl_vec = (
positions[self.map_exclusion[:, 0]]
- positions[self.map_exclusion[:, 1]]
)
excl_map0 = self.map_prm[self.map_exclusion[:, 0]]
excl_map1 = self.map_prm[self.map_exclusion[:, 1]]
chrg0_excl = charges[excl_map0]
chrg1_excl = charges[excl_map1]
chrgprod_excl = chrg0_excl * chrg1_excl
E_inter = get_coul_energy(dr_vec, chrgprod_scale, box)

E_excl = get_coul_energy(dr_excl_vec, chrgprod_excl, box)
E_excl = self.scale_exclusion * E_excl

return jnp.sum(E_inter) - jnp.sum(E_excl)
return jnp.sum(E_inter)

return get_energy

Expand All @@ -155,8 +135,7 @@ def __init__(
self,
r_cut,
map_prm,
map_exclusion,
scale_exclusion,
colvmap,
epsilon_1=1.0,
epsilon_solv=78.5,
isPBC=True,
Expand All @@ -168,8 +147,7 @@ def __init__(
self.exp_solv = epsilon_solv
self.eps_1 = epsilon_1
self.map_prm = map_prm
self.map_exclusion = map_exclusion
self.scale_exclusion = scale_exclusion
self.colvmap = colvmap
self.ifPBC = isPBC

def generate_get_energy(self):
Expand All @@ -191,30 +169,21 @@ def get_rf_energy(dr_vec, chrgprod, box):
return E

def get_energy(positions, box, pairs, charges, mscales):

colv_pair = self.colvmap[pairs[:,0],pairs[:,1]]
mscale_pair = mscales[colv_pair-1]

chrg_map0 = self.map_prm[pairs[:, 0]]
chrg_map1 = self.map_prm[pairs[:, 1]]
charge0 = charges[chrg_map0]
charge1 = charges[chrg_map1]
chrgprod = charge0 * charge1
chrgprod_scale = chrgprod * mscale_pair
dr_vec = positions[pairs[:, 0]] - positions[pairs[:, 1]]

E_inter = get_rf_energy(dr_vec, chrgprod, box)

# exclusion
dr_excl_vec = (
positions[self.map_exclusion[:, 0]]
- positions[self.map_exclusion[:, 1]]
)
excl_map0 = self.map_prm[self.map_exclusion[:, 0]]
excl_map1 = self.map_prm[self.map_exclusion[:, 1]]
chrg0_excl = charges[excl_map0]
chrg1_excl = charges[excl_map1]
chrgprod_excl = chrg0_excl * chrg1_excl

E_excl = get_rf_energy(dr_excl_vec, chrgprod_excl, box)
E_excl = self.scale_exclusion * E_excl
E_inter = get_rf_energy(dr_vec, chrgprod_scale, box)

return jnp.sum(E_inter) - jnp.sum(E_excl)
return jnp.sum(E_inter)

return get_energy

Expand Down
Loading