Skip to content

Commit

Permalink
MM3CAP added
Browse files Browse the repository at this point in the history
  • Loading branch information
Ruben authored and Ruben committed Oct 12, 2018
1 parent 83c8ae1 commit efd8d52
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 4 deletions.
91 changes: 90 additions & 1 deletion yaff/pes/ext.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ __all__ = [
'neigh_dtype', 'nlist_status_init', 'nlist_build', 'nlist_status_finish',
'nlist_recompute', 'nlist_inc_r',
'Hammer', 'Switch3',
'scaling_dtype', 'PairPot', 'PairPotLJ', 'PairPotMM3', 'PairPotGrimme',
'scaling_dtype', 'PairPot', 'PairPotLJ', 'PairPotMM3', 'PairPotMM3CAP', 'PairPotGrimme',
'PairPotExpRep', 'PairPotQMDFFRep', 'PairPotLJCross', 'PairPotDampDisp',
'PairPotDisp68BJDamp', 'PairPotEI', 'PairPotEIDip', 'PairPotEiSlater1s1sCorr',
'PairPotEiSlater1sp1spCorr', 'PairPotOlpSlater1s1s','PairPotChargeTransferSlater1s1s',
Expand Down Expand Up @@ -869,6 +869,95 @@ cdef class PairPotMM3(PairPot):
onlypaulis = property(_get_onlypaulis)


cdef class PairPotMM3CAP(PairPot):
r'''The MM3 version of the Lennard-Jones pair potential
**Energy:**
.. math:: E_\text{MM3} = \sum_{i=1}^{N} \sum_{j=i+1}^{N} s_{ij} \epsilon_{ij} \left[
1.84\times10^{5} \exp\left(\frac{\sigma_{ij}}{d_{ij}}\right) - 2.25\left(\frac{\sigma_{ij}}{d_{ij}}\right)^6
\right]
with
.. math:: \epsilon_{ij} = \sqrt{\epsilon_i \epsilon_j}
.. math:: \sigma_{ij} = \frac{\sigma_i + \sigma_j}{2}
.. math:: s_{ij} = \text{the short-range scaling factor}
**Arguments:**
sigmas
An array with sigma parameters, one for each atom, shape (natom,)
epsilons
An array with epsilon parameters, one for each atom, shape (natom,)
onlypaulis
An array integers. When non-zero for both atoms in a pair, only the
repulsive wall is computed.
rcut
The cutoff radius
**Optional arguments:**
tr
The truncation scheme, an instance of a subclass of ``Truncation``.
When not given, no truncation is applied
'''
cdef np.ndarray _c_sigmas
cdef np.ndarray _c_epsilons
cdef np.ndarray _c_onlypaulis
name = 'mm3cap'

def __cinit__(self, np.ndarray[double, ndim=1] sigmas,
np.ndarray[double, ndim=1] epsilons,
np.ndarray[int, ndim=1] onlypaulis, double rcut,
Truncation tr=None):
assert sigmas.flags['C_CONTIGUOUS']
assert epsilons.flags['C_CONTIGUOUS']
assert onlypaulis.flags['C_CONTIGUOUS']
assert sigmas.shape[0] == epsilons.shape[0]
assert sigmas.shape[0] == onlypaulis.shape[0]
pair_pot.pair_pot_set_rcut(self._c_pair_pot, rcut)
self.set_truncation(tr)
pair_pot.pair_data_mm3cap_init(self._c_pair_pot, <double*>sigmas.data, <double*>epsilons.data, <int*>onlypaulis.data)
if not pair_pot.pair_pot_ready(self._c_pair_pot):
raise MemoryError()
self._c_sigmas = sigmas
self._c_epsilons = epsilons
self._c_onlypaulis = onlypaulis

def log(self):
'''Write some suitable post-initialization screen log'''
if log.do_high:
log.hline()
log(' Atom Sigma Epsilon OnlyPauli')
log.hline()
for i in range(self._c_sigmas.shape[0]):
log('%7i %s %s %i' % (i, log.length(self._c_sigmas[i]), log.energy(self._c_epsilons[i]), self._c_onlypaulis[i]))

def _get_sigmas(self):
'''The array with sigma parameters'''
return self._c_sigmas.view()

sigmas = property(_get_sigmas)

def _get_epsilons(self):
'''The array with epsilon parameters'''
return self._c_epsilons.view()

epsilons = property(_get_epsilons)

def _get_onlypaulis(self):
'''The array with the only-Pauli flag'''
return self._c_onlypaulis.view()

onlypaulis = property(_get_onlypaulis)


cdef class PairPotGrimme(PairPot):
cdef np.ndarray _c_r0
cdef np.ndarray _c_c6
Expand Down
2 changes: 1 addition & 1 deletion yaff/pes/ff.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

from yaff.log import log, timer
from yaff.pes.ext import compute_ewald_reci, compute_ewald_reci_dd, compute_ewald_corr, \
compute_ewald_corr_dd, PairPotEI, PairPotLJ, PairPotMM3, PairPotGrimme, compute_grid3d
compute_ewald_corr_dd, PairPotEI, PairPotLJ, PairPotMM3, PairPotMM3CAP, PairPotGrimme, compute_grid3d
from yaff.pes.dlist import DeltaList
from yaff.pes.iclist import InternalCoordinateList
from yaff.pes.vlist import ValenceList
Expand Down
42 changes: 40 additions & 2 deletions yaff/pes/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from itertools import permutations

from yaff.log import log
from yaff.pes.ext import PairPotEI, PairPotLJ, PairPotMM3, PairPotExpRep, \
from yaff.pes.ext import PairPotEI, PairPotLJ, PairPotMM3, PairPotMM3CAP, PairPotExpRep, \
PairPotQMDFFRep, PairPotDampDisp, PairPotDisp68BJDamp, Switch3
from yaff.pes.ff import ForcePartPair, ForcePartValence, \
ForcePartEwaldReciprocal, ForcePartEwaldCorrection, \
Expand Down Expand Up @@ -71,7 +71,7 @@
'CrossBendDihedral6Generator',
'CrossBendCosDihedralGenerator',

'NonbondedGenerator', 'LJGenerator', 'MM3Generator', 'ExpRepGenerator',
'NonbondedGenerator', 'LJGenerator', 'MM3Generator', 'MM3CAPGenerator', 'ExpRepGenerator',
'DampDispGenerator', 'FixedChargeGenerator', 'D3BJGenerator',

'apply_generators',
Expand Down Expand Up @@ -1684,6 +1684,44 @@ def apply(self, par_table, scale_table, system, ff_args):
ff_args.parts.append(part_pair)


class MM3CAPGenerator(NonbondedGenerator):
prefix = 'MM3CAP'
suffixes = ['UNIT', 'SCALE', 'PARS']
par_info = [('SIGMA', float), ('EPSILON', float), ('ONLYPAULI', int)]

def __call__(self, system, parsec, ff_args):
self.check_suffixes(parsec)
conversions = self.process_units(parsec['UNIT'])
par_table = self.process_pars(parsec['PARS'], conversions, 1)
scale_table = self.process_scales(parsec['SCALE'])
self.apply(par_table, scale_table, system, ff_args)

def apply(self, par_table, scale_table, system, ff_args):
# Prepare the atomic parameters
sigmas = np.zeros(system.natom)
epsilons = np.zeros(system.natom)
onlypaulis = np.zeros(system.natom, np.int32)
for i in range(system.natom):
key = (system.get_ffatype(i),)
par_list = par_table.get(key, [])
if len(par_list) > 2:
raise TypeError('Superposition should not be allowed for non-covalent terms.')
elif len(par_list) == 1:
sigmas[i], epsilons[i], onlypaulis[i] = par_list[0]

# Prepare the global parameters
scalings = Scalings(system, scale_table[1], scale_table[2], scale_table[3], scale_table[4])

# Get the part. It should not exist yet.
part_pair = ff_args.get_part_pair(PairPotMM3CAP)
if part_pair is not None:
raise RuntimeError('Internal inconsistency: the MM3CAP part should not be present yet.')

pair_pot = PairPotMM3CAP(sigmas, epsilons, onlypaulis, ff_args.rcut, ff_args.tr)
nlist = ff_args.get_nlist(system)
part_pair = ForcePartPair(system, nlist, scalings, pair_pot)
ff_args.parts.append(part_pair)

class ExpRepGenerator(NonbondedGenerator):
prefix = 'EXPREP'
suffixes = ['UNIT', 'SCALE', 'MIX', 'PARS', 'CPARS']
Expand Down
61 changes: 61 additions & 0 deletions yaff/pes/pair_pot.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ void pair_data_mm3_init(pair_pot_type *pair_pot, double *sigma, double *epsilon,
}
}


