Commit 71d33617 authored by John Chodera (MSKCC)'s avatar John Chodera (MSKCC)
Browse files

Merge remote-tracking branch 'upstream/master'

parents eb232608 9da36463
......@@ -48,10 +48,11 @@
using namespace OpenMM;
using namespace std;
ReferencePlatform platform;
const double TOL = 1e-5;
void testSingleBond() {
ReferencePlatform platform;
System system;
system.addParticle(2.0);
system.addParticle(2.0);
......@@ -89,7 +90,6 @@ void testSingleBond() {
void testConstraints() {
const int numParticles = 8;
const double temp = 500.0;
ReferencePlatform platform;
System system;
VariableVerletIntegrator integrator(1e-5);
integrator.setConstraintTolerance(1e-5);
......@@ -148,7 +148,6 @@ void testConstraints() {
void testConstrainedClusters() {
const int numParticles = 7;
const double temp = 500.0;
ReferencePlatform platform;
System system;
VariableVerletIntegrator integrator(1e-5);
integrator.setConstraintTolerance(1e-5);
......@@ -211,7 +210,6 @@ void testConstrainedClusters() {
}
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
......@@ -255,7 +253,6 @@ void testArgonBox() {
// Create a box of argon atoms.
ReferencePlatform platform;
System system;
NonbondedForce* nonbonded = new NonbondedForce();
vector<Vec3> positions;
......
......@@ -48,10 +48,11 @@
using namespace OpenMM;
using namespace std;
ReferencePlatform platform;
const double TOL = 1e-5;
void testSingleBond() {
ReferencePlatform platform;
System system;
system.addParticle(2.0);
system.addParticle(2.0);
......@@ -88,7 +89,6 @@ void testSingleBond() {
void testConstraints() {
const int numParticles = 8;
const double temp = 500.0;
ReferencePlatform platform;
System system;
VerletIntegrator integrator(0.002);
integrator.setConstraintTolerance(1e-5);
......@@ -139,7 +139,6 @@ void testConstraints() {
void testConstrainedClusters() {
const int numParticles = 7;
const double temp = 500.0;
ReferencePlatform platform;
System system;
VerletIntegrator integrator(0.001);
integrator.setConstraintTolerance(1e-5);
......@@ -201,7 +200,6 @@ void testConstrainedClusters() {
}
void testConstrainedMasslessParticles() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
......
......@@ -50,11 +50,12 @@
using namespace OpenMM;
using namespace std;
ReferencePlatform platform;
/**
* Check that massless particles are handled correctly.
*/
void testMasslessParticle() {
ReferencePlatform platform;
System system;
system.addParticle(0.0);
system.addParticle(1.0);
......@@ -91,7 +92,6 @@ void testMasslessParticle() {
* Test a TwoParticleAverageSite virtual site.
*/
void testTwoParticleAverage() {
ReferencePlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
......@@ -128,7 +128,6 @@ void testTwoParticleAverage() {
* Test a ThreeParticleAverageSite virtual site.
*/
void testThreeParticleAverage() {
ReferencePlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
......@@ -170,7 +169,6 @@ void testThreeParticleAverage() {
* Test an OutOfPlaneSite virtual site.
*/
void testOutOfPlane() {
ReferencePlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
......@@ -223,7 +221,6 @@ void testLocalCoordinates() {
const Vec3 xWeights(-1.0, 0.5, 0.5);
const Vec3 yWeights(0.0, -1.0, 1.0);
const Vec3 localPosition(0.4, 0.3, 0.2);
ReferencePlatform platform;
System system;
system.addParticle(1.0);
system.addParticle(1.0);
......@@ -299,7 +296,6 @@ void testLocalCoordinates() {
* when using virtual sites.
*/
void testConservationLaws() {
ReferencePlatform platform;
System system;
NonbondedForce* forceField = new NonbondedForce();
system.addForce(forceField);
......
......@@ -159,7 +159,7 @@ public:
/**
* Update the per-angle parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setAngleParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setAngleParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-angle parameters. The set of particles involved
......
......@@ -131,7 +131,7 @@ public:
/**
* Update the per-bond parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setBondParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setBondParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-bond parameters. The set of particles involved
......
......@@ -156,7 +156,7 @@ public:
/**
* Update the per-particle parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setParticleParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setParticleParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-particle parameters. All other aspects of the Force
......
......@@ -164,7 +164,7 @@ public:
/**
* Update the per-angle parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setAngleParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setAngleParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-angle parameters. The set of particles involved
......
......@@ -340,7 +340,7 @@ public:
/**
* Update the multipole parameters in a Context to match those stored in this Force object. This method
* provides an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setMultipoleParameters() to modify this object's parameters, then call updateParametersInState() to
* Simply call setMultipoleParameters() to modify this object's parameters, then call updateParametersInContext() to
* copy them over to the Context.
*
* This method has several limitations. The only information it updates is the parameters of multipoles.
......
......@@ -156,7 +156,7 @@ public:
/**
* Update the per-bend term parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setOutOfPlaneBendParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setOutOfPlaneBendParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-bend term parameters. The set of particles involved
......
......@@ -106,7 +106,7 @@ public:
/**
* Update the per-torsion parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setPiTorsionParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setPiTorsionParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-torsion parameters. The set of particles involved
......
......@@ -112,7 +112,7 @@ public:
/**
* Update the per-stretch-bend term parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setStretchBendParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setStretchBendParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-stretch-bend term parameters. The set of particles involved
......
......@@ -205,7 +205,7 @@ public:
/**
* Update the per-particle parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setParticleParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setParticleParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-particle parameters. All other aspects of the Force
......
......@@ -92,7 +92,7 @@ public:
/**
* Update the per-particle parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setParticleParameters() to modify this object's parameters, then call updateParametersInState()
* Simply call setParticleParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* The only information this method updates is the values of per-particle parameters. All other aspects of the Force
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2014 Stanford University and the Authors. *
* Portions copyright (c) 2014-2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -148,6 +148,7 @@ void testMathFunctions() {
ASSERT_VEC4_EQUAL(min(f1, f2), 0.4, 1.2, -1.2, -5.0);
ASSERT_VEC4_EQUAL(max(f1, f2), 1.1, 1.9, 1.3, -3.8);
ASSERT_VEC4_EQUAL(sqrt(fvec4(1.5, 3.1, 4.0, 15.0)), sqrt(1.5), sqrt(3.1), sqrt(4.0), sqrt(15.0));
ASSERT_VEC4_EQUAL(rsqrt(fvec4(1.5, 3.1, 4.0, 15.0)), 1.0/sqrt(1.5), 1.0/sqrt(3.1), 1.0/sqrt(4.0), 1.0/sqrt(15.0));
ASSERT_EQUAL_TOL(f1[0]*f2[0]+f1[1]*f2[1]+f1[2]*f2[2], dot3(f1, f2), 1e-6);
ASSERT_EQUAL_TOL(f1[0]*f2[0]+f1[1]*f2[1]+f1[2]*f2[2]+f1[3]*f2[3], dot4(f1, f2), 1e-6);
ASSERT(any(f1 > 0.5));
......
......@@ -73,9 +73,8 @@ class AmberPrmtopFile(object):
def __init__(self, file):
"""Load a prmtop file."""
top = Topology()
## The Topology read from the prmtop file
self.topology = top
self.topology = top = Topology()
self.elements = []
# Load the prmtop file
......@@ -229,7 +228,7 @@ class AmberPrmtopFile(object):
elif implicitSolvent is None:
implicitSolventKappa = 0.0
sys = amber_file_parser.readAmberSystem(prmtop_loader=self._prmtop, shake=constraintString,
sys = amber_file_parser.readAmberSystem(self.topology, prmtop_loader=self._prmtop, shake=constraintString,
nonbondedCutoff=nonbondedCutoff, nonbondedMethod=methodMap[nonbondedMethod],
flexibleConstraints=False, gbmodel=implicitString, soluteDielectric=soluteDielectric,
solventDielectric=solventDielectric, implicitSolventKappa=implicitSolventKappa,
......
......@@ -37,6 +37,7 @@ from __future__ import division
from functools import wraps
from math import pi, cos, sin, sqrt
import os
import re
import simtk.openmm as mm
from simtk.openmm.vec3 import Vec3
import simtk.unit as u
......@@ -99,6 +100,8 @@ class _ZeroDict(dict):
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_resre = re.compile(r'(\d+)([a-zA-Z]*)')
class CharmmPsfFile(object):
"""
A chemical structure instantiated from CHARMM files.
......@@ -192,11 +195,13 @@ class CharmmPsfFile(object):
atom_list = AtomList()
for i in xrange(natom):
words = psfsections['NATOM'][1][i].split()
atid = int(words[0])
if atid != i + 1:
raise CharmmPSFError('Nonsequential atoms detected!')
system = words[1]
resid = conv(words[2], int, 'residue number')
rematch = _resre.match(words[2])
if not rematch:
raise RuntimeError('Could not parse residue number %s' %
words[2])
resid, inscode = rematch.groups()
resid = int(resid)
resname = words[3]
name = words[4]
attype = words[5]
......@@ -209,7 +214,7 @@ class CharmmPsfFile(object):
mass = conv(words[7], float, 'atomic mass')
props = words[8:]
atom = residue_list.add_atom(system, resid, resname, name,
attype, charge, mass, props)
attype, charge, mass, inscode, props)
atom_list.append(atom)
atom_list.assign_indexes()
atom_list.changed = False
......@@ -443,175 +448,6 @@ class CharmmPsfFile(object):
line = psf.readline().strip()
return title, pointers, data
def writePsf(self, dest, vmd=False):
"""
Writes a PSF file from the stored molecule
Parameters:
- dest (str or file-like) : The place to write the output PSF file.
If it has a "write" attribute, it will be used to print the
PSF file. Otherwise, it will be treated like a string and a
file will be opened, printed, then closed
- vmd (bool) : If True, it will write out a PSF in the format that
VMD prints it in (i.e., no NUMLP/NUMLPH or MOLNT sections)
Example:
>>> cs = CharmmPsfFile('testfiles/test.psf')
>>> cs.writePsf('testfiles/test2.psf')
"""
# See if this is an extended format
ext = 'EXT' in self.flags
own_handle = False
# Index the atoms and residues
self.residue_list.assign_indexes()
self.atom_list.assign_indexes()
if not hasattr(dest, 'write'):
own_handle = True
dest = open(dest, 'w')
# Assign the formats we need to write with
if ext:
atmfmt1 = ('%10d %-8s %-8i %-8s %-8s %4d %10.6f %13.4f' + 11*' ')
atmfmt2 = ('%10d %-8s %-8i %-8s %-8s %-4s %10.6f %13.4f' + 11*' ')
intfmt = '%10d' # For pointers
else:
atmfmt1 = ('%8d %-4s %-4i %-4s %-4s %4d %10.6f %13.4f' + 11*' ')
atmfmt2 = ('%8d %-4s %-4i %-4s %-4s %-4s %10.6f %13.4f' + 11*' ')
intfmt = '%8d' # For pointers
# Now print the header then the title
dest.write('PSF ' + ' '.join(self.flags) + '\n')
dest.write('\n')
dest.write(intfmt % len(self.title) + ' !NTITLE\n')
dest.write('\n'.join(self.title) + '\n\n')
# Now time for the atoms
dest.write(intfmt % len(self.atom_list) + ' !NATOM\n')
# atmfmt1 is for CHARMM format (i.e., atom types are integers)
# atmfmt is for XPLOR format (i.e., atom types are strings)
for i, atom in enumerate(self.atom_list):
if isinstance(atom.attype, str):
fmt = atmfmt2
else:
fmt = atmfmt1
atmstr = fmt % (i+1, atom.system, atom.residue.resnum,
atom.residue.resname, atom.name, atom.attype,
atom.charge, atom.mass)
dest.write(atmstr + ' '.join(atom.props) + '\n')
dest.write('\n')
# Bonds
dest.write(intfmt % len(self.bond_list) + ' !NBOND: bonds\n')
for i, bond in enumerate(self.bond_list):
dest.write((intfmt*2) % (bond.atom1.idx+1, bond.atom2.idx+1))
if i % 4 == 3: # Write 4 bonds per line
dest.write('\n')
# See if we need to terminate
if len(self.bond_list) % 4 != 0 or len(self.bond_list) == 0:
dest.write('\n')
dest.write('\n')
# Angles
dest.write(intfmt % len(self.angle_list) + ' !NTHETA: angles\n')
for i, angle in enumerate(self.angle_list):
dest.write((intfmt*3) % (angle.atom1.idx+1, angle.atom2.idx+1,
angle.atom3.idx+1)
)
if i % 3 == 2: # Write 3 angles per line
dest.write('\n')
# See if we need to terminate
if len(self.angle_list) % 3 != 0 or len(self.angle_list) == 0:
dest.write('\n')
dest.write('\n')
# Dihedrals
dest.write(intfmt % len(self.dihedral_list) + ' !NPHI: dihedrals\n')
for i, dih in enumerate(self.dihedral_list):
dest.write((intfmt*4) % (dih.atom1.idx+1, dih.atom2.idx+1,
dih.atom3.idx+1, dih.atom4.idx+1)
)
if i % 2 == 1: # Write 2 dihedrals per line
dest.write('\n')
# See if we need to terminate
if len(self.dihedral_list) % 2 != 0 or len(self.dihedral_list) == 0:
dest.write('\n')
dest.write('\n')
# Impropers
dest.write(intfmt % len(self.improper_list) + ' !NIMPHI: impropers\n')
for i, imp in enumerate(self.improper_list):
dest.write((intfmt*4) % (imp.atom1.idx+1, imp.atom2.idx+1,
imp.atom3.idx+1, imp.atom4.idx+1)
)
if i % 2 == 1: # Write 2 dihedrals per line
dest.write('\n')
# See if we need to terminate
if len(self.improper_list) % 2 != 0 or len(self.improper_list) == 0:
dest.write('\n')
dest.write('\n')
# Donor section
dest.write(intfmt % len(self.donor_list) + ' !NDON: donors\n')
for i, don in enumerate(self.donor_list):
dest.write((intfmt*2) % (don.atom1.idx+1, don.atom2.idx+1))
if i % 4 == 3: # 4 donors per line
dest.write('\n')
if len(self.donor_list) % 4 != 0 or len(self.donor_list) == 0:
dest.write('\n')
dest.write('\n')
# Acceptor section
dest.write(intfmt % len(self.acceptor_list) + ' !NACC: acceptors\n')
for i, acc in enumerate(self.acceptor_list):
dest.write((intfmt*2) % (acc.atom1.idx+1, acc.atom2.idx+1))
if i % 4 == 3: # 4 donors per line
dest.write('\n')
if len(self.acceptor_list) % 4 != 0 or len(self.acceptor_list) == 0:
dest.write('\n')
dest.write('\n')
# NNB section ??
dest.write(intfmt % 0 + ' !NNB\n\n')
for i in range(len(self.atom_list)):
dest.write(intfmt % 0)
if i % 8 == 7: # Write 8 0's per line
dest.write('\n')
if len(self.atom_list) % 8 != 0: dest.write('\n')
dest.write('\n')
# Group section
dest.write((intfmt*2) % (len(self.group_list), self.group_list.nst2))
dest.write(' !NGRP NST2\n')
for i, gp in enumerate(self.group_list):
dest.write((intfmt*3) % (gp.bs, gp.type, gp.move))
if i % 3 == 2: dest.write('\n')
if len(self.group_list) % 3 != 0 or len(self.group_list) == 0:
dest.write('\n')
dest.write('\n')
# The next two sections are never found in VMD prmtops...
if not vmd:
# Molecule section; first set molecularity
set_molecules(self.atom_list)
mollist = [a.marked for a in self.atom_list]
dest.write(intfmt % max(mollist) + ' !MOLNT\n')
for i, atom in enumerate(self.atom_list):
dest.write(intfmt % atom.marked)
if i % 8 == 7: dest.write('\n')
if len(self.atom_list) % 8 != 0: dest.write('\n')
dest.write('\n')
# NUMLP/NUMLPH section
dest.write((intfmt*2) % (0, 0) + ' !NUMLP NUMLPH\n')
dest.write('\n')
# CMAP section
dest.write(intfmt % len(self.cmap_list) + ' !NCRTERM: cross-terms\n')
for i, cmap in enumerate(self.cmap_list):
dest.write((intfmt*4) % (cmap.atom1.idx+1, cmap.atom2.idx+1,
cmap.atom3.idx+1, cmap.atom4.idx+1)
)
if cmap.consecutive:
dest.write((intfmt*4) % (cmap.atom2.idx+1, cmap.atom3.idx+1,
cmap.atom4.idx+1, cmap.atom5.idx+1)
)
else:
dest.write((intfmt*4) % (cmap.atom5.idx+1, cmap.atom6.idx+1,
cmap.atom7.idx+1, cmap.atom8.idx+1)
)
dest.write('\n')
# Done!
# If we opened our own handle, close it
if own_handle:
dest.close()
def loadParameters(self, parmset):
"""
Loads parameters from a parameter set that was loaded via CHARMM RTF,
......@@ -776,13 +612,13 @@ class CharmmPsfFile(object):
last_residue = None
# Add each chain (separate 'system's) and residue
for atom in self.atom_list:
resid = '%d%s' % (atom.residue.idx, atom.residue.inscode)
if atom.system != last_chain:
chain = topology.addChain(atom.system)
last_chain = atom.system
if atom.residue.idx != last_residue:
last_residue = atom.residue.idx
residue = topology.addResidue(atom.residue.resname, chain,
str(atom.residue.idx))
if resid != last_residue:
last_residue = resid
residue = topology.addResidue(atom.residue.resname, chain, resid)
if atom.type is not None:
# This is the most reliable way of determining the element
atomic_num = atom.type.atomic_number
......
......@@ -37,6 +37,8 @@ import time
import struct
import math
from simtk.unit import picoseconds, nanometers, angstroms, is_quantity, norm
from simtk.openmm import Vec3
from simtk.openmm.app.internal.unitcell import computeLengthsAndAngles
class DCDFile(object):
"""DCDFile provides methods for creating DCD files.
......@@ -112,16 +114,16 @@ class DCDFile(object):
file.seek(0, os.SEEK_END)
boxVectors = self._topology.getPeriodicBoxVectors()
if boxVectors is not None:
if getPeriodicBoxVectors is not None:
boxVectors = getPeriodicBoxVectors
if periodicBoxVectors is not None:
boxVectors = periodicBoxVectors
elif unitCellDimensions is not None:
if is_quantity(unitCellDimensions):
unitCellDimensions = unitCellDimensions.value_in_unit(nanometers)
boxVectors = (Vec3(unitCellDimensions[0], 0, 0), Vec3(0, unitCellDimensions[1], 0), Vec3(0, 0, unitCellDimensions[2]))*nanometers
(a_length, b_length, c_length, alpha, beta, gamma) = computeLengthsAndAngles(boxVectors)
a_length = a_length.value_in_unit(angstroms)
b_length = b_length.value_in_unit(angstroms)
c_length = c_length.value_in_unit(angstroms)
a_length = a_length * 10. # computeLengthsAndAngles returns unitless nanometers, but need angstroms here.
b_length = b_length * 10. # computeLengthsAndAngles returns unitless nanometers, but need angstroms here.
c_length = c_length * 10. # computeLengthsAndAngles returns unitless nanometers, but need angstroms here.
angle1 = math.sin(math.pi/2-gamma)
angle2 = math.sin(math.pi/2-beta)
angle3 = math.sin(math.pi/2-alpha)
......
......@@ -31,7 +31,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
__author__ = "Christopher M. Bruns"
__version__ = "1.0"
from collections import OrderedDict
from simtk.unit import daltons, is_quantity
import copy_reg
......@@ -47,6 +47,7 @@ class Element(object):
_elements_by_symbol = {}
_elements_by_atomic_number = {}
_elements_by_mass = None
def __init__(self, number, name, symbol, mass):
"""Create a new element
......@@ -67,8 +68,11 @@ class Element(object):
self._mass = mass
# Index this element in a global table
s = symbol.strip().upper()
## If we add a new element, we need to re-hash elements by mass
Element._elements_by_mass = None
assert s not in Element._elements_by_symbol
if s in Element._elements_by_symbol:
raise ValueError('Duplicate element symbol %s' % s)
Element._elements_by_symbol[s] = self
if number in Element._elements_by_atomic_number:
other_element = Element._elements_by_atomic_number[number]
......@@ -96,20 +100,45 @@ class Element(object):
"""
Get the element whose mass is CLOSEST to the requested mass. This method
should not be used for repartitioned masses
Parameters
----------
mass : float or Quantity
Mass of the atom to find the element for. Units assumed to be
daltons if not specified
Returns
-------
element : Element
The element whose atomic mass is closest to the input mass
"""
# Assume masses are in daltons if they are not units
if not is_quantity(mass):
mass = mass * daltons
if is_quantity(mass):
mass = mass.value_in_unit(daltons)
if mass < 0:
raise ValueError('Invalid Higgs field')
# If this is our first time calling getByMass (or we added an element
# since the last call), re-generate the ordered by-mass dict cache
if Element._elements_by_mass is None:
Element._elements_by_mass = OrderedDict()
for elem in sorted(Element._elements_by_symbol.values(),
key=lambda x: x.mass):
Element._elements_by_mass[elem.mass] = elem
diff = mass
best_guess = None
for key in Element._elements_by_atomic_number:
element = Element._elements_by_atomic_number[key]
massdiff = abs(element.mass - mass)
for elemmass, element in Element._elements_by_mass.iteritems():
massdiff = abs(elemmass._value - mass)
if massdiff < diff:
best_guess = element
diff = massdiff
if elemmass._value > mass:
# Elements are only getting heavier, so bail out early
return best_guess
# This really should only happen if we wanted ununoctium or something
# bigger... won't really happen but still make sure we return an Element
return best_guess
@property
......@@ -145,6 +174,9 @@ def _pickle_element(element):
copy_reg.pickle(Element, _pickle_element)
# NOTE: getElementByMass assumes all masses are Quantity instances with unit
# "daltons". All elements need to obey this assumption, or that method will
# fail. No checking is done in getElementByMass for performance reasons
hydrogen = Element( 1, "hydrogen", "H", 1.007947*daltons)
deuterium = Element( 1, "deuterium", "D", 2.01355321270*daltons)
helium = Element( 2, "helium", "He", 4.003*daltons)
......
......@@ -122,21 +122,22 @@ class PrmtopLoader(object):
with open(inFilename, 'r') as fIn:
for line in fIn:
if line.startswith('%VERSION'):
tag, self._prmtopVersion = line.rstrip().split(None, 1)
elif line.startswith('%FLAG'):
tag, flag = line.rstrip().split(None, 1)
self._flags.append(flag)
self._raw_data[flag] = []
elif line.startswith('%FORMAT'):
format = line.rstrip()
index0=format.index('(')
index1=format.index(')')
format = format[index0+1:index1]
m = FORMAT_RE_PATTERN.search(format)
self._raw_format[self._flags[-1]] = (format, m.group(1), m.group(2), m.group(3), m.group(4))
elif line.startswith('%COMMENT'):
continue
if line[0] == '%':
if line.startswith('%VERSION'):
tag, self._prmtopVersion = line.rstrip().split(None, 1)
elif line.startswith('%FLAG'):
tag, flag = line.rstrip().split(None, 1)
self._flags.append(flag)
self._raw_data[flag] = []
elif line.startswith('%FORMAT'):
format = line.rstrip()
index0=format.index('(')
index1=format.index(')')
format = format[index0+1:index1]
m = FORMAT_RE_PATTERN.search(format)
self._raw_format[self._flags[-1]] = (format, m.group(1), m.group(2), int(m.group(3)), m.group(4))
elif line.startswith('%COMMENT'):
continue
elif self._flags \
and 'TITLE'==self._flags[-1] \
and not self._raw_data['TITLE']:
......@@ -144,8 +145,7 @@ class PrmtopLoader(object):
else:
flag=self._flags[-1]
(format, numItems, itemType,
itemLength, itemPrecision) = self._getFormat(flag)
iLength=int(itemLength)
iLength, itemPrecision) = self._getFormat(flag)
line = line.rstrip()
for index in range(0, len(line), iLength):
item = line[index:index+iLength]
......@@ -305,6 +305,10 @@ class PrmtopLoader(object):
return self._nonbondTerms
except AttributeError:
pass
# Check if there are any non-zero HBOND terms
for x, y in zip(self._raw_data['HBOND_ACOEF'], self._raw_data['HBOND_BCOEF']):
if float(x) or float(y):
raise Exception('10-12 interactions are not supported')
self._nonbondTerms=[]
lengthConversionFactor = units.angstrom.conversion_factor_to(units.nanometer)
energyConversionFactor = units.kilocalorie_per_mole.conversion_factor_to(units.kilojoule_per_mole)
......@@ -333,6 +337,7 @@ class PrmtopLoader(object):
for i in range(numTypes):
for j in range(numTypes):
index = int(self._raw_data['NONBONDED_PARM_INDEX'][numTypes*i+j]) - 1
if index < 0: continue
rij = type_parameters[i][0] + type_parameters[j][0]
wdij = sqrt(type_parameters[i][1] * type_parameters[j][1])
a = float(self._raw_data['LENNARD_JONES_ACOEF'][index])
......@@ -477,6 +482,7 @@ class PrmtopLoader(object):
typ1 = atomTypeIndexes[iAtom] - 1
typ2 = atomTypeIndexes[lAtom] - 1
idx = nbidx[numTypes*typ1+typ2] - 1
if idx < 0: continue
a = parm_acoef[idx]
b = parm_bcoef[idx]
try:
......@@ -645,7 +651,7 @@ class PrmtopLoader(object):
# AMBER System builder (based on, but not identical to, systemManager from 'zander')
#=============================================================================================
def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmodel=None,
def readAmberSystem(topology, prmtop_filename=None, prmtop_loader=None, shake=None, gbmodel=None,
soluteDielectric=1.0, solventDielectric=78.5,
implicitSolventKappa=0.0*(1/units.nanometer), nonbondedCutoff=None,
nonbondedMethod='NoCutoff', scee=None, scnb=None, mm=None, verbose=False,
......@@ -653,6 +659,9 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
"""
Create an OpenMM System from an Amber prmtop file.
REQUIRED ARGUMENT
topology (forcefield.Topology) The topology for the system that is about
to be created
ARGUMENTS (specify one or the other, but not both)
prmtop_filename (String) - name of Amber prmtop file (new-style only)
prmtop_loader (PrmtopLoader) - the loaded prmtop file
......@@ -733,7 +742,7 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
system.addParticle(mass)
# Add constraints.
isWater = [prmtop.getResidueLabel(i) in ('WAT', 'TP4', 'TP5', 'T4E') for i in range(prmtop.getNumAtoms())]
isWater = [prmtop.getResidueLabel(i) in ('WAT', 'HOH', 'TP4', 'TP5', 'T4E') for i in range(prmtop.getNumAtoms())]
if shake in ('h-bonds', 'all-bonds', 'h-angles'):
for (iAtom, jAtom, k, rMin) in prmtop.getBondsWithH():
system.addConstraint(iAtom, jAtom, rMin)
......@@ -768,13 +777,14 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
distance = c[2].value_in_unit(units.nanometer)
atomConstraints[c[0]].append((c[1], distance))
atomConstraints[c[1]].append((c[0], distance))
topatoms = list(topology.atoms())
for (iAtom, jAtom, kAtom, k, aMin) in prmtop.getAngles():
if shake == 'h-angles':
type1 = prmtop.getAtomType(iAtom)
type2 = prmtop.getAtomType(jAtom)
type3 = prmtop.getAtomType(kAtom)
numH = len([type for type in (type1, type3) if type.startswith('H')])
constrained = (numH == 2 or (numH == 1 and type2.startswith('O')))
atomI = topatoms[iAtom]
atomJ = topatoms[jAtom]
atomK = topatoms[kAtom]
numH = ((atomI.element.atomic_number == 1) + (atomK.element.atomic_number == 1))
constrained = (numH == 2 or (numH == 1 and atomJ.element is elem.oxygen))
else:
constrained = False
if constrained:
......@@ -870,6 +880,7 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
for i in range(numTypes):
for j in range(numTypes):
idx = nbidx[numTypes*i+j] - 1
if idx < 0: continue
acoef[i+numTypes*j] = sqrt(parm_acoef[idx]) * afac
bcoef[i+numTypes*j] = parm_bcoef[idx] * bfac
if has_1264:
......@@ -878,6 +889,7 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
for i in range(numTypes):
for j in range(numTypes):
idx = nbidx[numTypes*i+j] - 1
if idx < 0: continue
ccoef[i+numTypes*j] = parm_ccoef[idx] * cfac
cforce = mm.CustomNonbondedForce('(a/r6)^2-b/r6-c/r^4; r6=r^6;'
'a=acoef(type1, type2);'
......@@ -911,6 +923,7 @@ def readAmberSystem(prmtop_filename=None, prmtop_loader=None, shake=None, gbmode
for i in range(numTypes):
for j in range(numTypes):
idx = nbidx[numTypes*i+j] - 1
if idx < 0: continue
ccoef[i+numTypes*j] = parm_ccoef[idx] * cfac
cforce = mm.CustomNonbondedForce('-c/r^4; c=ccoef(type1, type2)')
cforce.addTabulatedFunction('ccoef',
......
......@@ -375,12 +375,13 @@ class AtomList(TrackedList):
class Residue(object):
""" Residue class """
def __init__(self, resname, idx):
def __init__(self, resname, idx, inscode=''):
self.resname = resname
self.idx = idx
self.atoms = []
self.resnum = None # Numbered based on SYSTEM name
self.system = None
self.inscode = inscode
def add_atom(self, atom):
if self.system is None:
......@@ -416,7 +417,7 @@ class Residue(object):
return self.resname == thing.resname and self.idx == thing.idx
if isinstance(thing, tuple) or isinstance(thing, list):
# Must be resnum, resname
return thing == (self.resname, self.idx)
return thing == (self.resname, self.idx, self.inscode)
return False # No other type can be equal.
def __ne__(self, thing):
......@@ -447,7 +448,7 @@ class ResidueList(list):
resnum += 1
def add_atom(self, system, resnum, resname, name,
attype, charge, mass, props=None):
attype, charge, mass, inscode, props=None):
"""
Adds an atom to the list of residues. If the residue is not the same as
the last residue that was created, a new Residue is created and added
......@@ -461,25 +462,22 @@ class ResidueList(list):
- attype (int or str) : Type of the atom
- charge (float) : Partial atomic charge of the atom
- mass (float) : Mass (amu) of the atom
- inscode (str) : Insertion code, if it is specified
Returns:
The Atom instance created and added to the list of residues
"""
if self._last_residue is None:
res = self._last_residue = Residue(resname, resnum)
lr = self._last_residue
if lr is None:
res = self._last_residue = Residue(resname, resnum, inscode)
list.append(self, res)
elif (self._last_residue != (resname, resnum) or
system != self._last_residue.system):
if (self._last_residue.idx == resnum and
self._last_residue.system == system):
lresname = self._last_residue.resname
warnings.warn('Residue %d split into separate residues %s '
'and %s' % (resnum, lresname, resname),
SplitResidueWarning)
res = self._last_residue = Residue(resname, resnum)
elif (lr.resname != resname or lr.idx != resname or
lr.inscode != inscode or system != lr.system):
res = self._last_residue = Residue(resname, resnum, inscode)
res.system = system
list.append(self, res)
else:
res = self._last_residue
res = lr
atom = Atom(system, name, attype, float(charge), float(mass), props)
res.add_atom(atom)
return atom
......
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