Skip to content

Commit

Permalink
merge update
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmkrieger committed Nov 5, 2023
2 parents a94b5d6 + 27e38ba commit cba8c56
Show file tree
Hide file tree
Showing 72 changed files with 88,627 additions and 498 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["2.7", "3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["2.7", "3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v2
Expand All @@ -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
16 changes: 16 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,19 @@ with ProDy. The original CE method was developed by Ilya Shindyalov and Philip
Bourne. The Python version which is used by ProDy is developed by Jason Vertrees
and available under the New BSD license.

Hbp module: The calculation of hydrophobic interactions, solvent accessible surface
area (SASA) and volume for each residue is using geometric methods based on the
information of the atoms in the molecule. The methods have been programmed in C++
and can be compiled as a python module “hpb.so” which is then used by ProDy.
Files for compilation are stored at prody/proteins/hpbmodule folder and
required C++ and Fortran compiler. After compilation hpb.so file can be
stored in prody/proteins folder in ProDy or in the local directory which
is used to perform calulations. The precompiled versions for Python 2.7,
3.8, 3.9, and 3.10 are availabe in prody/proteins/hpbmodule. The user can
choose the correct version of hpb.so and copy to the prody/proteins or
local directory.
C++ code of hpb.so was developed by Xin Cao and Fortran code by Xin Cao,
Michelle H. Hummel, Bihua Yu, and Evangelos A. Coutsias (License in
prody/proteins/hpbmodule folder). Details of the method can be found
in the Supplementary Material of InSty manuscript
(soon will be submitted for publication).
2 changes: 1 addition & 1 deletion docs/docs
6 changes: 6 additions & 0 deletions docs/reference/proteins/interactions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Interactions Tools
======================

.. automodule:: prody.proteins.interactions
:members:
:undoc-members:
4 changes: 2 additions & 2 deletions prody/apps/prody_apps/prody_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def prody_select(selstr, *pdbs, **kwargs):
prefix = kwargs.get('prefix', None)
suffix = kwargs.get('suffix', '_selected')
output = kwargs.get('output', None)
altloc = kwargs.get('altloc', None)
altloc = kwargs.get('altloc', 'all')

for pdb in pdbs:
pdb = parsePDB(pdb, altloc=altloc)
Expand Down Expand Up @@ -83,7 +83,7 @@ def addCommand(commands):
type=str, help=('output filename prefix (default: PDB filename)'))

group.add_argument('-L', '--altloc', dest='altloc', metavar='STR',
type=str, help=('altloc (default: None (take all))'))
type=str, default='all', help=('altloc (default: %(default)s)'))

group.add_argument('-x', '--suffix', dest='suffix', metavar='STR',
type=str, default='_selected',
Expand Down
21 changes: 21 additions & 0 deletions prody/atomic/atom.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,27 @@ def setCoords(self, coords):
self._ag._coords[acsi, self._index] = coords
self._ag._setTimeStamp(acsi)

def getAnisou(self):
"""Returns a copy of anisotropic temperature factors of the atom from the active coordinate
set."""

if self._ag._anisous is not None:
return self._ag._anisous[self.getACSIndex(), self._index].copy()

def _getAnisou(self):
"""Returns a view of anisotropic temperature factors of the atom from the active coordinate
set."""

if self._ag._anisous is not None:
return self._ag._anisous[self.getACSIndex(), self._index]

def setAnisou(self, anisou):
"""Set anisotropic temperature factors of the atom in the active coordinate set."""

acsi = self.getACSIndex()
self._ag._anisous[acsi, self._index] = anisou
self._ag._setTimeStamp(acsi)

def getCoordsets(self, indices=None):
"""Returns a copy of coordinate set(s) at given *indices*."""

Expand Down
115 changes: 112 additions & 3 deletions prody/atomic/atomgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

from prody import LOGGER, PY2K
from prody.kdtree import KDTree
from prody.utilities import checkCoords, rangeString, getDistance, copy
from prody.utilities import (checkCoords, checkAnisous,
rangeString, getDistance, copy)

from .atomic import Atomic
from .fields import ATOMIC_FIELDS, READONLY
Expand Down Expand Up @@ -130,7 +131,7 @@ class AtomGroup(Atomic):
'_donors', '_acceptors', '_nbexclusions', '_crossterms',
'_cslabels', '_acsi', '_n_csets', '_data',
'_fragments', '_flags', '_flagsts', '_subsets',
'_msa', '_sequenceMap']
'_msa', '_sequenceMap', '_anisous']

def __init__(self, title='Unnamed'):

