Skip to content

Commit

Permalink
Merge pull request #673 from MDAnalysis/fixes-ContactAnalysis1
Browse files Browse the repository at this point in the history
Fixes for analysis.contacts.ContactAnalysis1
  • Loading branch information
kain88-de committed Jan 29, 2016
2 parents 481b560 + 5ed8a9a commit 4e4f0fa
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 36 deletions.
42 changes: 17 additions & 25 deletions package/MDAnalysis/analysis/contacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@
The first graph shows that when AdK opens, about 20% of the salt
bridges that existed in the closed state disappear when the enzyme
opens. They open in a step-wise fashion (made more clear by the movie
http://sbcb.bioch.ox.ac.uk/oliver/Movies/AdK/AdK_zipper_cartoon.avi
(divx, on Mac use http://perian.org)).
`AdK_zipper_cartoon.avi`_).
The output graphs can be made prettier but if you look at the code
itself then you'll quickly figure out what to do. The qavg plot is the
Expand All @@ -113,14 +112,17 @@
See the docs for :class:`ContactAnalysis1` for another example.
.. AdK_zipper_cartoon.avi:
http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2803350/bin/NIHMS150766-supplement-03.avi
Two-dimensional contact analysis (q1-q2)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Analyze a single DIMS transition of AdK between its closed and open
conformation and plot the trajectory projected on q1-q2::
import MDAnalysis.analysis.contacts
from MDAnalysis.tests.datafiles import *
from MDAnalysis.tests.datafiles import PSF, DCD
C = MDAnalysis.analysis.contacts.ContactAnalysis(PSF, DCD)
C.run()
C.plot()
Expand Down Expand Up @@ -199,9 +201,9 @@ def __init__(self, topology, trajectory, ref1=None, ref2=None, radius=8.0,
interest; the default is to only select the C-alpha atoms
in *ref1* and *ref*2 ["name CA"]
.. Note:: If *selection* produces more than one atom per
residue then you will get multiple contacts per
residue unless you also set *centroids* = ``True``
.. Note:: If *selection* produces more than one atom per
residue then you will get multiple contacts per
residue unless you also set *centroids* = ``True``
*centroids*
If set to ``True``, use the centroids for the selected atoms on a
per-residue basis to compute contacts. This allows, for instance
Expand Down Expand Up @@ -318,8 +320,6 @@ def run(self, store=True, force=False):
store=True) and writes them to a bzip2-compressed data file.
"""
if self._skip or self.output_exists(force=force):
import warnings

warnings.warn("File {output!r} or {output_bz2!r} already exists, loading {trajectory!r}.".format(**vars(self)))
try:
self.load(self.output)
Expand Down Expand Up @@ -409,11 +409,6 @@ def plot(self, **kwargs):
class ContactAnalysis1(object):
"""Perform a very flexible native contact analysis with respect to a single reference.
.. class:: ContactAnalysis1(topology, trajectory[,selection[,refgroup[,radius[,outfile]]]])
.. class:: ContactAnalysis1(universe[,selection[,refgroup[,radius[,outfile]]]])
This analysis class allows one to calculate the fraction of native contacts
*q* between two arbitrary groups of atoms with respect to an arbitrary
reference structure. For instance, as a reference one could take a crystal
Expand All @@ -425,8 +420,8 @@ class ContactAnalysis1(object):
the reference atoms; this example uses some arbitrary selections::
ref = Universe('crystal.pdb')
refA = re.select_atoms('name CA and segid A and resid 6:100')
refB = re.select_atoms('name CA and segid B and resid 1:40')
refA = ref.select_atoms('name CA and segid A and resid 6:100')
refB = ref.select_atoms('name CA and segid B and resid 1:40')
Load the trajectory::
Expand Down Expand Up @@ -597,7 +592,6 @@ def run(self, store=True, force=False, start=0, stop=None, step=1, **kwargs):
*step*
The number of frames to skip during trajectory iteration (default: use every frame)
"""
import warnings

if 'start_frame' in kwargs:
warnings.warn("start_frame argument has been deprecated, use start instead --"
Expand All @@ -615,8 +609,6 @@ def run(self, store=True, force=False, start=0, stop=None, step=1, **kwargs):
step = kwargs.pop('step_value')

if self.output_exists(force=force):
import warnings

warnings.warn("File %r already exists, loading it INSTEAD of trajectory %r. "
"Use force=True to overwrite the output file. " %
(self.output, self.universe.trajectory.filename))
Expand All @@ -629,11 +621,6 @@ def run(self, store=True, force=False, start=0, stop=None, step=1, **kwargs):
records = []
self.qavg *= 0 # average contact existence
A, B = self.selections
# determine the end_frame value to use:
total_frames = self.universe.trajectory.n_frames
if not stop:
# use the total number of frames in trajectory if no final value specified
end_frame = total_frames
for ts in self.universe.trajectory[start:stop:step]:
frame = ts.frame
# use pre-allocated distance array to save a little bit of time
Expand All @@ -646,8 +633,13 @@ def run(self, store=True, force=False, start=0, stop=None, step=1, **kwargs):
out.write("{frame:4d} {q1:8.6f} {n1:5d}\n".format(**vars()))
if store:
self.timeseries = np.array(records).T
n_frames = len(range(total_frames)[start:stop:step])
self.qavg /= n_frames
n_frames = len(np.arange(
self.universe.trajectory.n_frames)[start:stop:step])
if n_frames > 0:
self.qavg /= n_frames
else:
logger.warn("No frames were analyzed. Check values of start, stop, step.")
logger.debug("start={start} stop={stop} step={step}".format(**vars()))
np.savetxt(self.outarray, self.qavg, fmt="%8.6f")
return self.output

Expand Down
41 changes: 30 additions & 11 deletions testsuite/MDAnalysisTests/analysis/test_contacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,47 @@
from MDAnalysisTests.datafiles import PSF, DCD
from MDAnalysisTests import executable_not_found, parser_not_found

class TestContacts(TestCase):
class TestContactAnalysis1(TestCase):
@dec.skipif(parser_not_found('DCD'),
'DCD parser not available. Are you using python 3?')
def setUp(self):
self.universe = MDAnalysis.Universe(PSF, DCD)
self.trajectory = self.universe.trajectory
self.tempdir = tempdir.TempDir()

def tearDown(self):
del self.universe
del self.trajectory
del self.tempdir

def test_startframe(self):
"""For resolution of Issue #624."""
def _run_ContactAnalysis1(self, **runkwargs):
sel_basic = "(resname ARG or resname LYS) and (name NH* or name NZ)"
sel_acidic = "(resname ASP or resname GLU) and (name OE* or name OD*)"
acidic = self.universe.select_atoms(sel_acidic)
basic = self.universe.select_atoms(sel_basic)
outfile = self.tempdir.name + '/qsalt.dat'
CA1 = MDAnalysis.analysis.contacts.ContactAnalysis1(self.universe,
selection=(sel_acidic, sel_basic), refgroup=(acidic, basic),
radius=6.0, outfile=outfile)
CA1.run(force=True)
self.assertEqual(CA1.timeseries.shape[1], self.universe.trajectory.n_frames)
outfile = 'qsalt.dat'
CA1 = MDAnalysis.analysis.contacts.ContactAnalysis1(
self.universe,
selection=(sel_acidic, sel_basic), refgroup=(acidic, basic),
radius=6.0, outfile=outfile)
kwargs = runkwargs.copy()
kwargs['force'] = True
CA1.run(**kwargs)
return CA1

def test_startframe(self):
"""test_startframe: TestContactAnalysis1: start frame set to 0 (resolution of Issue #624)"""
with tempdir.in_tempdir():
CA1 = self._run_ContactAnalysis1()
self.assertEqual(CA1.timeseries.shape[1], self.universe.trajectory.n_frames)

def test_end_zero(self):
"""test_end_zero: TestContactAnalysis1: stop frame 0 is not ignored"""
with tempdir.in_tempdir():
CA1 = self._run_ContactAnalysis1(stop=0)
self.assertEqual(len(CA1.timeseries), 0)

def test_slicing(self):
start, stop, step = 10, 30, 5
with tempdir.in_tempdir():
CA1 = self._run_ContactAnalysis1(start=start, stop=stop, step=step)
frames = np.arange(self.universe.trajectory.n_frames)[start:stop:step]
self.assertEqual(CA1.timeseries.shape[1], len(frames))

0 comments on commit 4e4f0fa

Please sign in to comment.