/usr/share/pyshared/cogent/struct/asa.py is in python-cogent 1.5.3-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | """Classes and functions for computing and manipulating accessible
surface areas (ASA)."""
from cogent.app.stride import Stride
from cogent.parse.stride import stride_parser
from cogent.struct.selection import einput
from cogent.struct.annotation import xtradata
from cogent.maths.geometry import sphere_points, coords_to_symmetry, \
coords_to_crystal
from _asa import asa_loop
from numpy import array, r_
__author__ = "Marcin Cieslik"
__copyright__ = "Copyright 2007-2012, The Cogent Project"
__credits__ = ["Marcin Cieslik"]
__license__ = "GPL"
__version__ = "1.5.3"
__maintainer__ = "Marcin Cieslik"
__email__ = "mpc4p@virginia.edu"
__status__ = "Development"
def _run_asa(atoms, lattice_coords, spoints, probe=1.4, bucket_size=5, \
MAXSYM=200000):
"""Runs an ASA calculation. This function takes a selection of atoms
(in the most common case all atoms in a structure) and lattice coordinates
(in the most common a 3x3 box of unit-cells).
This function should be considered low-level and not part of the interface.
Arguments:
- atoms: Holder of atom entities.
- lattice_coords: Numpy array of coordinates.
- spoints: an array of coordinates on the unit sphere, defines the
accuracy of ASA calculation.
- probe: size of the probe i.e. solvent molecule.
- bucket_size: see: ``KDTree``.
- MAXSYM (int): maximum number of symmetry generated atoms.
"""
# get array of radii inflated by probe size of the selection of atoms.
atom_radii = array(atoms.getData('radius', forgiving=False)) + probe
# get array of coordinates
atom_coords = array(atoms.getData('coords', forgiving=False))
# calculate bounding box in a form of an array
search_limit = 2 * (2.0 + probe) # 2.0 is maximum atom radius
atom_box = r_[atom_coords.min(axis=0) - search_limit, \
atom_coords.max(axis=0) + search_limit]
# the lattice coordinates are atom coordinates after transformations in a
# 4D-array this array gets reshaped into an all_atoms x 3 array.
shape = lattice_coords.shape
lattice_coords = \
lattice_coords.reshape((shape[0] * shape[1] * shape[2], shape[3]))
# this calls the cython code which loops over all query atoms, surface
# points, and lattice atoms
return asa_loop(atom_coords, lattice_coords, atom_radii, atom_radii, \
spoints, atom_box, probe, bucket_size, MAXSYM)
def _prepare_entities(entities):
"""Prepares input entities for ASA calculation, which includes masking water
molecules and water chains.
"""
# First we mask all water residues and chains with all residues masked
# (water chains).
lattice_residues = einput(entities, 'R')
lattice_residues.maskChildren('H_HOH', 'eq', 'name')
lattice_chains = einput(entities, 'C')
lattice_chains.maskChildren([], 'eq', 'values', method=True)
# if no residues or chains are left - no atoms to work with,
# abort with warning.
if not lattice_chains.values():
# the following makes sure that masking changes by the above
# tests are reverted.
lattice_structures = einput(entities, 'S')
lattice_structures.setUnmasked(force=True)
raise ValueError('No unmasked atoms to build lattice.')
# these are all atoms we can work with
lattice_atoms = einput(entities, 'A')
lattice_atoms.dispatch('setRadius')
def _postpare_entities(entities):
"""Restores entities after ASA calculation, which includes unmasking."""
structures = einput(entities, 'S')
structures.setUnmasked(force=True)
def _prepare_asa(entities, symmetry_mode=None, crystal_mode=None, points=960, \
**kwargs):
"""Prepares the atomic solvent-accessible surface area (ASA) calculation.
Arguments:
- entities: input entities for ASA calculation (most commondly a
structure entity).
- symmetry_mode (str): One of 'uc', 'bio' or 'table'. This defines the
transformations of applied to the coordinates of the input entities.
It is one of 'bio', 'uc' or 'table'. Where 'bio' and 'uc' are
transformations to create the biological molecule or unit-cell from
the PDB header. The 'table' uses transformation matrices derived from
space-group information only using crystallographic tables(requires
``cctbx``).
- crystal_mode (int): Defines the number of unit-cells to expand the
initial unit-cell into. The number of unit-cells in each direction
i.e. 1 is makes a total of 27 unit cells: (-1, 0, 1) == 3, 3^3 == 27
- points: number of points on atom spheres higher is slower but more
accurate.
Additional keyworded arguments are passed to the ``_run_asa`` function.
"""
# generate uniform points on the unit-sphere
spoints = sphere_points(points)
# prepare entities for asa calculation
# free-floating area mode
result = {}
atoms = einput(entities, 'A')
if not symmetry_mode and not crystal_mode:
coords = array(atoms.getData('coords', forgiving=False))
coords = array([[coords]]) # fake 3D and 4D
idx_to_id = dict(enumerate(atoms.getData('getFull_id', \
forgiving=False, method=True)))
asas = _run_asa(atoms, coords, spoints, **kwargs)
for idx in xrange(asas.shape[0]):
result[idx_to_id[idx]] = asas[idx]
# crystal-contact area mode
elif symmetry_mode in ('table', 'uc'):
structure = einput(entities, 'S').values()[0]
sh = structure.header
coords = array(atoms.getData('coords', forgiving=False))
idx_to_id = dict(enumerate(atoms.getData('getFull_id', \
forgiving=False, method=True)))
# expand to unit-cell, real 3D
coords = coords_to_symmetry(coords, \
sh[symmetry_mode + '_fmx'], \
sh[symmetry_mode + '_omx'], \
sh[symmetry_mode + '_mxs'], \
symmetry_mode)
# expand to crystal, real 4D
if crystal_mode:
coords = coords_to_crystal(coords, \
sh[symmetry_mode + '_fmx'], \
sh[symmetry_mode + '_omx'], \
crystal_mode) # real 4D
else:
coords = array([coords]) # fake 4D
asas = _run_asa(atoms, coords, spoints, **kwargs)
for idx in xrange(asas.shape[0]):
result[idx_to_id[idx]] = asas[idx]
# biological area mode
elif symmetry_mode == 'bio':
structure = einput(entities, 'S').values()[0]
chains = einput(entities, 'C')
sh = structure.header
start = 0
for chain_ids, mx_num in sh['bio_cmx']:
sel = chains.selectChildren(chain_ids, 'contains', 'id').values()
atoms = einput(sel, 'A')
coords = array(atoms.getData('coords', forgiving=False))
idx_to_id = dict(enumerate(atoms.getData('getFull_id', \
forgiving=False, method=True)))
stop = start + mx_num
coords = coords_to_symmetry(coords, \
sh['uc_fmx'], \
sh['uc_omx'], \
sh['bio_mxs'][start:stop], \
symmetry_mode)
coords = array([coords])
start = stop
asas = _run_asa(atoms, coords, spoints, **kwargs)
for idx in xrange(asas.shape[0]):
result[idx_to_id[idx]] = asas[idx]
return result
def asa_xtra(entities, mode='internal', xtra_key=None, **asa_kwargs):
"""Calculates accessible surface areas (ASA) and puts the results into the
xtra dictionaries of entities.
Arguments:
- entities: an entity or sequence of entities
- mode(str): 'internal' for calculations using the built-in cython code
or 'stride' if the stride binary should be called to do the job.
- xtra_key(str): Key in the xtra dictionary to hold the result for each
entity
Additional keyworded arguments are passed to the ``_prepare_asa`` and
``_run_asa`` functions.
"""
xtra_key = xtra_key or 'ASA'
structures = einput(entities, 'S')
if len(structures.values()) > 1:
raise ValueError('Entities from multiple structures are not supported.')
if mode == 'internal':
_prepare_entities(entities) # mask waters
result = _prepare_asa(entities, **asa_kwargs) # calculate ASA
_postpare_entities(entities) # unmask waters
result = dict([(id, {xtra_key:v}) for id, v in result.iteritems()])
xtradata(result, structures)
elif mode == 'stride':
models = einput(entities, 'M')
stride_app = Stride()
result = stride_app(entities)['StdOut'].readlines()
result = stride_parser(result)
xtradata(result, structures.values()[0][(0,)])
else:
raise ValueError('Not a valid mode: "%s"' % mode)
return result
|