Expand Down Expand Up @@ -170,6 +171,7 @@ def __init__(self, title='Unnamed'):
self._subsets = None
self._msa = None
self._sequenceMap = None
self._anisous = None

def __repr__(self):

Expand Down Expand Up @@ -238,12 +240,20 @@ def __add__(self, other):
if self._n_csets:
if self._n_csets == other._n_csets:
new.setCoords(np.concatenate((self._coords, other._coords), 1))
this = self._anisous
that = other._anisous
if this is not None and that is not None:
if (isinstance(this, np.ndarray) and isinstance(that, np.ndarray)
and len(this) > 0 and len(that) > 0):
new.setAnisous(np.concatenate((self._anisous, other._anisous), 1))
if self._n_csets > 1:
LOGGER.info('All {0} coordinate sets are copied to '
'{1}.'.format(self._n_csets, new.getTitle()))
else:
new.setCoords(np.concatenate((self._getCoords(),
other._getCoords())))
new.setAnisous(np.concatenate((self.getAnisous(),
other.getAnisous())))
LOGGER.info('Active coordinate sets are copied to {0}.'
.format(new.getTitle()))
elif other._n_csets:
Expand Down Expand Up @@ -565,7 +575,101 @@ def _setCoords(self, coords, label='', overwrite=False):
self._setTimeStamp(acsi)
self._cslabels[acsi] = str(label)

def addCoordset(self, coords, label=None):
def getAnisous(self):
"""Returns a copy of anisotropic temperature factors from active coordinate set."""

if self._anisous is not None:
return self._anisous[self._acsi].copy()

def _getAnisous(self):
"""Returns a view of anisotropic temperature factors from active coordinate set."""

if self._anisous is not None:
return self._anisous[self._acsi]

def setAnisous(self, anisous, label=''):
"""Set anisotropic temperature factors of atoms. *anisous* may be any array like object
or an object instance with :meth:`getAnisous` method. If the shape of
anisou array is ``(n_csets > 1, n_atoms, 3)``, it will replace all
coordinate sets and the active coordinate set index will reset to
zero. This situation can be avoided using :meth:`addCoordset`.
If shape of *coords* is ``(n_atoms, 3)`` or ``(1, n_atoms, 3)``, it
will replace the active coordinate set. *label* argument may be used
to label coordinate set(s). *label* may be a string or a list of
strings length equal to the number of coordinate sets."""

atoms = anisous
try:
if self._anisous is None and hasattr(atoms, '_getAnisous'):
anisous = atoms._getAnisous()
else:
anisous = atoms.getAnisous()
except AttributeError:
if self._anisous is None:
anisous = np.array(anisous)
else:
if anisous is None:
raise ValueError('anisous of {0} are not set'
.format(str(atoms)))

try:
checkAnisous(anisous, csets=True, dtype=(float, np.float32))
except TypeError:
raise TypeError('anisous must be a numpy array or an '
'object with `getAnisous` method')

self._setAnisous(anisous, label=label)

def _setAnisous(self, anisous, label='', overwrite=False):
"""Set anisotropic temperature factors without data type checking.
*anisous* must be a :class:`~numpy.ndarray`, but may have data type
other than :class:`~numpy.float64`, e.g. :class:`~numpy.float32`.
*label* argument may be used to label coordinate sets. *label* may be
a string or a list of strings length equal to the number of
coordinate sets."""

n_atoms = self._n_atoms
if n_atoms:
if anisous.shape[-2] != n_atoms:
raise ValueError('anisous array has incorrect number of atoms')
else:
self._n_atoms = n_atoms = anisous.shape[-2]

ndim = anisous.ndim
shape = anisous.shape
if self._anisous is None or overwrite or (ndim == 6 and shape[0] > 1):
if ndim == 2:
self._anisous = anisous.reshape((1, n_atoms, 6))
self._cslabels = [str(label)]
self._n_csets = n_csets = 1

else:
self._anisous = anisous
self._n_csets = n_csets = shape[0]

if isinstance(label, list):
if len(label) == n_csets:
self._cslabels = list(label)

else:
self._cslabels = [''] * n_csets
LOGGER.warn('Number of labels does not match number '
'of coordinate sets.')
else:
self._cslabels = [str(label)] * n_csets
self._acsi = 0
self._setTimeStamp()

else:
acsi = self._acsi
if ndim == 2:
self._anisous[acsi] = anisous
else:
self._anisous[acsi] = anisous[0]
self._setTimeStamp(acsi)
self._cslabels[acsi] = str(label)

def addCoordset(self, coords, label=None, anisous=None):
"""Add a coordinate set. *coords* argument may be an object with
:meth:`getCoordsets` method."""

