Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests for water bridges #1761

Merged
merged 12 commits into from
Oct 6, 2023
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ jobs:
echo $CONDA/bin >> $GITHUB_PATH
- name: Install dependencies
run: |
if [[ ${{ matrix.python-version }} == "3.11" ]]; then conda config --add channels conda-forge; fi
if [[ ${{ matrix.python-version }} != "2.7" ]]; then conda config --add channels conda-forge; fi
conda create --yes -n test python=${{ matrix.python-version }}
source activate test
conda install --yes numpy scipy nose pyparsing requests
if [[ ${{ matrix.python-version }} == "2.7" ]]; then conda install --yes unittest2; fi
if [[ ${{ matrix.python-version }} == "2.7" ]]; then conda install --yes unittest2; else conda install --yes pdbfixer; fi
pip install mmtf-python
pip install .
python setup.py build_ext --inplace --force
Expand Down
2 changes: 1 addition & 1 deletion prody/proteins/waterbridges.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ def calcWaterBridges(atoms, **kwargs):
waterBridgesWithIndices, getChainBridgeTuple)

LOGGER.info(
f'{len(waterBridgesWithIndices)} water bridges detected.')
f'{len(waterBridgesWithIndices)} water bridges detected using method {method}.')
if method == 'atomic':
LOGGER.info('Call getInfoOutput to convert atomic to info output.')