double pair_fn_mm3(void *pair_data, long center_index, long other_index, double d, double *delta, double *g, double *g_cart) {
// E = epsilon*[1.84e5*exp(-12.0*R/sigma) - 2.25(sigma/R)^6]
double sigma, epsilon, x, exponent;
Expand Down Expand Up @@ -268,6 +269,66 @@ double pair_fn_mm3(void *pair_data, long center_index, long other_index, double
}


void pair_data_mm3cap_init(pair_pot_type *pair_pot, double *sigma, double *epsilon, int *onlypauli) {
pair_data_mm3_type *pair_data;
pair_data = malloc(sizeof(pair_data_mm3_type));
(*pair_pot).pair_data = pair_data;
if (pair_data != NULL) {
(*pair_pot).pair_fn = pair_fn_mm3cap;
(*pair_data).sigma = sigma;
(*pair_data).epsilon = epsilon;
(*pair_data).onlypauli = onlypauli;
}
}


double pair_fn_mm3cap(void *pair_data, long center_index, long other_index, double d, double *delta, double *g, double *g_cart) {
// modified mm3 potential for MC simulations:
// F = epsilon*[2.208e6/sigma*exp(-12.0*R/sigma) - 13.5*sigma^6/R^7] if R > 0.355114 * sigma (maximum of F)
// = 12182.86986*epsilon/sigma if R < 0.355114 * sigma
// E = epsilon*[1.84e5*exp(-12.0*R/sigma) - 2.25(sigma/R)^6] if R > 0.355114 * sigma
// = epsilon*[5799.303156-12182.86986*R/sigma] if R < 0.355114 * sigma
double sigma, epsilon, x, exponent, xmax;
int onlypauli;
sigma = (
(*(pair_data_mm3_type*)pair_data).sigma[center_index]+
(*(pair_data_mm3_type*)pair_data).sigma[other_index]
);
epsilon = sqrt(
(*(pair_data_mm3_type*)pair_data).epsilon[center_index]*
(*(pair_data_mm3_type*)pair_data).epsilon[other_index]
);
onlypauli = (
(*(pair_data_mm3_type*)pair_data).onlypauli[center_index]+
(*(pair_data_mm3_type*)pair_data).onlypauli[other_index]
);
x = d/sigma;
xmax = 0.355114;
if (onlypauli == 0){
if (x > xmax){
exponent = 1.84e5*exp(-12.0*x);
x *= x;
x *= 1/2.25*x*x;
if (g != NULL) {
*g =epsilon/d*(-12.0/sigma*exponent+6.0/d/x);
}
return epsilon*(exponent-1/x);
}
else {
exponent = 1.84e5*exp(-12.0*xmax);
xmax *= xmax;
xmax *= 1/2.25*xmax*xmax;
if (g != NULL) {
*g =epsilon/d*(-12.0/sigma*exponent+6.0/d/xmax);
}
return epsilon*(5799.303156-12182.86986*x);
}
}
else {
return pair_fn_mm3(pair_data, center_index, other_index, d, delta, g, g_cart);
}
}


void pair_data_grimme_init(pair_pot_type *pair_pot, double *r0, double *c6) {
pair_data_grimme_type *pair_data;
Expand Down
2 changes: 2 additions & 0 deletions yaff/pes/pair_pot.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ typedef struct {
void pair_data_mm3_init(pair_pot_type *pair_pot, double *sigma, double *epsilon, int *onlypauli);
double pair_fn_mm3(void *pair_data, long center_index, long other_index, double d, double *delta, double *g, double *g_cart);

void pair_data_mm3cap_init(pair_pot_type *pair_pot, double *sigma, double *epsilon, int *onlypauli);
double pair_fn_mm3cap(void *pair_data, long center_index, long other_index, double d, double *delta, double *g, double *g_cart);

typedef struct {
double *r0;
Expand Down
2 changes: 2 additions & 0 deletions yaff/pes/pair_pot.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ cdef extern from "pair_pot.h":

void pair_data_mm3_init(pair_pot_type *pair_pot, double *sigma, double *epsilon, int *onlypauli)

void pair_data_mm3cap_init(pair_pot_type *pair_pot, double *sigma, double *epsilon, int *onlypauli)

void pair_data_grimme_init(pair_pot_type *pair_pot, double *r0, double *c6)

void pair_data_exprep_init(pair_pot_type *pair_pot, long nffatype, long* ffatype_ids, double *amp_cross, double *b_cross)
Expand Down
79 changes: 79 additions & 0 deletions yaff/pes/test/test_pair_pot.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,45 @@ def pair_fn(i, j, d, delta):
return 0.0
return system, nlist, scalings, part_pair, pair_fn

def get_part_water32_9A_mm3cap():
# Initialize system, nlist and scaling
system = get_system_water32()
nlist = NeighborList(system)
scalings = Scalings(system)
# Initialize parameters
sigma_table = {1: 1.62*angstrom, 8: 1.82*angstrom}
epsilon_table = {1: 0.020*kcalmol, 8: 0.059*kcalmol}
sigmas = np.zeros(96, float)
epsilons = np.zeros(96, float)
onlypaulis = np.zeros(96, np.int32)
for i in range(system.natom):
sigmas[i] = sigma_table[system.numbers[i]]
epsilons[i] = epsilon_table[system.numbers[i]]
# Create the pair_pot and part_pair
rcut = 9*angstrom
pair_pot = PairPotMM3CAP(sigmas, epsilons, onlypaulis, rcut, Hammer(1.0))
assert abs(pair_pot.sigmas - sigmas).max() == 0.0
assert abs(pair_pot.epsilons - epsilons).max() == 0.0
part_pair = ForcePartPair(system, nlist, scalings, pair_pot)
# Create a pair function:
def pair_fn(i, j, d, delta):
sigma = sigmas[i]+sigmas[j]
epsilon = np.sqrt(epsilons[i]*epsilons[j])
x = (sigma/d)
if d<rcut:
return epsilon*(1.84e5*np.exp(-12.0/x)-2.25*x**6)*np.exp(1.0/(d-rcut))
else:
return 0.0
return system, nlist, scalings, part_pair, pair_fn


def test_pair_pot_mm3_water32_9A():
system, nlist, scalings, part_pair, pair_fn = get_part_water32_9A_mm3()
check_pair_pot_water32(system, nlist, scalings, part_pair, pair_fn, 1e-12)

def test_pair_pot_mm3cap_water32_9A():
system, nlist, scalings, part_pair, pair_fn = get_part_water32_9A_mm3cap()
check_pair_pot_water32(system, nlist, scalings, part_pair, pair_fn, 1e-12)

def get_part_water32_9A_grimme():
# Initialize system, nlist and scaling
Expand Down Expand Up @@ -687,10 +721,50 @@ def pair_fn(i, j, d):
return system, nlist, scalings, part_pair, pair_fn


def get_part_caffeine_mm3cap_15A():
# Get a system and define scalings
system = get_system_caffeine()
nlist = NeighborList(system)
scalings = Scalings(system, 0.0, 1.0, 0.5)
# Initialize (random) parameters
rminhalf_table = {
1: 0.2245*angstrom,
6: 1.6000*angstrom,
7: 1.7000*angstrom,
8: 1.7682*angstrom
}
epsilon_table = {
1: -0.0460*kcalmol,
6: -0.2357*kcalmol,
7: -0.1970*kcalmol,
8: -0.1521*kcalmol,
}
sigmas = np.zeros(24, float)
epsilons = np.zeros(24, float)
onlypaulis = np.zeros(24, np.int32)
for i in range(system.natom):
sigmas[i] = rminhalf_table[system.numbers[i]]*(2.0)**(5.0/6.0)
epsilons[i] = epsilon_table[system.numbers[i]]
# Construct the pair potential and part
pair_pot = PairPotMM3CAP(sigmas, epsilons, onlypaulis, 15*angstrom)
part_pair = ForcePartPair(system, nlist, scalings, pair_pot)
# The pair function
def pair_fn(i, j, d):
sigma = sigmas[i]+sigmas[j]
epsilon = np.sqrt(epsilons[i]*epsilons[j])
x = (sigma/d)
return epsilon*(1.84e5*np.exp(-12.0/x)-2.25*x**6)
return system, nlist, scalings, part_pair, pair_fn


def test_pair_pot_mm3_caffeine_15A():
system, nlist, scalings, part_pair, pair_fn = get_part_caffeine_mm3_15A()
check_pair_pot_caffeine(system, nlist, scalings, part_pair, pair_fn, 1e-12)

def test_pair_pot_mm3cap_caffeine_15A():
system, nlist, scalings, part_pair, pair_fn = get_part_caffeine_mm3cap_15A()
check_pair_pot_caffeine(system, nlist, scalings, part_pair, pair_fn, 1e-12)


def get_part_caffeine_grimme_15A():
# Get a system and define scalings
Expand Down Expand Up @@ -1185,6 +1259,11 @@ def test_gpos_vtens_pair_pot_caffeine_mm3_15A():
check_gpos_part(system, part_pair, nlist)
check_vtens_part(system, part_pair, nlist)

def test_gpos_vtens_pair_pot_caffeine_mm3cap_15A():
system, nlist, scalings, part_pair, pair_fn = get_part_caffeine_mm3cap_15A()
check_gpos_part(system, part_pair, nlist)
check_vtens_part(system, part_pair, nlist)


def test_gpos_vtens_pair_pot_caffeine_grimme_15A():
system, nlist, scalings, part_pair, pair_fn = get_part_caffeine_grimme_15A()
Expand Down

0 comments on commit efd8d52

Please sign in to comment.