Expand Down Expand Up @@ -594,8 +698,13 @@ def addCoordset(self, coords, label=None):
if coords.ndim == 2:
coords = coords.reshape((1, n_atoms, 3))

if anisous is not None and anisous.ndim == 2:
anisous = anisous.reshape((1, n_atoms, 6))

diff = coords.shape[0]
self._coords = np.concatenate((self._coords, coords), axis=0)
if anisous is not None and self._anisous is not None:
self._anisous = np.concatenate((self._anisous, anisous/10000), axis=0)
self._n_csets = self._coords.shape[0]
timestamps = self._timestamps
self._timestamps = np.zeros(self._n_csets)
Expand Down
2 changes: 0 additions & 2 deletions prody/atomic/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,6 @@ def getDocstr(self, meth, plural=True, selex=True):
'altloc': Field('altloc', DTYPE + '1',
doc='alternate location indicator',
selstr=('altloc A B', 'altloc _'),),
'anisou': Field('anisou', float, doc='anisotropic temperature factor',
ndim=2),
'chain': Field('chain', DTYPE + '6', doc='chain identifier',
meth='Chid', none=HVNONE, synonym='chid',
selstr=('chain A', 'chid A B C', 'chain _')),
Expand Down
13 changes: 12 additions & 1 deletion prody/atomic/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,7 @@ def _and2(self, sel, loc, tokens, subset=None):
isDataLabel = atoms.isDataLabel
append = None
wasand = False
wasdata = False
while tokens:
# check whether token is an array to avoid array == str comparison
token = tokens.pop(0)
Expand All @@ -1354,9 +1355,10 @@ def _and2(self, sel, loc, tokens, subset=None):
.format(repr('and ... and')), ['and', 'and'])
append = None
wasand = True
wasdata = False
continue

elif isFlagLabel(token):
elif isFlagLabel(token) and not wasdata:
flags.append(token)
append = None

Expand Down Expand Up @@ -1396,10 +1398,12 @@ def _and2(self, sel, loc, tokens, subset=None):
evals.append([])
append = evals[-1].append
append(token)
wasdata = True

elif token in UNARY:
unary.append([])
append = unary[-1].append
wasdata = False

if token == 'not':
append((token,))
Expand Down Expand Up @@ -2420,3 +2424,10 @@ def _getCoords(self):
if self._coords is None:
self._coords = self._atoms._getCoords()
return self._coords

def _getAnisous(self):
"""Returns anisotropic temperature factors of atoms."""

if self._anisous is None:
self._anisous = self._atoms._getAnisous()
return self._anisous
16 changes: 16 additions & 0 deletions prody/atomic/subset.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,29 @@ def getCoords(self):

_getCoords = getCoords

def getAnisous(self):
"""Returns a copy of anisotropic temperature factors from the active coordinate set."""

if self._ag._anisous is not None:
# Since this is not slicing, a view is not returned
return self._ag._anisous[self.getACSIndex(), self._indices]

_getAnisous = getAnisous

def setCoords(self, coords):
"""Set coordinates in the active coordinate set."""

if self._ag._coords is not None:
self._ag._coords[self.getACSIndex(), self._indices] = coords
self._ag._setTimeStamp(self.getACSIndex())

def setAnisous(self, anisous):
"""Set anisotropic temperature factors in the active coordinate set."""

if self._ag._anisous is not None:
self._ag._anisous[self.getACSIndex(), self._indices] = anisous
self._ag._setTimeStamp(self.getACSIndex())

def getCoordsets(self, indices=None):
"""Returns coordinate set(s) at given *indices*, which may be an integer
or a list/array of integers."""
Expand Down
14 changes: 12 additions & 2 deletions prody/database/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
* :func:`.fetchPfamMSA` - download MSA files
* :func:`.searchPfam` - search for domain families of a protein
.. _Pfam: http://pfam.sanger.ac.uk/
.. _Pfam: https://www.ebi.ac.uk/interpro/entry/pfam/
UniProt
========
Expand Down Expand Up @@ -70,7 +69,14 @@
.. _GOA: https://www.ebi.ac.uk/GOA/
Interpro
====
The following functions can be used to search and retrieve Pfam_ data:
* :func:`.searchInterpro` - search for domain families of a protein
.. _Pfam: https://www.ebi.ac.uk/interpro/
"""

__all__ = []
Expand Down Expand Up @@ -98,3 +104,7 @@
from . import quartataweb
from .quartataweb import *
__all__.extend(quartataweb.__all__)

from . import interpro
from .interpro import *
__all__.extend(interpro.__all__)
Loading

0 comments on commit cba8c56

Please sign in to comment.