Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 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
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ StyleCopReport.xml
*.ilk
*.meta
*.iobj
*.ipdb
*.pgc
*.pgd
*.rsp
Expand Down Expand Up @@ -774,3 +775,4 @@ FodyWeavers.xsd

### VisualStudio Patch ###
# Additional files built by Visual Studio
.vscode/**
1,222 changes: 995 additions & 227 deletions dmff/api.py

Large diffs are not rendered by default.

333 changes: 330 additions & 3 deletions dmff/classical/inter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,332 @@
from dmff.admp.pairwise import distribute_scalar
import jax.numpy as jnp
from dmff.admp.pme import energy_pme, setup_ewald_parameters
from dmff.admp.recip import generate_pme_recip
from dmff.admp.spatial import v_pbc_shift
import numpy as np
import jax.numpy as jnp
from jax import grad
from dmff.admp.recip import generate_pme_recip, Ck_1
from dmff.admp.pme import DIELECTRIC

ONE_4PI_EPS0 = DIELECTRIC * 0.1


class LennardJonesForce:
pass
def __init__(
self,
r_switch,
r_cut,
map_prm,
map_nbfix,
map_exclusion,
scale_exclusion,
isSwitch=False,
isPBC=True,
isNoCut=False,
) -> None:
self.isSwitch = isSwitch
self.r_switch = r_switch
self.r_cut = r_cut

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

def generate_get_energy(self):
def get_LJ_energy(dr_vec, sig, eps, box):
if self.ifPBC:
dr_vec = v_pbc_shift(dr_vec, box, jnp.linalg.inv(box))
dr_norm = jnp.linalg.norm(dr_vec, axis=1)
if not self.ifNoCut:
sig = sig[dr_norm <= self.r_cut]
eps = eps[dr_norm <= self.r_cut]
dr_norm = dr_norm[dr_norm <= self.r_cut]

dr_inv = 1.0 / dr_norm
sig_dr = sig * dr_inv
sig_dr6 = jnp.power(sig_dr, 6)
sig_dr12 = jnp.power(sig_dr6, 2)
E = 4.0 * eps * (sig_dr12 - sig_dr6)

if self.isSwitch:

x = (dr_norm - self.r_switch) / (self.r_cut - self.r_switch)
S = 1 - 6. * x ** 5 + 15. * x ** 4 - 10. * x ** 3
jnp.where(dr_norm > self.r_switch, E, E * S)

return E

def get_energy(positions, box, pairs, epsilon, sigma, epsfix, sigfix):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like in the classical module, all positions/box are assumed to be in unit of nanometer. But in ADMP, all positions are assumed to be in Angstrom. We should discuss this unit conflicts...

Copy link
Member Author

@WangXinyan940 WangXinyan940 Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to input position/box in nm & kJ/mol in API, and then transfer to angstrom when creating potential function like this:

class ADMPDispGenerator:
    def createForce():
        def potential_fn(positions, box, pairs, params):
            position_ang = positions * 10.0 
            box_ang = box * 10.0
            E_sr = pot_fn_sr(
                position_ang, box_ang, pairs, mScales, a_list, b_list, q_list, c_list[0]
            )
            E_lr = pot_fn_lr(position_ang, box_ang, pairs, c_list.T, mScales)
            return E_sr - E_lr

Then we don't need to touch parameter preparing process.

Copy link
Collaborator

@KuangYu KuangYu Apr 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good.


eps_m1 = jnp.repeat(epsilon.reshape((-1, 1)), epsilon.shape[0], axis=1)
eps_m2 = eps_m1.T
eps_mat = jnp.sqrt(eps_m1 * eps_m2)
sig_m1 = jnp.repeat(sigma.reshape((-1, 1)), sigma.shape[0], axis=1)
sig_m2 = sig_m1.T
sig_mat = (sig_m1 + sig_m2) * 0.5

eps_mat = eps_mat.at[self.map_nbfix[:, 0], self.map_nbfix[:, 1]].set(epsfix)
eps_mat = eps_mat.at[self.map_nbfix[:, 1], self.map_nbfix[:, 0]].set(epsfix)
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)

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]

E_excl = get_LJ_energy(dr_excl_vec, sig_excl, eps_excl, box)
E_excl = self.scale_exclusion * E_excl

return jnp.sum(E_inter) - jnp.sum(E_excl)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may cause precision issues. The way in admp/pairwise.py might be better? Try to apply scaling factor directly on pairwise interactions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Making change now.

#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:

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

def generate_get_energy(self):
def get_coul_energy(dr_vec, chrgprod, box):
dr_norm = jnp.linalg.norm(dr_vec, axis=1)

dr_inv = 1.0 / dr_norm
E = chrgprod * ONE_4PI_EPS0 / self.eps_1 * dr_inv

return E

def get_energy(positions, box, pairs, charges, mscales):
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
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_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 get_energy


class CoulReactionFieldForce:
# E=\frac{{q}_{1}{q}_{2}}{4\pi\epsilon_0\epsilon_1}\left(\frac{1}{r}+{k}_{\mathit{rf}}{r}^{2}-{c}_{\mathit{rf}}\right)
def __init__(
self,
r_cut,
map_prm,
map_exclusion,
scale_exclusion,
epsilon_1=1.0,
epsilon_solv=78.5,
isPBC=True,
) -> None:

self.r_cut = r_cut
self.krf = (1.0 / r_cut ** 3) * (epsilon_solv - 1) / (2.0 * epsilon_solv + 1)
self.crf = (1.0 / r_cut) * 3.0 * epsilon_solv / (2.0 * epsilon_solv + 1)
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.ifPBC = isPBC

def generate_get_energy(self):
def get_rf_energy(dr_vec, chrgprod, box):
if self.ifPBC:
dr_vec = v_pbc_shift(dr_vec, box, jnp.linalg.inv(box))
dr_norm = jnp.linalg.norm(dr_vec, axis=1)
chrgprod = chrgprod[dr_norm <= self.r_cut]
dr_norm = dr_norm[dr_norm <= self.r_cut]

dr_inv = 1.0 / dr_norm
E = (
chrgprod
* ONE_4PI_EPS0
/ self.eps_1
* (dr_inv + self.krf * dr_norm * dr_norm - self.crf)
)

return E

def get_energy(positions, box, pairs, charges, mscales):
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
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

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

return get_energy


class CoulombPMEForce:
def __init__(self, box, rc, ethresh, covalent_map):

self.kappa, self.K1, self.K2, self.K3 = setup_ewald_parameters(rc, ethresh, box)

self.covalent_map = covalent_map
self.refresh_calculator()

def generate_get_energy(self):
def get_energy(positions, box, pairs, Q, mScales):

return energy_pme(
positions,
box,
pairs,
Q,
None,
None,
None,
mScales,
None,
None,
self.covalent_map,
None,
self.pme_recip,
self.kappa,
self.K1,
self.K2,
self.K3,
self.lmax,
False,
)

return get_energy

def refresh_calculator(self):

self.construct_local_frames = None
lmax = 0
self.pme_recip = generate_pme_recip(
Ck_1, self.kappa, False, self.pme_order, self.K1, self.K2, self.K3, lmax
)

self.get_energy = self.genreate_get_energy()

return


if __name__ == "__main__":

# atoms: 0, 1, 2, 3
# exclusion: 0 - 1, 2 - 3
# nbfix: 0 - 3 (3., 0.3)
positions = jnp.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 0, 1]], dtype=float)
p_ref = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 0, 1]], dtype=float)

box = jnp.array([[10, 0, 0], [0, 10, 0], [0, 0, 10]])

pairs = np.array([[0, 1], [0, 2], [1, 2], [1, 3], [2, 3]])
covalent_map = np.array(
[[0, 1, 1, 0], [1, 0, 1, 1], [1, 1, 0, 1], [0, 1, 1, 0]]
) # NOTE:not sure
pairs_ref = np.array([[0, 2], [0, 3], [1, 2], [1, 3]])

epsilon = jnp.array([1.0, 2.0])
sigma = jnp.array([0.5, 0.6])

map_prm = np.array([0, 0, 1, 1])
map_nbfix = np.array([[0, 3]])
epsfix = jnp.array([3.0])
sigfix = jnp.array([0.8])
map_exclusion = np.array([[0, 1], [2, 3]])
scale_exclusion = jnp.array([1.0, 1.0])
map_14 = np.array([[]])

lj = LennardJonesForce(0, 3, map_prm, map_nbfix, map_exclusion, scale_exclusion)
get_energy = lj.generate_get_energy()

E = get_energy(positions, box, pairs, epsilon, sigma, epsfix, sigfix)

# Eref
eps0 = epsilon[map_prm[pairs_ref[:, 0]]]
eps1 = epsilon[map_prm[pairs_ref[:, 1]]]
sig0 = sigma[map_prm[pairs_ref[:, 0]]]
sig1 = sigma[map_prm[pairs_ref[:, 1]]]

eps = np.sqrt(eps0 * eps1)
sig = (sig0 + sig1) / 2.0
p0 = p_ref[pairs_ref[:, 0]]
p1 = p_ref[pairs_ref[:, 1]]
dr_vec = p1 - p0
dr = np.sqrt(np.power(dr_vec, 2).sum(axis=1))
sig_dr = sig / dr
Eref = 4.0 * eps * (np.power(sig_dr, 12) - np.power(sig_dr, 6))
Eref = Eref.sum()
dr_fix = p_ref[0] - p_ref[3]
dr_fix = np.sqrt((dr_fix * dr_fix).sum())
Eref += 4.0 * 3.0 * ((0.3 / dr_fix) ** 12 - (0.3 / dr_fix) ** 6)

print(E, "vs", Eref)
F = grad(get_energy)(positions, box, pairs, epsilon, sigma, epsfix, sigfix)
print(F)

class CoulombForce:
pass
# test PME
rc = 4
ethresh = 1e-4
mScales = np.array([1.0, 1.0, 1.0])
Q = np.array([0.1, 0.1])
pme = CoulombPMEForce(box, rc, ethresh)
get_energy = pme.generate_get_energy()
E = get_energy(positions, box, pairs, Q, mScales)
Loading