Source code for fast.analysis.contacts
# Author: Maxwell I. Zimmerman <mizimmer@wustl.edu>
# Contributors:
# Copywright (C) 2017, Washington University in St. Louis
# All rights reserved.
# Unauthorized copying of this file, via any medium, is strictly prohibited
# Proprietary and confidential
#######################################################################
# imports
#######################################################################
import glob
import itertools
import mdtraj as md
import numpy as np
import os
from .base_analysis import base_analysis
from .. import tools
#######################################################################
# code
#######################################################################
[docs]def best_hummer_q(traj, native, verbose=False, native_cutoff=0.45):
"""Compute the fraction of native contacts according the definition from
Best, Hummer and Eaton [1].
Adapted from: 'http://mdtraj.org/latest/examples/native-contact.html'
Parameters
----------
traj : md.Trajectory
The trajectory to do the computation for
native : md.Trajectory
The 'native state'. This can be an entire trajecory, or just a single frame.
Only the first conformation is used
Returns
-------
q : np.array, shape=(len(traj),)
The fraction of native contacts in each frame of `traj`
References
----------
..[1] Best, Hummer, and Eaton, "Native contacts determine protein folding
mechanisms in atomistic simulations" PNAS (2013)
"""
BETA_CONST = 50 # 1/nm
LAMBDA_CONST = 1.8
NATIVE_CUTOFF = native_cutoff # nanometers
# get the indices of all of the heavy atoms
heavy = native.topology.select_atom_indices('heavy')
# get the pairs of heavy atoms which are farther than 3
# residues apart
heavy_pairs = np.array(
[(i,j) for (i,j) in itertools.combinations(heavy, 2)
if abs(native.topology.atom(i).residue.index - \
native.topology.atom(j).residue.index) > 3])
# compute the distances between these pairs in the native state
heavy_pairs_distances = md.compute_distances(native[0], heavy_pairs)[0]
# and get the pairs s.t. the distance is less than NATIVE_CUTOFF
native_contacts = heavy_pairs[heavy_pairs_distances < NATIVE_CUTOFF]
if verbose:
print("Number of native contacts", len(native_contacts))
# now compute these distances for the whole trajectory
r = md.compute_distances(traj, native_contacts)
# and recompute them for just the native state
r0 = md.compute_distances(native[0], native_contacts)
q = np.mean(
1.0 / (1 + np.exp(BETA_CONST * (r - LAMBDA_CONST * r0))), axis=1)
return q
[docs]class ContactsWrap(base_analysis):
"""Analyses the fraction of native contacts.
Parameters
----------
base_struct : str or md.Trajectory,
The base structure to compare for native contacts. This
topology must match the structures to analyse. Can be provided
as a pdb location or an md.Trajectory object.
atom_indices : str or array,
The atom indices to use for computing native contacts. Can be
provided as a data file to load or an array.
Attributes
----------
output_name : str,
The file containing rankings.
"""
def __init__(
self, base_struct, atom_indices=None):
# determine base_struct
self.base_struct = base_struct
if type(base_struct) is md.Trajectory:
self.base_struct_md = self.base_struct
else:
self.base_struct_md = md.load(base_struct)
# determine atom indices
self.atom_indices = atom_indices
if type(atom_indices) is str:
self.atom_indices_vals = np.loadtxt(atom_indices, dtype=int)
else:
self.atom_indices_vals = self.atom_indices
@property
def class_name(self):
return "ContactsWrap"
@property
def config(self):
return {
'base_struct': self.base_struct,
'atom_indices': self.atom_indices,
}
@property
def analysis_folder(self):
return None
@property
def base_output_name(self):
return "contacts_per_state"
[docs] def run(self):
# determine if file already exists
if os.path.exists(self.output_name):
pass
else:
# load centers
centers = md.load(
"./data/full_centers.xtc", top=self.base_struct_md,
atom_indices=self.atom_indices_vals)
# get subset if necessary
if self.atom_indices_vals is None:
struct_sub = self.base_struct_md
else:
struct_sub = self.base_struct_md.atom_slice(self.atom_indices_vals)
# calculate and save contacts
contacts = best_hummer_q(centers, struct_sub)
np.save(self.output_name, contacts)