Commit 5c646b02 authored by peastman's avatar peastman Committed by GitHub
Browse files

Merge pull request #1668 from peastman/bond

Created Bond class that can store bond type and order
parents b465c982 ebb7a083
...@@ -229,8 +229,8 @@ def buildKeywordDictionary(major_version_num=MAJOR_VERSION_NUM, ...@@ -229,8 +229,8 @@ def buildKeywordDictionary(major_version_num=MAJOR_VERSION_NUM,
def main(): def main():
if sys.version_info < (2, 6): if sys.version_info < (2, 7):
reportError("OpenMM requires Python 2.6 or better.") reportError("OpenMM requires Python 2.7 or better.")
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
macVersion = [int(x) for x in platform.mac_ver()[0].split('.')] macVersion = [int(x) for x in platform.mac_ver()[0].split('.')]
if tuple(macVersion) < (10, 5): if tuple(macVersion) < (10, 5):
......
...@@ -6,7 +6,7 @@ from __future__ import absolute_import ...@@ -6,7 +6,7 @@ from __future__ import absolute_import
__docformat__ = "epytext en" __docformat__ = "epytext en"
__author__ = "Peter Eastman" __author__ = "Peter Eastman"
__copyright__ = "Copyright 2015, Stanford University and Peter Eastman" __copyright__ = "Copyright 2016, Stanford University and Peter Eastman"
__credits__ = [] __credits__ = []
__license__ = "MIT" __license__ = "MIT"
__maintainer__ = "Peter Eastman" __maintainer__ = "Peter Eastman"
...@@ -44,3 +44,10 @@ PME = forcefield.PME ...@@ -44,3 +44,10 @@ PME = forcefield.PME
HBonds = forcefield.HBonds HBonds = forcefield.HBonds
AllBonds = forcefield.AllBonds AllBonds = forcefield.AllBonds
HAngles = forcefield.HAngles HAngles = forcefield.HAngles
Single = topology.Single
Double = topology.Double
Triple = topology.Triple
Aromatic = topology.Aromatic
Amide = topology.Amide
...@@ -36,6 +36,7 @@ from math import sqrt ...@@ -36,6 +36,7 @@ from math import sqrt
from simtk.openmm.app import Topology from simtk.openmm.app import Topology
from simtk.openmm.app import PDBFile from simtk.openmm.app import PDBFile
from simtk.openmm.app.internal import amber_file_parser from simtk.openmm.app.internal import amber_file_parser
from simtk.openmm.app.internal.singleton import Singleton
from . import forcefield as ff from . import forcefield as ff
from . import element as elem from . import element as elem
import simtk.unit as u import simtk.unit as u
...@@ -44,27 +45,27 @@ from simtk.openmm.app.internal.unitcell import computePeriodicBoxVectors ...@@ -44,27 +45,27 @@ from simtk.openmm.app.internal.unitcell import computePeriodicBoxVectors
# Enumerated values for implicit solvent model # Enumerated values for implicit solvent model
class HCT(object): class HCT(Singleton):
def __repr__(self): def __repr__(self):
return 'HCT' return 'HCT'
HCT = HCT() HCT = HCT()
class OBC1(object): class OBC1(Singleton):
def __repr__(self): def __repr__(self):
return 'OBC1' return 'OBC1'
OBC1 = OBC1() OBC1 = OBC1()
class OBC2(object): class OBC2(Singleton):
def __repr__(self): def __repr__(self):
return 'OBC2' return 'OBC2'
OBC2 = OBC2() OBC2 = OBC2()
class GBn(object): class GBn(Singleton):
def __repr__(self): def __repr__(self):
return 'GBn' return 'GBn'
GBn = GBn() GBn = GBn()
class GBn2(object): class GBn2(Singleton):
def __repr__(self): def __repr__(self):
return 'GBn2' return 'GBn2'
GBn2 = GBn2() GBn2 = GBn2()
......
...@@ -45,6 +45,7 @@ import simtk.openmm as mm ...@@ -45,6 +45,7 @@ import simtk.openmm as mm
import simtk.unit as unit import simtk.unit as unit
from . import element as elem from . import element as elem
from simtk.openmm.app import Topology from simtk.openmm.app import Topology
from simtk.openmm.app.internal.singleton import Singleton
def _convertParameterToNumber(param): def _convertParameterToNumber(param):
if unit.is_quantity(param): if unit.is_quantity(param):
...@@ -89,44 +90,44 @@ def _createFunctions(force, functions): ...@@ -89,44 +90,44 @@ def _createFunctions(force, functions):
# Enumerated values for nonbonded method # Enumerated values for nonbonded method
class NoCutoff(object): class NoCutoff(Singleton):
def __repr__(self): def __repr__(self):
return 'NoCutoff' return 'NoCutoff'
NoCutoff = NoCutoff() NoCutoff = NoCutoff()
class CutoffNonPeriodic(object): class CutoffNonPeriodic(Singleton):
def __repr__(self): def __repr__(self):
return 'CutoffNonPeriodic' return 'CutoffNonPeriodic'
CutoffNonPeriodic = CutoffNonPeriodic() CutoffNonPeriodic = CutoffNonPeriodic()
class CutoffPeriodic(object): class CutoffPeriodic(Singleton):
def __repr__(self): def __repr__(self):
return 'CutoffPeriodic' return 'CutoffPeriodic'
CutoffPeriodic = CutoffPeriodic() CutoffPeriodic = CutoffPeriodic()
class Ewald(object): class Ewald(Singleton):
def __repr__(self): def __repr__(self):
return 'Ewald' return 'Ewald'
Ewald = Ewald() Ewald = Ewald()
class PME(object): class PME(Singleton):
def __repr__(self): def __repr__(self):
return 'PME' return 'PME'
PME = PME() PME = PME()
# Enumerated values for constraint type # Enumerated values for constraint type
class HBonds(object): class HBonds(Singleton):
def __repr__(self): def __repr__(self):
return 'HBonds' return 'HBonds'
HBonds = HBonds() HBonds = HBonds()
class AllBonds(object): class AllBonds(Singleton):
def __repr__(self): def __repr__(self):
return 'AllBonds' return 'AllBonds'
AllBonds = AllBonds() AllBonds = AllBonds()
class HAngles(object): class HAngles(Singleton):
def __repr__(self): def __repr__(self):
return 'HAngles' return 'HAngles'
HAngles = HAngles() HAngles = HAngles()
......
"""
Creates a subclass for all classes intended to be a singleton. This
maintains the correctness of instance is instance even following
pickling/unpickling
"""
class Singleton(object):
_inst = None
def __new__(cls):
if cls._inst is None:
cls._inst = super(Singleton, cls).__new__(cls)
return cls._inst
def __reduce__(self):
return repr(self)
...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of ...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of
Biological Structures at Stanford, funded under the NIH Roadmap for Biological Structures at Stanford, funded under the NIH Roadmap for
Medical Research, grant U54 GM072970. See https://simtk.org. Medical Research, grant U54 GM072970. See https://simtk.org.
Portions copyright (c) 2012-2015 Stanford University and the Authors. Portions copyright (c) 2012-2016 Stanford University and the Authors.
Authors: Peter Eastman Authors: Peter Eastman
Contributors: Contributors:
...@@ -32,12 +32,41 @@ from __future__ import absolute_import ...@@ -32,12 +32,41 @@ from __future__ import absolute_import
__author__ = "Peter Eastman" __author__ = "Peter Eastman"
__version__ = "1.0" __version__ = "1.0"
from collections import namedtuple
import os import os
import xml.etree.ElementTree as etree import xml.etree.ElementTree as etree
from simtk.openmm.vec3 import Vec3 from simtk.openmm.vec3 import Vec3
from simtk.openmm.app.internal.singleton import Singleton
from simtk.unit import nanometers, sqrt, is_quantity from simtk.unit import nanometers, sqrt, is_quantity
from copy import deepcopy from copy import deepcopy
# Enumerated values for bond type
class Single(Singleton):
def __repr__(self):
return 'Single'
Single = Single()
class Double(Singleton):
def __repr__(self):
return 'Double'
Double = Double()
class Triple(Singleton):
def __repr__(self):
return 'Triple'
Triple = Triple()
class Aromatic(Singleton):
def __repr__(self):
return 'Aromatic'
Aromatic = Aromatic()
class Amide(Singleton):
def __repr__(self):
return 'Amide'
Amide = Amide()
class Topology(object): class Topology(object):
"""Topology stores the topological information about a system. """Topology stores the topological information about a system.
...@@ -155,7 +184,7 @@ class Topology(object): ...@@ -155,7 +184,7 @@ class Topology(object):
residue._atoms.append(atom) residue._atoms.append(atom)
return atom return atom
def addBond(self, atom1, atom2): def addBond(self, atom1, atom2, type=None, order=None):
"""Create a new bond and add it to the Topology. """Create a new bond and add it to the Topology.
Parameters Parameters
...@@ -164,8 +193,13 @@ class Topology(object): ...@@ -164,8 +193,13 @@ class Topology(object):
The first Atom connected by the bond The first Atom connected by the bond
atom2 : Atom atom2 : Atom
The second Atom connected by the bond The second Atom connected by the bond
type : object=None
The type of bond to add. Allowed values are None, Single, Double, Triple,
Aromatic, or Amide.
order : int=None
The bond order, or None if it is not specified
""" """
self._bonds.append((atom1, atom2)) self._bonds.append(Bond(atom1, atom2, type, order))
def chains(self): def chains(self):
"""Iterate over all Chains in the Topology.""" """Iterate over all Chains in the Topology."""
...@@ -387,7 +421,7 @@ class Residue(object): ...@@ -387,7 +421,7 @@ class Residue(object):
return "<Residue %d (%s) of chain %d>" % (self.index, self.name, self.chain.index) return "<Residue %d (%s) of chain %d>" % (self.index, self.name, self.chain.index)
class Atom(object): class Atom(object):
"""An Atom object represents a residue within a Topology.""" """An Atom object represents an atom within a Topology."""
def __init__(self, name, element, index, residue, id): def __init__(self, name, element, index, residue, id):
"""Construct a new Atom. You should call addAtom() on the Topology instead of calling this directly.""" """Construct a new Atom. You should call addAtom() on the Topology instead of calling this directly."""
...@@ -404,3 +438,32 @@ class Atom(object): ...@@ -404,3 +438,32 @@ class Atom(object):
def __repr__(self): def __repr__(self):
return "<Atom %d (%s) of chain %d residue %d (%s)>" % (self.index, self.name, self.residue.chain.index, self.residue.index, self.residue.name) return "<Atom %d (%s) of chain %d residue %d (%s)>" % (self.index, self.name, self.residue.chain.index, self.residue.index, self.residue.name)
class Bond(namedtuple('Bond', ['atom1', 'atom2'])):
"""A Bond object represents a bond between two Atoms within a Topology.
This class extends tuple, and may be interpreted as a 2 element tuple of Atom objects.
It also has fields that can optionally be used to describe the bond order and type of bond."""
def __new__(cls, atom1, atom2, type=None, order=None):
"""Create a new Bond. You should call addBond() on the Topology instead of calling this directly."""
bond = super(Bond, cls).__new__(cls, atom1, atom2)
bond.type = type
bond.order = order
return bond
def __getnewargs__(self):
"Support for pickle protocol 2: http://docs.python.org/2/library/pickle.html#pickling-and-unpickling-normal-class-instances"
return self[0], self[1], self.type, self.order
def __deepcopy__(self, memo):
return Bond(self[0], self[1], self.type, self.order)
def __repr__(self):
s = "Bond(%s, %s" % (self[0], self[1])
if self.type is not None:
s = "%s, type=%s" % (s, self.type)
if self.order is not None:
s = "%s, order=%d" % (s, self.order)
s += ")"
return s
import pickle
import sys import sys
import unittest import unittest
from simtk.openmm.app import * from simtk.openmm.app import *
...@@ -26,6 +27,14 @@ class TestTopology(unittest.TestCase): ...@@ -26,6 +27,14 @@ class TestTopology(unittest.TestCase):
"""Test getters for number of atoms, residues, chains.""" """Test getters for number of atoms, residues, chains."""
self.check_pdbfile('systems/1T2Y.pdb', 271, 25, 1) self.check_pdbfile('systems/1T2Y.pdb', 271, 25, 1)
def test_bondtype_singleton(self):
""" Tests that the bond types are really singletons """
self.assertIs(Single, pickle.loads(pickle.dumps(Single)))
self.assertIs(Double, pickle.loads(pickle.dumps(Double)))
self.assertIs(Triple, pickle.loads(pickle.dumps(Triple)))
self.assertIs(Aromatic, pickle.loads(pickle.dumps(Aromatic)))
self.assertIs(Amide, pickle.loads(pickle.dumps(Amide)))
def test_residue_bonds(self): def test_residue_bonds(self):
"""Test retrieving bonds for a residue produces expected results.""" """Test retrieving bonds for a residue produces expected results."""
# Create a test topology # Create a test topology
......
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