Unverified Commit 0118afa0 authored by kyw220's avatar kyw220 Committed by GitHub
Browse files

Support of Amber FF19SB CMAP (#3143)



* Support of Amber FF19SB CMAP

* Update: Support of Amber FF19SB CMAP
Co-authored-by: default avatarKye Won Wang <kyw220@sol.cc.lehigh.edu>
parent fad93127
...@@ -14,7 +14,7 @@ Medical Research, grant U54 GM072970. See https://simtk.org. ...@@ -14,7 +14,7 @@ Medical Research, grant U54 GM072970. See https://simtk.org.
Portions copyright (c) 2012-2014 Stanford University and the Authors. Portions copyright (c) 2012-2014 Stanford University and the Authors.
Authors: Randall J. Radmer, John D. Chodera, Peter Eastman Authors: Randall J. Radmer, John D. Chodera, Peter Eastman
Contributors: Christoph Klein, Michael R. Shirts, Jason Swails Contributors: Christoph Klein, Michael R. Shirts, Jason Swails, Kye Won Wang
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
...@@ -62,7 +62,7 @@ from . import customgbforces as customgb ...@@ -62,7 +62,7 @@ from . import customgbforces as customgb
#============================================================================================= #=============================================================================================
# A regex for extracting print format info from the FORMAT lines. # A regex for extracting print format info from the FORMAT lines.
FORMAT_RE_PATTERN=re.compile("([0-9]+)([a-zA-Z]+)([0-9]+)\.?([0-9]*)") FORMAT_RE_PATTERN=re.compile("([0-9]+)\(?([a-zA-Z]+)([0-9]+)\.?([0-9]*)\)?")
# Pointer labels which map to pointer numbers at top of prmtop files # Pointer labels which map to pointer numbers at top of prmtop files
POINTER_LABELS = """ POINTER_LABELS = """
...@@ -132,8 +132,6 @@ class PrmtopLoader(object): ...@@ -132,8 +132,6 @@ class PrmtopLoader(object):
raise TypeError('CHAMBER-style topology files are not supported here. ' raise TypeError('CHAMBER-style topology files are not supported here. '
'Consider using the CHARMM files directly with CharmmPsfFile ' 'Consider using the CHARMM files directly with CharmmPsfFile '
'or ParmEd (where CHAMBER topologies are supported)') 'or ParmEd (where CHAMBER topologies are supported)')
if 'CMAP' in flag:
raise TypeError("CMAP terms in AMBER topology files are not supported. You can use ParmEd instead")
self._flags.append(flag) self._flags.append(flag)
self._raw_data[flag] = [] self._raw_data[flag] = []
elif line.startswith('%FORMAT'): elif line.startswith('%FORMAT'):
...@@ -461,6 +459,62 @@ class PrmtopLoader(object): ...@@ -461,6 +459,62 @@ class PrmtopLoader(object):
int(0.5+float(periodicity[iType])))) int(0.5+float(periodicity[iType]))))
return self._dihedralList return self._dihedralList
def getNumMaps(self):
"""Return number of CMAPs. Return 0 if CMAP does not exist"""
try:
return self._numCMAP
except AttributeError:
pass
if "CMAP_COUNT" in self._raw_data.keys():
self._numCMAP=int(self._raw_data["CMAP_COUNT"][1])
return self._numCMAP
return 0
def getCMAPResolutions(self):
"""Return CMAP resolution info. Return 0 if CMAP does not exist"""
try:
return self._cmapResolution
except AttributeError:
pass
if "CMAP_RESOLUTION" in self._raw_data.keys():
self._cmapResolution=self._raw_data["CMAP_RESOLUTION"]
return self._cmapResolution
return 0
def getCMAPParameters(self, index):
"""Return list of CMAP energy values"""
flag="CMAP_PARAMETER_{:02d}".format(index)
return [float(pointer) for pointer in self._raw_data[flag]]
def getCMAPDihedrals(self):
"""Return CMAP type, list of first four atoms, and list of second four atoms"""
try:
return self._cmapList
except AttributeError:
pass
cmapPointers = self._raw_data["CMAP_INDEX"]
self._cmapList=[]
forceConstConversionFactor = (units.kilocalorie_per_mole).conversion_factor_to(units.kilojoule_per_mole)
for ii in range(0,len(cmapPointers),6):
if any([int(cmapPointers[ii+jj])<0 for jj in range(5)]):
raise ValueError("Found negative cmap atom pointers %s"
% ((cmapPointers[ii],
cmapPointers[ii+1],
cmapPointers[ii+2],
cmapPointers[ii+3],
cmapPointers[ii+4]),))
iType=int(cmapPointers[ii+5])-1
self._cmapList.append((int(iType),
int(cmapPointers[ii])-1,
int(cmapPointers[ii+1])-1,
int(cmapPointers[ii+2])-1,
int(cmapPointers[ii+3])-1,
int(cmapPointers[ii+1])-1,
int(cmapPointers[ii+2])-1,
int(cmapPointers[ii+3])-1,
int(cmapPointers[ii+4])-1))
return self._cmapList
def get14Interactions(self): def get14Interactions(self):
"""Return list of atom pairs, chargeProduct, rMin and epsilon for each 1-4 interaction""" """Return list of atom pairs, chargeProduct, rMin and epsilon for each 1-4 interaction"""
dihedralPointers = self._raw_data["DIHEDRALS_INC_HYDROGEN"] \ dihedralPointers = self._raw_data["DIHEDRALS_INC_HYDROGEN"] \
...@@ -742,6 +796,34 @@ def readAmberSystem(topology, prmtop_filename=None, prmtop_loader=None, shake=No ...@@ -742,6 +796,34 @@ def readAmberSystem(topology, prmtop_filename=None, prmtop_loader=None, shake=No
force.addTorsion(iAtom, jAtom, kAtom, lAtom, periodicity, phase, forceConstant) force.addTorsion(iAtom, jAtom, kAtom, lAtom, periodicity, phase, forceConstant)
system.addForce(force) system.addForce(force)
# Add CMAP info.
## Get mapSize and Resolutions
numMap = prmtop.getNumMaps()
mapSize = prmtop.getCMAPResolutions()
if numMap > 0:
if verbose: print("Adding CMAPs...")
force = mm.CMAPTorsionForce()
### Get map energies
for field in range(numMap):
index = field + 1
ngrid = int(mapSize[field])
cmap = []
cmap_param = prmtop.getCMAPParameters(index)
forceConstConversionFactor = (units.kilocalorie_per_mole).conversion_factor_to(units.kilojoule_per_mole)
for i in range(ngrid):
for j in range(ngrid):
idx = ngrid*((j+ngrid//2)%ngrid)+((i+ngrid//2)%ngrid)
cmap.append(cmap_param[idx]*forceConstConversionFactor)
cmap = tuple(cmap)
force.addMap(ngrid, cmap)
#### Add CMAPtorsions.
if verbose: print("Adding CMAP torsions...")
for (Type, iAtom, jAtom, kAtom, lAtom, jAtom, kAtom, lAtom, mAtom) in prmtop.getCMAPDihedrals():
index=force.addTorsion(Type, iAtom, jAtom, kAtom, lAtom, jAtom, kAtom, lAtom, mAtom)
system.addForce(force)
# Add nonbonded interactions. # Add nonbonded interactions.
if verbose: print("Adding nonbonded interactions...") if verbose: print("Adding nonbonded interactions...")
force = mm.NonbondedForce() force = mm.NonbondedForce()
......
...@@ -13,8 +13,10 @@ prmtop3 = AmberPrmtopFile('systems/ff14ipq.parm7') ...@@ -13,8 +13,10 @@ prmtop3 = AmberPrmtopFile('systems/ff14ipq.parm7')
prmtop4 = AmberPrmtopFile('systems/Mg_water.prmtop') prmtop4 = AmberPrmtopFile('systems/Mg_water.prmtop')
prmtop5 = AmberPrmtopFile('systems/tz2.truncoct.parm7') prmtop5 = AmberPrmtopFile('systems/tz2.truncoct.parm7')
prmtop6 = AmberPrmtopFile('systems/gaffwat.parm7') prmtop6 = AmberPrmtopFile('systems/gaffwat.parm7')
prmtop7 = AmberPrmtopFile('systems/18protein.parm7')
inpcrd3 = AmberInpcrdFile('systems/ff14ipq.rst7') inpcrd3 = AmberInpcrdFile('systems/ff14ipq.rst7')
inpcrd4 = AmberInpcrdFile('systems/Mg_water.inpcrd') inpcrd4 = AmberInpcrdFile('systems/Mg_water.inpcrd')
inpcrd7 = AmberInpcrdFile('systems/18protein.rst7')
class TestAmberPrmtopFile(unittest.TestCase): class TestAmberPrmtopFile(unittest.TestCase):
...@@ -403,5 +405,32 @@ class TestAmberPrmtopFile(unittest.TestCase): ...@@ -403,5 +405,32 @@ class TestAmberPrmtopFile(unittest.TestCase):
energy = context.getState(getEnergy=True, groups={1}).getPotentialEnergy().value_in_unit(kilojoules_per_mole) energy = context.getState(getEnergy=True, groups={1}).getPotentialEnergy().value_in_unit(kilojoules_per_mole)
self.assertAlmostEqual(energy, expectedEnergy, delta=5e-4*abs(energy)) self.assertAlmostEqual(energy, expectedEnergy, delta=5e-4*abs(energy))
def testAmberCMAP(self):
"""Check that CMAP energy calcultion compared to AMber."""
temperature = 50*kelvin
conversion = 4.184 # 4.184 kJ/mol
sander_CMAP_E = 8.2864 # CMAP energy calcluated by Amber, unit kcal/mol
prmtop = prmtop7 # systems/18protein.parm7
inpcrd = inpcrd7 # systems/18protein.rst7
system = prmtop.createSystem(nonbondedMethod=PME, nonbondedCutoff=1.2)
integrator = LangevinIntegrator(temperature, 1.0 / picosecond, 0.002 * picoseconds)
simulation = Simulation(prmtop.topology, system, integrator)
simulation.context.setPositions(inpcrd.positions)
simulation.context.setPeriodicBoxVectors(*inpcrd.boxVectors)
for i, force in enumerate(system.getForces()):
force.setForceGroup(i)
simulation.context.reinitialize(True)
for i in range(system.getNumForces()):
if i == 3: # 3 indicates CMAP force
# print(simulation.context.getState(getEnergy=True, groups=1<<i).getPotentialEnergy().value_in_unit(kilojoules_per_mole))
OpenMM_CMAP_E = simulation.context.getState(getEnergy=True, groups=1<<i).getPotentialEnergy().value_in_unit(kilojoules_per_mole)/conversion
self.assertAlmostEqual(OpenMM_CMAP_E, sander_CMAP_E, places=4)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment