import unittest from simtk.openmm.app import * from simtk.openmm import * from simtk.unit import * import simtk.openmm.app.forcefield as forcefield import math try: from cStringIO import StringIO except ImportError: from io import StringIO import os class TestPatches(unittest.TestCase): """Test ForceFields that use patches.""" def testParsePatch(self): """Test parsing a tag.""" xml = """ """ ff = ForceField(StringIO(xml)) self.assertEqual(1, len(ff._patches)) patch = ff._patches['Test'] self.assertEqual(1, len(patch.addedAtoms)) self.assertEqual(1, len(patch.addedAtoms[0])) self.assertEqual(1, len(patch.changedAtoms)) self.assertEqual(1, len(patch.changedAtoms[0])) self.assertEqual(1, len(patch.deletedAtoms)) self.assertEqual(1, len(patch.addedBonds)) self.assertEqual(1, len(patch.deletedBonds)) self.assertEqual(1, len(patch.addedExternalBonds)) self.assertEqual(1, len(patch.deletedExternalBonds)) self.assertEqual(1, len(ff._templatePatches)) self.assertEqual(1, len(ff._templatePatches['RES'])) self.assertEqual('A', patch.addedAtoms[0][0].name) self.assertEqual('A type', patch.addedAtoms[0][0].type) self.assertEqual('B', patch.changedAtoms[0][0].name) self.assertEqual('B type', patch.changedAtoms[0][0].type) self.assertEqual('C', patch.deletedAtoms[0].name) self.assertEqual(0, patch.deletedAtoms[0].residue) self.assertEqual('A', patch.addedBonds[0][0].name) self.assertEqual(0, patch.addedBonds[0][0].residue) self.assertEqual('B', patch.addedBonds[0][1].name) self.assertEqual(0, patch.addedBonds[0][1].residue) self.assertEqual('B', patch.deletedBonds[0][0].name) self.assertEqual(0, patch.deletedBonds[0][0].residue) self.assertEqual('C', patch.deletedBonds[0][1].name) self.assertEqual(0, patch.deletedBonds[0][1].residue) self.assertEqual('A', patch.addedExternalBonds[0].name) self.assertEqual(0, patch.addedExternalBonds[0].residue) self.assertEqual('C', patch.deletedExternalBonds[0].name) self.assertEqual(0, patch.deletedExternalBonds[0].residue) patch = list(ff._templatePatches['RES'])[0] self.assertEqual('Test', patch[0]) self.assertEqual(0, patch[1]) def testParseMultiresiduePatch(self): """Test parsing a tag that affects two residues.""" xml = """ """ ff = ForceField(StringIO(xml)) self.assertEqual(1, len(ff._patches)) patch = ff._patches['Test'] self.assertEqual(2, len(patch.addedAtoms)) self.assertEqual(1, len(patch.addedAtoms[0])) self.assertEqual(0, len(patch.addedAtoms[1])) self.assertEqual(2, len(patch.changedAtoms)) self.assertEqual(0, len(patch.changedAtoms[0])) self.assertEqual(1, len(patch.changedAtoms[1])) self.assertEqual(1, len(patch.addedBonds)) self.assertEqual(2, len(ff._templatePatches)) self.assertEqual(1, len(ff._templatePatches['RESA'])) self.assertEqual(1, len(ff._templatePatches['RESB'])) self.assertEqual('A', patch.addedAtoms[0][0].name) self.assertEqual('A type', patch.addedAtoms[0][0].type) self.assertEqual('B', patch.changedAtoms[1][0].name) self.assertEqual('B type', patch.changedAtoms[1][0].type) self.assertEqual('A', patch.addedBonds[0][0].name) self.assertEqual(0, patch.addedBonds[0][0].residue) self.assertEqual('B', patch.addedBonds[0][1].name) self.assertEqual(1, patch.addedBonds[0][1].residue) patchA = list(ff._templatePatches['RESA'])[0] self.assertEqual('Test', patchA[0]) self.assertEqual(0, patchA[1]) patchB = list(ff._templatePatches['RESB'])[0] self.assertEqual('Test', patchB[0]) self.assertEqual(1, patchB[1]) def testApplyPatch(self): """Test applying a patch to a template.""" xml = """ """ ff = ForceField(StringIO(xml)) self.assertEqual(1, len(ff._patches)) patch = ff._patches['Test'] template = ff._templates['RES'] newTemplates = patch.createPatchedTemplates([template]) self.assertEqual(1, len(newTemplates)) t = newTemplates[0] self.assertEqual(3, len(t.atoms)) self.assertTrue(any(a.name == 'B' and a.type == 'A type' for a in t.atoms)) self.assertTrue(any(a.name == 'C' and a.type == 'C type' for a in t.atoms)) self.assertTrue(any(a.name == 'D' and a.type == 'D type' for a in t.atoms)) indexMap = dict([(a.name, i) for i, a in enumerate(t.atoms)]) self.assertEqual(2, len(t.bonds)) self.assertTrue((indexMap['B'], indexMap['C']) in t.bonds) self.assertTrue((indexMap['B'], indexMap['D']) in t.bonds) self.assertEqual(1, len(t.externalBonds)) self.assertTrue(indexMap['D'] in t.externalBonds) self.assertEqual(1, len(t.virtualSites)) v = t.virtualSites[0] self.assertEqual('average2', v.type) self.assertEqual(0.6, v.weights[0]) self.assertEqual(0.4, v.weights[1]) self.assertEqual(indexMap['C'], v.index) self.assertEqual(indexMap['B'], v.atoms[0]) self.assertEqual(indexMap['C'], v.atoms[1]) def testAlaAlaAla(self): """Test constructing a System that involves two patches.""" xml = """ """ ff = ForceField(StringIO(xml)) pdb = PDBFile(os.path.join('systems', 'ala_ala_ala.pdb')) system = ff.createSystem(pdb.topology) nb = system.getForce(0) expectedCharges = [0.1414, 0.2719, 0.2719, 0.2719, 0.0337, 0.0823, 0.0337, 0.0603, 0.0603, 0.0603, 0.5973, -0.5679, -0.4157, 0.2719, 0.0337, 0.0823, 0.0337, 0.0603, 0.0603, 0.0603, 0.5973, -0.5679, 0.5973, -0.8055, -0.8055, -0.4157, 0.2719, 0.0337, 0.0823, 0.0337, 0.0603, 0.0603, 0.0603] for i in range(system.getNumParticles()): self.assertEqual(expectedCharges[i], nb.getParticleParameters(i)[0].value_in_unit(elementary_charge)) def testDisulfidePatch(self): pdb = PDBFile(os.path.join('systems', 'bpti.pdb')) ff = ForceField('amber99sb.xml') system1 = ff.createSystem(pdb.topology) # Override the CYX template so it will no longer match. xml = """ """ ff.loadFile(StringIO(xml)) try: ff.createSystem(pdb.topology) failed = False except: failed = True self.assertTrue(failed) # Now add a patch for matching disulfides. xml = """ """ ff.loadFile(StringIO(xml)) system2 = ff.createSystem(pdb.topology) self.assertEqual(XmlSerializer.serialize(system1), XmlSerializer.serialize(system2)) if __name__ == '__main__': unittest.main()