Expand Down
16 changes: 15 additions & 1 deletion prody/tests/datafiles/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@
'n_atoms': 683,
'models': 1
},
'1ubi_addH': {
'pdb': '1ubi',
'file': 'pdb_addH_1ubi.pdb',
'n_atoms': 1474,
'models': 1,
'n_h': 791
},
'1ubi_mmtf': {
'pdb': '1UBI',
'file': '1ubi.mmtf',
Expand Down Expand Up @@ -84,7 +91,14 @@
'file': 'pdb3enl.pdb',
'n_atoms': 7294,
'models': 1
},
},
'3enl_addH': {
'pdb': '3enl',
'file': 'addH_pdb3enl.pdb',
'n_atoms': 7641,
'models': 1,
'n_h': 3999
},
'3enl_mmtf': {
'pdb': '3ENL',
'file': 'mmtf3enl.mmtf',
Expand Down
7,646 changes: 7,646 additions & 0 deletions prody/tests/datafiles/addH_pdb3enl.pdb

Large diffs are not rendered by default.

1,479 changes: 1,479 additions & 0 deletions prody/tests/datafiles/pdb_addH_1ubi.pdb

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions prody/tests/proteins/test_fixer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""This module contains unit tests for :mod:`~prody.proteins`."""

from numpy.testing import *
try:
import numpy.testing.decorators as dec
except ImportError:
from numpy.testing import dec

from prody import *
from prody import LOGGER
from prody.tests import unittest
from prody.tests.datafiles import *

import os

LOGGER.verbosity = 'none'

PATH_1UBI = pathDatafile('1ubi')
SPLIT_PATH = os.path.split(PATH_1UBI)
EXPECT_PATH = os.path.join(SPLIT_PATH[0], 'addH_' + SPLIT_PATH[1])

class TestFixer(unittest.TestCase):

def setUp(self):
"""Set PDB file data and parse the PDB file."""

self.ubi_orig = DATA_FILES['1ubi']
self.ubi_addH = DATA_FILES['1ubi_addH']

@dec.slow
def testPDBFixer(self):

if prody.PY3K:
self.filename = addMissingAtoms(PATH_1UBI, method='pdbfixer')
self.assertEqual(self.filename, EXPECT_PATH,
'addMissing atoms wrote the file in the wrong place')

atoms = parsePDB(self.filename)
self.assertEqual(len(atoms.hydrogen), DATA_FILES['1ubi_addH']['n_h'],
'addMissing atoms did not add the right number of hydrogens')
144 changes: 144 additions & 0 deletions prody/tests/proteins/test_waterbridges.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""This module contains unit tests for :mod:`~prody.proteins`."""

import numpy as np
from numpy.testing import *
try:
import numpy.testing.decorators as dec
except ImportError:
from numpy.testing import dec

from prody import *
from prody import LOGGER
from prody.tests import unittest
from prody.tests.datafiles import *

import os

LOGGER.verbosity = 'none'

PATH_PDB = pathDatafile('3enl_addH')
SPLIT_PATH = os.path.split(PATH_PDB)
TARGET_PATH = os.path.join(SPLIT_PATH[0], 'wb_cluster_' + SPLIT_PATH[1])

class TestWaterBridges(unittest.TestCase):

def setUp(self):
"""Parse the PDB file and run the core calculations."""
self.atoms = parsePDB(PATH_PDB)

if prody.PY3K:
self.waterBridgesChain = calcWaterBridges(self.atoms)
self.chainMultiWater = self.waterBridgesChain[37]

self.waterBridgesClust = calcWaterBridges(self.atoms, method='cluster')
self.clustMultiWater = self.waterBridgesClust[36]

self.waterBridgesClustInfo = calcWaterBridges(self.atoms, method='cluster',
output='info')
self.clustInfoMultiWater = self.waterBridgesClustInfo[36]

self.pro0 = self.clustMultiWater.proteins[0]
self.pro1 = self.clustMultiWater.proteins[1]
self.w0 = self.clustMultiWater.waters[0]
self.w1 = self.clustMultiWater.waters[1]

@dec.slow
def testSingleWaterBridgesChain(self):
if prody.PY3K:
self.assertIsInstance(self.waterBridgesChain, list,
'calcWaterBridges chain output should be a list')

self.assertEqual(len(self.waterBridgesChain), 77,
'calcWaterBridges chain list should have 77 items')


self.assertIsInstance(self.chainMultiWater, prody.proteins.waterbridges.AtomicOutput,
'calcWaterBridges output should contain AtomicOutput')

self.assertEqual(len(self.chainMultiWater.proteins), 2,
'water bridges chains should have 2 protein items')
self.assertIsInstance(self.chainMultiWater.proteins[0], Atom,
'protein items in water bridges chains should be Atom')

self.assertEqual(len(self.chainMultiWater.waters), 2,
'water bridges chain should have 2 water items')
self.assertIsInstance(self.chainMultiWater.waters[0], Atom,
'waters items in water bridges chains should be Atom')

@dec.slow
def testSingleWaterBridgesCluster(self):
if prody.PY3K:
self.assertIsInstance(self.waterBridgesClust, list,
'calcWaterBridges clust output should be a list')

self.assertEqual(len(self.waterBridgesClust), 74,
'calcWaterBridges clust list should have 74 items')

self.assertIsInstance(self.clustMultiWater, prody.proteins.waterbridges.AtomicOutput,
'calcWaterBridges output should contain AtomicOutput')

self.assertEqual(len(self.clustMultiWater.proteins), 2,
'tested water bridges multi-water cluster should have 3 protein items')
self.assertIsInstance(self.clustMultiWater.proteins[0], Atom,
'protein items in water bridges clusters should be Atom')

self.assertEqual(len(self.clustMultiWater.waters), 2,
'tested water bridges multi-water cluster should have 2 waters items')
self.assertIsInstance(self.clustMultiWater.waters[0], Atom,
'waters items in water bridges clusters should be Atom')

@dec.slow
def testSaveWaterBridges(self):
if prody.PY3K:
savePDBWaterBridges(self.waterBridgesClust, self.atoms, TARGET_PATH)
self.saved = parsePDB(TARGET_PATH)

self.assertFalse(np.allclose(self.atoms.protein.getBetas(), self.saved.protein.getBetas()),
'savePDBWaterBridges did not change protein b-factors')

self.assertFalse(np.allclose(self.atoms.protein.getOccupancies(), self.saved.protein.getOccupancies()),
'savePDBWaterBridges did not change protein occupancies')

self.assertFalse(np.equal(self.atoms.water.numAtoms(), self.saved.water.numAtoms()),
'savePDBWaterBridges did not change the number of water atoms')

@dec.slow
def testSingleWaterBridgesOutputInfo(self):
if prody.PY3K:
self.assertIsInstance(self.waterBridgesClustInfo, list,
'calcWaterBridges clust info output should be a list')

self.assertEqual(len(self.waterBridgesClustInfo), 74,
'calcWaterBridges clust info list should have 74 items')

self.assertIsInstance(self.clustInfoMultiWater, list,
'tested water bridges multi-water cluster info output should contain lists')

self.assertEqual(len(self.clustInfoMultiWater), 9,
'tested water bridges multi-water cluster info should have 9 items')
self.assertIsInstance(self.clustInfoMultiWater[0], str,
'info items in water bridges clusters should be str')


self.assertEqual(self.clustInfoMultiWater[0], self.pro0.getResname() + str(self.pro0.getResnum()),
'item 0 from selected info should be resname + resnum of atom 0')
self.assertEqual(self.clustInfoMultiWater[1], self.pro0.getName() + '_' + str(self.pro0.getIndex()),
'item 1 from selected info should be name + _ + index of atom 0')
self.assertEqual(self.clustInfoMultiWater[2], self.pro0.getChid(),
'item 2 from selected info should be chid of atom 0')

self.assertEqual(self.clustInfoMultiWater[3], self.pro1.getResname() + str(self.pro1.getResnum()),
'item 3 from selected info should be resname + resnum of atom 1')
self.assertEqual(self.clustInfoMultiWater[4], self.pro1.getName() + '_' + str(self.pro1.getIndex()),
'item 4 from selected info should be name + _ + index of atom 1')
self.assertEqual(self.clustInfoMultiWater[5], self.pro1.getChid(),
'item 5 from selected info should be chid of atom 1')

self.assertEqual(self.clustInfoMultiWater[6], calcDistance(self.pro0, self.pro1),
'item 6 from selected info should be distance from protein atom 0 to protein atom 1')
self.assertEqual(self.clustInfoMultiWater[7], len(self.clustMultiWater.waters),
'item 7 from selected info should be number of waters in the cluster')
self.assertEqual(self.clustInfoMultiWater[8],
list(map(lambda w: w.getChid() + "_" + str(w.getIndex()), self.clustMultiWater.waters)),
'item 8 from selected info should be chid and index for 2 water atoms')