Example #1
0
def _reduceModel(matrix, system):
    """This is the underlying function that reduces models, which shall 
    remain private. ``system`` is a boolean array where **True** indicates 
    system nodes."""

    linalg = importLA()

    other = np.invert(system)

    ss = matrix[system, :][:, system]
    so = matrix[system, :][:, other]
    os = matrix[other, :][:, system]
    oo = matrix[other, :][:, other]

    if other.any():
        try:
            invoo = linalg.inv(oo)
        except:
            invoo = linalg.pinv(oo)

        matrix = ss - np.dot(so, np.dot(invoo, os))
    else:
        matrix = ss

    return matrix
Example #2
0
def getTransformation(mob, tar, weights=None):
    
    linalg = importLA()
    
    if weights is None:
        mob_com = mob.mean(0)
        tar_com = tar.mean(0)
        mob = mob - mob_com
        tar = tar - tar_com
        matrix = np.dot(tar.T, mob)
    else:
        weights_sum = weights.sum()
        weights_dot = np.dot(weights.T, weights)
        mob_com = (mob * weights).sum(axis=0) / weights_sum
        tar_com = (tar * weights).sum(axis=0) / weights_sum
        mob = mob - mob_com
        tar = tar - tar_com
        matrix = np.dot((tar * weights).T, (mob * weights)) / weights_dot

    U, s, Vh = linalg.svd(matrix)
    Id = np.array([ [1, 0, 0], 
                    [0, 1, 0], 
                    [0, 0, np.sign(linalg.det(matrix))] ])
    rotation = np.dot(Vh.T, np.dot(Id, U.T))

    return rotation, tar_com - np.dot(mob_com, rotation)
Example #3
0
def _getEigvecs(modes, row_norm=False):
    if isinstance(modes, (ModeSet, NMA)):
        V = modes.getEigvecs()
    elif isinstance(modes, Mode):
        V = modes.getEigvec()
    elif isinstance(modes, np.ndarray):
        V = modes
    else:
        try:
            mode0 = modes[0]
            if isinstance(mode0, Mode):
                V = np.empty((len(mode0), 0))
                for mode in modes:
                    assert isinstance(mode,
                                      Mode), 'Modes should be a list of modes.'
                    v = mode.getEigvec()
                    v = np.expand_dims(v, axis=1)
                    V = np.hstack((V, v))
            else:
                V = np.array(modes)
        except TypeError:
            TypeError('Modes should be a list of modes.')
    if V.ndim == 1:
        V = np.expand_dims(V, axis=1)

    # normalize the rows so that feature vectors are unit vectors
    if row_norm:
        la = importLA()
        norms = la.norm(V, axis=1)
        N = np.diag(div0(1., norms))
        V = np.dot(N, V)
    return V
Example #4
0
def calcProjection(ensemble, modes, rmsd=True, norm=True):
    """Returns projection of conformational deviations onto given modes.
    *ensemble* coordinates are used to calculate the deviations that are
    projected onto *modes*.  For K conformations and M modes, a (K,M)
    matrix is returned.

    :arg ensemble: an ensemble, trajectory or a conformation for which
        deviation(s) will be projected, or a deformation vector
    :type ensemble: :class:`.Ensemble`, :class:`.Conformation`,
        :class:`.Vector`, :class:`.Trajectory`
    :arg modes: up to three normal modes
    :type modes: :class:`.Mode`, :class:`.ModeSet`, :class:`.NMA`

    By default root-mean-square deviation (RMSD) along the normal mode is
    calculated. To calculate the projection pass ``rmsd=True``.
    :class:`.Vector` instances are accepted as *ensemble* argument to allow
    for projecting a deformation vector onto normal modes."""

    if not isinstance(ensemble, (Ensemble, Conformation, Vector, TrajBase)):
        raise TypeError('ensemble must be Ensemble, Conformation, Vector, '
                        'or a TrajBase, not {0}'.format(type(ensemble)))
    if not isinstance(modes, (NMA, ModeSet, VectorBase)):
        raise TypeError('rows must be NMA, ModeSet, or Mode, not {0}'.format(
            type(modes)))
    if not modes.is3d():
        raise ValueError('modes must be 3-dimensional')
    if isinstance(ensemble, Vector):
        n_atoms = ensemble.numAtoms()
    else:
        n_atoms = ensemble.numSelected()
    if n_atoms != modes.numAtoms():
        raise ValueError('number of atoms are not the same')
    if isinstance(ensemble, Vector):
        if not ensemble.is3d():
            raise ValueError('ensemble must be a 3d vector instance')
        deviations = ensemble._getArray()
    elif isinstance(ensemble, (Ensemble, Conformation)):
        deviations = ensemble.getDeviations()
    else:
        nfi = ensemble.nextIndex()
        ensemble.goto(0)
        deviations = np.array([frame.getDeviations() for frame in ensemble])
        ensemble.goto(nfi)
    if deviations.ndim == 3:
        deviations = deviations.reshape(
            (deviations.shape[0], deviations.shape[1] * 3))
    elif deviations.ndim == 2:
        deviations = deviations.reshape((1, deviations.shape[0] * 3))
    else:
        deviations = deviations.reshape((1, deviations.shape[0]))
    la = importLA()
    if norm:
        N = la.norm(deviations)
        if N != 0:
            deviations = deviations / N
    projection = np.dot(deviations, modes._getArray())
    if rmsd:
        projection = (1 / (n_atoms**0.5)) * projection
    return projection
Example #5
0
def calcProjection(ensemble, modes, rmsd=True, norm=True):
    """Returns projection of conformational deviations onto given modes.
    *ensemble* coordinates are used to calculate the deviations that are
    projected onto *modes*.  For K conformations and M modes, a (K,M)
    matrix is returned.

    :arg ensemble: an ensemble, trajectory or a conformation for which
        deviation(s) will be projected, or a deformation vector
    :type ensemble: :class:`.Ensemble`, :class:`.Conformation`,
        :class:`.Vector`, :class:`.Trajectory`
    :arg modes: up to three normal modes
    :type modes: :class:`.Mode`, :class:`.ModeSet`, :class:`.NMA`

    By default root-mean-square deviation (RMSD) along the normal mode is
    calculated. To calculate the projection pass ``rmsd=True``.
    :class:`.Vector` instances are accepted as *ensemble* argument to allow
    for projecting a deformation vector onto normal modes."""

    if not isinstance(ensemble, (Ensemble, Conformation, Vector, TrajBase)):
        raise TypeError('ensemble must be Ensemble, Conformation, Vector, '
                        'or a TrajBase, not {0}'.format(type(ensemble)))
    if not isinstance(modes, (NMA, ModeSet, VectorBase)):
        raise TypeError('rows must be NMA, ModeSet, or Mode, not {0}'
                        .format(type(modes)))
    if not modes.is3d():
        raise ValueError('modes must be 3-dimensional')
    if isinstance(ensemble, Vector):
        n_atoms = ensemble.numAtoms()
    else:
        n_atoms = ensemble.numSelected()
    if n_atoms != modes.numAtoms():
        raise ValueError('number of atoms are not the same')
    if isinstance(ensemble, Vector):
        if not ensemble.is3d():
            raise ValueError('ensemble must be a 3d vector instance')
        deviations = ensemble._getArray()
    elif isinstance(ensemble, (Ensemble, Conformation)):
        deviations = ensemble.getDeviations()
    else:
        nfi = ensemble.nextIndex()
        ensemble.goto(0)
        deviations = np.array([frame.getDeviations() for frame in ensemble])
        ensemble.goto(nfi)
    if deviations.ndim == 3:
        deviations = deviations.reshape((deviations.shape[0],
                                         deviations.shape[1] * 3))
    elif deviations.ndim == 2:
        deviations = deviations.reshape((1, deviations.shape[0] * 3))
    else:
        deviations = deviations.reshape((1, deviations.shape[0]))
    la = importLA()
    if norm:
        N = la.norm(deviations)
        if N != 0:
            deviations = deviations / N
    projection = np.dot(deviations, modes._getArray())
    if rmsd:
        projection = (1 / (n_atoms ** 0.5)) * projection
    return projection
Example #6
0
def calcHitTime(model, method='standard'):
    """Returns the hit and commute times between pairs of nodes calculated 
    based on a :class:`.NMA` object. 

    .. [CB95] Chennubhotla C., Bahar I. Signal Propagation in Proteins and Relation
    to Equilibrium Fluctuations. *PLoS Comput Biol* **2007** 3(9).

    :arg model: model to be used to calculate hit times
    :type model: :class:`.NMA`  

    :arg method: method to be used to calculate hit times. Available options are 
        ``"standard"`` or ``"kirchhoff"``. Default is ``"standard"``
    :type method: str

    :returns: (:class:`~numpy.ndarray`, :class:`~numpy.ndarray`)
    """

    try:
        K = model.getKirchhoff()
    except AttributeError:
        raise TypeError('model must be an NMA instance')

    if K is None:
        raise ValueError('model not built')
    
    method = method.lower()

    D = np.diag(K)
    A = np.diag(D) - K

    start = time.time()
    linalg = importLA()
    if method == 'standard':
        st = D / sum(D)

        P = np.dot(np.diag(D**(-1)), A)
        W = np.ones((len(st), 1)) * st.T
        Z = linalg.pinv(np.eye(P.shape[0], P.shape[1]) - P + W)

        H = np.ones((len(st), 1)) * np.diag(Z).T - Z
        H = H / W
        H = H.T

    elif method == 'kirchhoff':
        K_inv = linalg.pinv(K)
        sum_D = sum(D)

        T1 = (sum_D * np.ones((len(D),1)) * np.diag(K_inv)).T

        T2 = sum_D * K_inv
        T3_i = np.dot((np.ones((len(D),1)) * D), K_inv)

        H = T1 - T2 + T3_i - T3_i.T

    C = H + H.T

    LOGGER.debug('Hit and commute times are calculated in  {0:.2f}s.'
                 .format(time.time()-start)) 
    return H, C
Example #7
0
    def _superpose(self, **kwargs):
        """Superpose conformations and update coordinates."""

        indices = self._indices
        weights = self._weights
        mobs = self._confs
        if indices is None:
            idx = False
            tar = self._coords
            movs = None
        else:
            idx = True
            if self._weights is not None:
                weights = weights[indices]
            tar = self._coords[indices]
            movs = self._confs

        linalg = importLA()
        svd = linalg.svd
        det = linalg.det

        if weights is None:
            tar_com = tar.mean(0)
            tar_org = (tar - tar_com)
            mob_org = zeros(tar_org.shape, dtype=mobs.dtype)
            tar_org = tar_org.T
        else:
            weights_sum = weights.sum()
            weights_dot = dot(weights.T, weights)
            tar_com = (tar * weights).sum(axis=0) / weights_sum
            tar_org = (tar - tar_com)
            mob_org = zeros(tar_org.shape, dtype=mobs.dtype)

        LOGGER.progress('Superposing ', len(mobs), '_prody_ensemble')
        for i, mob in enumerate(mobs):
            if idx:
                mob = mob[indices]
            if weights is None:
                mob_com = mob.mean(0)
                matrix = dot(tar_org, subtract(mob, mob_com, mob_org))
            else:
                mob_com = (mob * weights).sum(axis=0) / weights_sum
                subtract(mob, mob_com, mob_org)
                matrix = dot((tar_org * weights).T,
                             (mob_org * weights)) / weights_dot

            U, s, Vh = svd(matrix)
            Id = array([[1, 0, 0], [0, 1, 0], [0, 0, sign(det(matrix))]])
            rotation = dot(Vh.T, dot(Id, U.T))

            if movs is None:
                mobs[i] = dot(mob_org, rotation)
                add(mobs[i], tar_com, mobs[i])
            else:
                add(dot(movs[i], rotation),
                    (tar_com - dot(mob_com, rotation)), movs[i])
            LOGGER.update(i, '_prody_ensemble')
        LOGGER.clear()
Example #8
0
    def _superpose(self, **kwargs):
        """Superpose conformations and update coordinates."""

        indices = self._indices
        weights = self._weights
        mobs = self._confs
        if indices is None:
            idx = False
            tar = self._coords
            movs = None
        else:
            idx = True
            if self._weights is not None:
                weights = weights[indices]
            tar = self._coords[indices]
            movs = self._confs

        linalg = importLA()
        svd = linalg.svd
        det = linalg.det

        if weights is None:
            tar_com = tar.mean(0)
            tar_org = (tar - tar_com)
            mob_org = zeros(tar_org.shape, dtype=mobs.dtype)
            tar_org = tar_org.T
        else:
            weights_sum = weights.sum()
            weights_dot = dot(weights.T, weights)
            tar_com = (tar * weights).sum(axis=0) / weights_sum
            tar_org = (tar - tar_com)
            mob_org = zeros(tar_org.shape, dtype=mobs.dtype)

        LOGGER.progress('Superposing ', len(mobs), '_prody_ensemble')
        for i, mob in enumerate(mobs):
            if idx:
                mob = mob[indices]
            if weights is None:
                mob_com = mob.mean(0)
                matrix = dot(tar_org, subtract(mob, mob_com, mob_org))
            else:
                mob_com = (mob * weights).sum(axis=0) / weights_sum
                subtract(mob, mob_com, mob_org)
                matrix = dot((tar_org * weights).T,
                             (mob_org * weights)) / weights_dot

            U, s, Vh = svd(matrix)
            Id = array([[1, 0, 0], [0, 1, 0], [0, 0, sign(det(matrix))]])
            rotation = dot(Vh.T, dot(Id, U.T))

            if movs is None:
                mobs[i] = dot(mob_org, rotation)
                add(mobs[i], tar_com, mobs[i])
            else:
                add(dot(movs[i], rotation),
                    (tar_com - dot(mob_com, rotation)), movs[i])
            LOGGER.update(i + 1, label='_prody_ensemble')
        LOGGER.finish()
Example #9
0
    def performSVD(self, coordsets):
        """Calculate principal modes using singular value decomposition (SVD).
        *coordsets* argument may be a :class:`.Atomic`, :class:`.Ensemble`,
        or :class:`numpy.ndarray` instance.  If *coordsets* is a numpy array,
        its shape must be ``(n_csets, n_atoms, 3)``.  Note that coordinate
        sets must be aligned prior to SVD calculations.

        This is a considerably faster way of performing PCA calculations
        compared to eigenvalue decomposition of covariance matrix, but is
        an approximate method when heterogeneous datasets are analyzed.
        Covariance method should be preferred over this one for analysis of
        ensembles with missing atomic data.  See :ref:`pca-xray-calculations`
        example for comparison of results from SVD and covariance methods."""

        linalg = importLA()

        start = time.time()
        if not isinstance(coordsets, (Ensemble, Atomic, np.ndarray)):
            raise TypeError('coordsets must be an Ensemble, Atomic, Numpy '
                            'array instance')
        if isinstance(coordsets, np.ndarray):
            if (coordsets.ndim != 3 or coordsets.shape[2] != 3
                    or coordsets.dtype not in (np.float32, float)):
                raise ValueError('coordsets is not a valid coordinate array')
            deviations = coordsets - coordsets.mean(0)
        else:
            if isinstance(coordsets, Ensemble):
                deviations = coordsets.getDeviations()
            elif isinstance(coordsets, Atomic):
                deviations = (coordsets._getCoordsets() -
                              coordsets._getCoords())

        n_confs = deviations.shape[0]
        if n_confs < 3:
            raise ValueError('coordsets must have more than 3 coordinate sets')
        n_atoms = deviations.shape[1]
        if n_atoms < 3:
            raise ValueError('coordsets must have more than 3 atoms')

        dof = n_atoms * 3
        deviations = deviations.reshape((n_confs, dof)).T

        vectors, values, self._temp = linalg.svd(deviations,
                                                 full_matrices=False)
        values = (values**2) / n_confs
        self._dof = dof
        self._n_atoms = n_atoms
        which = values > 1e-18
        self._eigvals = values[which]
        self._array = vectors[:, which]
        self._vars = self._eigvals
        self._trace = self._vars.sum()
        self._n_modes = len(self._eigvals)
        LOGGER.debug('{0} modes were calculated in {1:.2f}s.'.format(
            self._n_modes,
            time.time() - start))
Example #10
0
    def performSVD(self, coordsets):
        """Calculate principal modes using singular value decomposition (SVD).
        *coordsets* argument may be a :class:`.Atomic`, :class:`.Ensemble`,
        or :class:`numpy.ndarray` instance.  If *coordsets* is a numpy array,
        its shape must be ``(n_csets, n_atoms, 3)``.  Note that coordinate
        sets must be aligned prior to SVD calculations.

        This is a considerably faster way of performing PCA calculations
        compared to eigenvalue decomposition of covariance matrix, but is
        an approximate method when heterogeneous datasets are analyzed.
        Covariance method should be preferred over this one for analysis of
        ensembles with missing atomic data.  See :ref:`pca-xray-calculations`
        example for comparison of results from SVD and covariance methods."""

        linalg = importLA()

        start = time.time()
        if not isinstance(coordsets, (Ensemble, Atomic, np.ndarray)):
            raise TypeError('coordsets must be an Ensemble, Atomic, Numpy '
                            'array instance')
        if isinstance(coordsets, np.ndarray):
            if (coordsets.ndim != 3 or coordsets.shape[2] != 3 or
                    coordsets.dtype not in (np.float32, float)):
                raise ValueError('coordsets is not a valid coordinate array')
            deviations = coordsets - coordsets.mean(0)
        else:
            if isinstance(coordsets, Ensemble):
                deviations = coordsets.getDeviations()
            elif isinstance(coordsets, Atomic):
                deviations = (coordsets._getCoordsets() -
                              coordsets._getCoords())

        n_confs = deviations.shape[0]
        if n_confs < 3:
            raise ValueError('coordsets must have more than 3 coordinate sets')
        n_atoms = deviations.shape[1]
        if n_atoms < 3:
            raise ValueError('coordsets must have more than 3 atoms')

        dof = n_atoms * 3
        deviations = deviations.reshape((n_confs, dof)).T

        vectors, values, self._temp = linalg.svd(deviations,
                                                 full_matrices=False)
        values = (values ** 2) / n_confs
        self._dof = dof
        self._n_atoms = n_atoms
        which = values > 1e-18
        self._eigvals = values[which]
        self._array = vectors[:, which]
        self._vars = self._eigvals
        self._trace = self._vars.sum()
        self._n_modes = len(self._eigvals)
        LOGGER.debug('{0} modes were calculated in {1:.2f}s.'
                     .format(self._n_modes, time.time()-start))
Example #11
0
def _getEigvecs(modes, row_norm=False, dummy_mode=False):
    la = importLA()

    if isinstance(modes, (Mode, ModeSet, NMA)):
        model = modes._model
        if isinstance(model, MaskedGNM):
            masked = model.masked
            model.masked = True
            V = modes.getArray()
            model.masked = masked
        else:
            V = modes.getArray()
    elif isinstance(modes, np.ndarray):
        V = modes
    else:
        try:
            mode0 = modes[0]
            if isinstance(mode0, Mode):
                V = np.empty((len(mode0), 0))
                for mode in modes:
                    assert isinstance(mode,
                                      Mode), 'Modes should be a list of modes.'
                    v = mode.getEigvec()
                    v = np.expand_dims(v, axis=1)
                    V = np.hstack((V, v))
            else:
                V = np.array(modes)
        except TypeError:
            raise TypeError('Modes should be a list of modes.')
    if V.ndim == 1:
        V = np.expand_dims(V, axis=1)

    # add a dummy zero mode to the modeset
    if dummy_mode:
        v0 = V[:, 0]
        if np.allclose(v0, np.mean(v0)):
            dummy_mode = False
            LOGGER.warn(
                'at least one zero mode is detected therefore dummy mode will NOT be added'
            )

    if dummy_mode:
        n, _ = V.shape
        v0 = np.ones((n, 1), dtype=V.dtype)
        v0 /= la.norm(v0)
        V = np.hstack((v0, V))
        LOGGER.debug('a dummy zero mode is added')

    # normalize the rows so that feature vectors are unit vectors
    if row_norm:
        norms = la.norm(V, axis=1)
        N = np.diag(div0(1., norms))
        V = np.dot(N, V)

    return V
Example #12
0
    def calcModes(self, n_modes=20, turbo=True):
        """Calculate principal (or essential) modes.  This method uses
        :func:`scipy.linalg.eigh`, or :func:`numpy.linalg.eigh`, function
        to diagonalize the covariance matrix.

        :arg n_modes: number of non-zero eigenvalues/vectors to calculate,
            default is 20,
            if **None** or ``'all'`` is given, all modes will be calculated
        :type n_modes: int

        :arg turbo: when available, use a memory intensive but faster way to
            calculate modes, default is **True**
        :type turbo: bool"""

        linalg = importLA()
        if self._cov is None:
            raise ValueError('covariance matrix is not built or set')
        start = time.time()
        dof = self._dof
        self._clear()
        if str(n_modes).lower() == 'all':
            n_modes = None
        if linalg.__package__.startswith('scipy'):
            if n_modes is None:
                eigvals = None
                n_modes = dof
            else:
                n_modes = int(n_modes)
                if n_modes >= self._dof:
                    eigvals = None
                    n_modes = dof
                else:
                    eigvals = (dof - n_modes, dof - 1)
            values, vectors = linalg.eigh(self._cov,
                                          turbo=turbo,
                                          eigvals=eigvals)
        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes are calculated.')
            values, vectors = linalg.eigh(self._cov)
        # Order by descending SV
        revert = list(range(len(values) - 1, -1, -1))
        values = values[revert]
        vectors = vectors[:, revert]
        which = values > 1e-8
        self._eigvals = values[which]
        self._array = vectors[:, which]
        self._vars = self._eigvals
        self._n_modes = len(self._eigvals)
        LOGGER.debug('{0} modes were calculated in {1:.2f}s.'.format(
            self._n_modes,
            time.time() - start))
Example #13
0
    def superpose(self):
        """Superpose frame onto the trajectory reference coordinates.  Note 
        that transformation matrix is calculated based on selected atoms and 
        applied to all atoms. If atom weights for the trajectory are set, they 
        will be used to calculate the transformation."""
        
        traj = self._traj
        indices = traj._indices 
        ag = traj._ag
        if ag is None:
            mob = mov = self._coords
        else:
            mob = mov = ag._getCoords()
        
        weights = traj._weights
        if indices is None:
            tar = traj._coords
            mov = None
        else:
            tar = traj._coords[indices]
            mob = mob[indices]
            if weights is not None:
                weights = weights[indices]

        linalg = importLA()
        if weights is None:
            mob_com = mob.mean(0)
            mob_org = mob - mob_com
            tar_com = tar.mean(0)
            tar_org = tar - tar_com
            matrix = np.dot(tar_org.T, mob_org)
        else:
            weights_sum = weights.sum()
            weights_dot = np.dot(weights.T, weights)
            mob_com = (mob * weights).sum(axis=0) / weights_sum
            mob_org = mob - mob_com
            tar_com = (tar * weights).sum(axis=0) / weights_sum
            tar_org = tar - tar_com
            matrix = np.dot((tar_org * weights).T, 
                            (mob_org * weights)) / weights_dot
        
        U, s, Vh = linalg.svd(matrix)
        Id = np.array([ [1, 0, 0], 
                        [0, 1, 0], 
                        [0, 0, np.sign(linalg.det(matrix))] ])
        rotation = np.dot(Vh.T, np.dot(Id, U.T))

        if mov is None:
            np.add(np.dot(mob_org, rotation), tar_com, mob) 
        else:
            np.add(np.dot(mov, rotation), 
                   (tar_com - np.dot(mob_com, rotation)), mov)
Example #14
0
def calcEntropyTransfer(model, ind1, ind2, tau):
    """This function calculates the entropy transfer from residue indice 
    ind1 to ind2 for a given time constant tau based on GNM.  
    """
    if not isinstance(model, NMA):
        raise TypeError('model must be a NMA instance')
    elif model.is3d():
        raise TypeError('model must be a 1-dimensional NMA instance')

    linalg = importLA()
    n_atoms = model.numAtoms()
    n_modes = model.numModes()

    eigvecs = model.getEigvecs().T
    eigvals = model.getEigvals()

    tau_0 = 1
    T = 0
    dummy1 = 0
    dummy2 = 0
    for k in range(n_modes):
        dummy1 += 1.0 / eigvals[k] * eigvecs[k,ind2] * eigvecs[k,ind2]
        dummy2 += 1.0 / eigvals[k] * eigvecs[k,ind2] * eigvecs[k,ind2] * np.exp(-eigvals[k]*tau/tau_0)
    T += 0.5 * np.log(dummy1**2 - dummy2**2)

    dummy1 = 0
    dummy2 = 0
    dummy3 = 0 
    dummy4 = 0 
    dummy5 = 0 
    dummy6 = 0 
    dummy7 = 0 
    dummy8 = 0 
    dummy9 = 0 
    dummy10 = 0 
    for k in range(n_modes):
        dummy1 += 1.0 / eigvals[k] * eigvecs[k,ind1] * eigvecs[k,ind1]
        dummy2 += 1.0 / eigvals[k] * eigvecs[k,ind2] * eigvecs[k,ind2]
        dummy3 += 1.0 / eigvals[k] * eigvecs[k,ind1] * eigvecs[k,ind2]
        dummy4 += 1.0 / eigvals[k] * eigvecs[k,ind2] * eigvecs[k,ind2] * np.exp(-eigvals[k]*tau/tau_0)
        dummy5 += 1.0 / eigvals[k] * eigvecs[k,ind1] * eigvecs[k,ind2] * np.exp(-eigvals[k]*tau/tau_0)  
        dummy9 += 1.0 / eigvals[k] * eigvecs[k,ind2] * eigvecs[k,ind2] * np.exp(-eigvals[k]*tau/tau_0)       
        
    dummy6 = dummy5
    dummy7 = dummy3 
    dummy8 = dummy2
    dummy10 = dummy1

    T -= 0.5 * np.log(dummy1*dummy2**2+2*dummy3*dummy4*dummy5-(dummy6**2+dummy7**2)*dummy8-dummy9**2*dummy10)
    T -= 0.5 * np.log(dummy2)
    T += 0.5 * np.log(dummy1*dummy2-dummy3**2)
    return T
Example #15
0
def calcOverallNetEntropyTransfer(model, turbo=False):
    """This function calculates the net entropy transfer for a whole structure 
    with a given time constant tau based on GNM.  
    """
    if not isinstance(model, NMA):
        raise TypeError('model must be a NMA instance')
    elif model.is3d():
        raise TypeError('model must be a 1-dimensional NMA instance')

    linalg = importLA()
    n_atoms = model.numAtoms()
    n_modes = model.numModes()

    tau_max = 5.0 
    tau_step = 0.1
    taus = np.arange(start=tau_step, stop=tau_max+1e-6, step=tau_step)
    taus = np.insert(taus,0,0.000001)
    numTaus = len(taus)
    netEntropyTransfer = np.zeros((numTaus,n_atoms,n_atoms))
    if turbo:
        try:
            from joblib import Parallel, delayed
            import multiprocessing as mp
        except: 
            LOGGER.report('joblib and multiprocessing is not imported. Running' + 
                'with sequential execution.')
        LOGGER.timeit('_ent_trans')
        n_cpu = mp.cpu_count()
        netEntropyTransfer = Parallel(n_jobs=n_cpu)(delayed(calcAllEntropyTransfer)(model,taus[i]) \
            for i in range(numTaus))
        netEntropyTransfer = np.asarray(netEntropyTransfer)
    
    else:
        LOGGER.timeit('_ent_trans')
        for i in range(len(taus)):
            netEntropyTransfer[i,:,:] = calcAllEntropyTransfer(model,taus[i])

    LOGGER.report('Net Entropy Transfer calculation is completed in %.1fs.',
                  '_ent_trans')

    overallNetEntropyTransfer = np.zeros((n_atoms,n_atoms))

    LOGGER.timeit('_num_int')
    for i in range(n_atoms):
        for j in range(n_atoms):
            if i != j:
                overallNetEntropyTransfer[i,j] = np.trapz(netEntropyTransfer[:,i,j],taus)
    LOGGER.report('Numerical integration is completed in %.1fs.',
                  '_num_int')

    return overallNetEntropyTransfer
Example #16
0
File: gnm.py Project: sixpi/ProDy
    def getNormDistFluct(self, coords):
        """Normalized distance fluctuation
        """
            
        model = self.getModel()
        LOGGER.info('Number of chains: {0}, chains: {1}.'
                     .format(len(list(set(coords.getChids()))), \
                                 list(set(coords.getChids()))))

        try:
            #coords = coords.select('protein and name CA')
            coords = (coords._getCoords() if hasattr(coords, '_getCoords') else
                coords.getCoords())
        except AttributeError:
            try:
                checkCoords(coords)
            except TypeError:
                raise TypeError('coords must be a Numpy array or an object '
                                                'with `getCoords` method')
        
        if not isinstance(model, NMA):
            LOGGER.info('Calculating new model')
            model = GNM('prot analysis')
            model.buildKirchhoff(coords)
            model.calcModes() 
            
        linalg = importLA()
        n_atoms = model.numAtoms()
        n_modes = model.numModes()
        LOGGER.timeit('_ndf')
    
        from .analysis import calcCrossCorr
        from numpy import linalg as LA
        # <dRi, dRi>, <dRj, dRj> = 1
        crossC = 2-2*calcCrossCorr(model)
        r_ij = np.zeros((n_atoms,n_atoms,3))

        for i in range(n_atoms):
           for j in range(i+1,n_atoms):
               r_ij[i][j] = coords[j,:] - coords[i,:]
               r_ij[j][i] = r_ij[i][j]
               r_ij_n = LA.norm(r_ij, axis=2)

        #with np.errstate(divide='ignore'):
        r_ij_n[np.diag_indices_from(r_ij_n)] = 1e-5  # div by 0
        crossC=abs(crossC)
        normdistfluct = np.divide(np.sqrt(crossC),r_ij_n)
        LOGGER.report('NDF calculated in %.2lfs.', label='_ndf')
        normdistfluct[np.diag_indices_from(normdistfluct)] = 0  # div by 0
        return normdistfluct
Example #17
0
    def calcModes(self, n_modes=20, turbo=True):
        """Calculate principal (or essential) modes.  This method uses
        :func:`scipy.linalg.eigh`, or :func:`numpy.linalg.eigh`, function
        to diagonalize the covariance matrix.

        :arg n_modes: number of non-zero eigenvalues/vectors to calculate,
            default is 20,
            if **None** or ``'all'`` is given, all modes will be calculated
        :type n_modes: int

        :arg turbo: when available, use a memory intensive but faster way to
            calculate modes, default is **True**
        :type turbo: bool"""
        
        linalg = importLA()
        if self._cov is None:
            raise ValueError('covariance matrix is not built or set')
        start = time.time()
        dof = self._dof
        self._clear()
        if str(n_modes).lower() == 'all':
            n_modes = None
        if linalg.__package__.startswith('scipy'):
            if n_modes is None:
                eigvals = None
                n_modes = dof
            else:
                n_modes = int(n_modes)
                if n_modes >= self._dof:
                    eigvals = None
                    n_modes = dof
                else:
                    eigvals = (dof - n_modes, dof - 1)
            values, vectors = linalg.eigh(self._cov, turbo=turbo,
                                          eigvals=eigvals)
        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes are calculated.')
            values, vectors = linalg.eigh(self._cov)
        # Order by descending SV
        revert = list(range(len(values)-1, -1, -1))
        values = values[revert]
        vectors = vectors[:, revert]
        which = values > 1e-8
        self._eigvals = values[which]
        self._array = vectors[:, which]
        self._vars = self._eigvals
        self._n_modes = len(self._eigvals)
        LOGGER.debug('{0} modes were calculated in {1:.2f}s.'
                     .format(self._n_modes, time.time()-start))
Example #18
0
    def getNormDistFluct(self, coords):
        """Normalized distance fluctuation
        """

        model = self.getModel()
        LOGGER.info('Number of chains: {0}, chains: {1}.'
                     .format(len(list(set(coords.getChids()))), \
                                 list(set(coords.getChids()))))

        try:
            #coords = coords.select('protein and name CA')
            coords = (coords._getCoords()
                      if hasattr(coords, '_getCoords') else coords.getCoords())
        except AttributeError:
            try:
                checkCoords(coords)
            except TypeError:
                raise TypeError('coords must be a Numpy array or an object '
                                'with `getCoords` method')

        if not isinstance(model, NMA):
            LOGGER.info('Calculating new model')
            model = GNM('prot analysis')
            model.buildKirchhoff(coords)
            model.calcModes()

        linalg = importLA()
        n_atoms = model.numAtoms()
        n_modes = model.numModes()
        LOGGER.timeit('_ndf')

        from .analysis import calcCrossCorr
        from numpy import linalg as LA
        # <dRi, dRi>, <dRj, dRj> = 1
        crossC = 2 - 2 * calcCrossCorr(model)
        r_ij = np.zeros((n_atoms, n_atoms, 3))

        for i in range(n_atoms):
            for j in range(i + 1, n_atoms):
                r_ij[i][j] = coords[j, :] - coords[i, :]
                r_ij[j][i] = r_ij[i][j]
                r_ij_n = LA.norm(r_ij, axis=2)

        #with np.errstate(divide='ignore'):
        r_ij_n[np.diag_indices_from(r_ij_n)] = 1e-5  # div by 0
        crossC = abs(crossC)
        normdistfluct = np.divide(np.sqrt(crossC), r_ij_n)
        LOGGER.report('NDF calculated in %.2lfs.', label='_ndf')
        normdistfluct[np.diag_indices_from(normdistfluct)] = 0  # div by 0
        return normdistfluct
Example #19
0
def SCN(M, **kwargs):
    la = importLA()
    total_count = kwargs.pop('total_count', None)
    max_loops = kwargs.pop('max_loops', 100)
    tol = kwargs.pop('tol', 1e-5)

    N = M.copy()
    n = 0
    d0 = None
    p = 1
    last_p = None

    while True:
        C = np.diag(div0(1., np.sum(N, axis=0)))
        N = np.dot(N, C)

        R = np.diag(div0(1., np.sum(N, axis=1)))
        N = np.dot(R, N)

        n += 1

        # check convergence of symmetry
        d = np.mean(np.abs(N - N.T))

        if d0 is not None:
            p = div0(d, d0)
            dp = np.abs(p - last_p)
            if dp < tol:
                break
        else:
            d0 = d
        LOGGER.debug('Iteration {0}: d = {1}, p = {2}'.format(
            str(n), str(d), str(p)))
        last_p = p

        if max_loops is not None:
            if n >= max_loops:
                LOGGER.warn('The SCN algorithm did not converge after {0} '
                            'iterations.'.format(max_loops))
                break
    # guarantee symmetry
    N = (N + N.T) / 2.
    if total_count is 'original':
        total_count = np.sum(M)

    if total_count is not None:
        sum_N = np.sum(N)
        k = total_count / sum_N
        N = N * k
    return N
Example #20
0
def SCN(M, **kwargs):
    la = importLA()
    total_count = kwargs.pop('total_count', None)
    max_loops = kwargs.pop('max_loops', 100)
    tol = kwargs.pop('tol', 1e-5)

    N = M.copy()
    n = 0
    d0 = None
    p = 1
    last_p = None

    while True:
        C = np.diag(div0(1., np.sum(N, axis=0)))
        N = np.dot(N, C)

        R = np.diag(div0(1., np.sum(N, axis=1)))
        N = np.dot(R, N)

        n += 1

        # check convergence of symmetry
        d = np.mean(np.abs(N - N.T))
        
        if d0 is not None:
            p = div0(d, d0)
            dp = np.abs(p - last_p)
            if dp < tol:
                break
        else:
            d0 = d
        LOGGER.debug('Iteration {0}: d = {1}, p = {2}'.format(str(n), str(d), str(p)))
        last_p = p
        
        if max_loops is not None:
            if n >= max_loops:
                LOGGER.warn('The SCN algorithm did not converge after {0} '
                            'iterations.'.format(max_loops))
                break
    # guarantee symmetry
    N = (N + N.T) / 2.
    if total_count is 'original':
        total_count = np.sum(M)

    if total_count is not None:
        sum_N = np.sum(N)
        k = total_count / sum_N
        N = N * k
    return N
Example #21
0
    def superpose(self):
        """Superpose frame onto the trajectory reference coordinates.  Note
        that transformation matrix is calculated based on selected atoms and
        applied to all atoms. If atom weights for the trajectory are set, they
        will be used to calculate the transformation."""

        traj = self._traj
        indices = traj._indices
        mob = mov = self._getxyz()

        weights = traj._weights
        if indices is None:
            tar = traj._coords
            mov = None
        else:
            tar = traj._coords[indices]
            mob = mob[indices]
            if weights is not None:
                weights = weights[indices]

        linalg = importLA()
        if weights is None:
            mob_com = mob.mean(0)
            mob_org = mob - mob_com
            tar_com = tar.mean(0)
            tar_org = tar - tar_com
            matrix = np.dot(tar_org.T, mob_org)
        else:
            weights_sum = weights.sum()
            weights_dot = np.dot(weights.T, weights)
            mob_com = (mob * weights).sum(axis=0) / weights_sum
            mob_org = mob - mob_com
            tar_com = (tar * weights).sum(axis=0) / weights_sum
            tar_org = tar - tar_com
            matrix = np.dot((tar_org * weights).T,
                            (mob_org * weights)) / weights_dot

        U, s, Vh = linalg.svd(matrix)
        Id = np.array([[1, 0, 0], [0, 1, 0],
                       [0, 0, np.sign(linalg.det(matrix))]])
        rotation = np.dot(Vh.T, np.dot(Id, U.T))

        if mov is None:
            np.add(np.dot(mob_org, rotation), tar_com, mob)
        else:
            np.add(np.dot(mov, rotation),
                   (tar_com - np.dot(mob_com, rotation)), mov)
Example #22
0
File: gnm.py Project: brezal/ProDy
    def calcHitTime(self, method='Z'):

        if self._affinity is None:
            self._buildAffinity()

        start = time.time()
        linalg = importLA()
        if method == 'Z':

            D = self._diagonal
            A = self._affinity

            st = D / sum(D)

            P = np.dot(np.diag(D**(-1)), A)

            W = np.ones((len(st),1)) * st.T

            Z = linalg.pinv(np.eye(P.shape[0], P.shape[1]) - P + W)

            H = np.ones((len(st),1)) * np.diag(Z).T - Z
            H = H / W
            H = H.T

        elif method == 'K':

            K = self._kirchhoff
            D = self._diagonal

            K_inv = linalg.pinv(K)
            sum_D = sum(D)

            T1 = (sum_D * np.ones((len(D),1)) * np.diag(K_inv)).T

            T2 = sum_D * K_inv
            T3_i = np.dot((np.ones((len(D),1)) * D), K_inv)

            H = T1 - T2 + T3_i - T3_i.T

        self._hitTime = H
        self._commuteTime = H + H.T


        LOGGER.debug('Hitting and commute time are calculated in  {0:.2f}s.'
                     .format(time.time()-start))    
Example #23
0
File: gnm.py Project: prody/ProDy
    def calcHitTime(self, method='Z'):

        if self._affinity is None:
            self._buildAffinity()

        start = time.time()
        linalg = importLA()
        if method == 'Z':

            D = self._diagonal
            A = self._affinity

            st = D / sum(D)

            P = np.dot(np.diag(D**(-1)), A)

            W = np.ones((len(st),1)) * st.T

            Z = linalg.pinv(np.eye(P.shape[0], P.shape[1]) - P + W)

            H = np.ones((len(st),1)) * np.diag(Z).T - Z
            H = H / W
            H = H.T

        elif method == 'K':

            K = self._kirchhoff
            D = self._diagonal

            K_inv = linalg.pinv(K)
            sum_D = sum(D)

            T1 = (sum_D * np.ones((len(D),1)) * np.diag(K_inv)).T

            T2 = sum_D * K_inv
            T3_i = np.dot((np.ones((len(D),1)) * D), K_inv)

            H = T1 - T2 + T3_i - T3_i.T

        self._hitTime = H
        self._commuteTime = H + H.T


        LOGGER.debug('Hitting and commute time are calculated in  {0:.2f}s.'
                     .format(time.time()-start))    
Example #24
0
def calcAllEntropyTransfer(model, tau):
    """This function calculates the net entropy transfer for a whole structure 
    with a given time constant tau based on GNM.  
    """
    if not isinstance(model, NMA):
        raise TypeError('model must be a NMA instance')
    elif model.is3d():
        raise TypeError('model must be a 1-dimensional NMA instance')

    linalg = importLA()
    n_atoms = model.numAtoms()
    n_modes = model.numModes()

    entropyTransfer = np.zeros((n_atoms,n_atoms))
    for i in range(n_atoms):
        for j in range(n_atoms):
            if i != j:
                entropyTransfer[i,j]=calcEntropyTransfer(model,i,j,tau)

    return entropyTransfer
Example #25
0
def _getEigvecs(modes, row_norm=False, remove_zero_rows=False):
    if isinstance(modes, (ModeSet, NMA)):
        V = modes.getEigvecs()
    elif isinstance(modes, Mode):
        V = modes.getEigvec()
    elif isinstance(modes, np.ndarray):
        V = modes
    else:
        try:
            mode0 = modes[0]
            if isinstance(mode0, Mode):
                V = np.empty((len(mode0),0))
                for mode in modes:
                    assert isinstance(mode, Mode), 'Modes should be a list of modes.'
                    v = mode.getEigvec()
                    v = np.expand_dims(v, axis=1)
                    V = np.hstack((V, v))
            else:
                V = np.array(modes)
        except TypeError:
            raise TypeError('Modes should be a list of modes.')
    if V.ndim == 1:
        V = np.expand_dims(V, axis=1)

    # normalize the rows so that feature vectors are unit vectors
    if row_norm:
        la = importLA()
        norms = la.norm(V, axis=1)
        N = np.diag(div0(1., norms))
        V = np.dot(N, V)
    
    # remove rows with all zeros
    m, _ = V.shape
    mask = np.ones(m, dtype=bool)
    if remove_zero_rows:
        mask = V.any(axis=1)
        V = V[mask]
    return V, mask
Example #26
0
def _getEigvecs(modes, row_norm=False, remove_zero_rows=False):
    if isinstance(modes, (ModeSet, NMA)):
        V = modes.getEigvecs()
    elif isinstance(modes, Mode):
        V = modes.getEigvec()
    elif isinstance(modes, np.ndarray):
        V = modes
    else:
        try:
            mode0 = modes[0]
            if isinstance(mode0, Mode):
                V = np.empty((len(mode0),0))
                for mode in modes:
                    assert isinstance(mode, Mode), 'Modes should be a list of modes.'
                    v = mode.getEigvec()
                    v = np.expand_dims(v, axis=1)
                    V = np.hstack((V, v))
            else:
                V = np.array(modes)
        except TypeError:
            TypeError('Modes should be a list of modes.')
    if V.ndim == 1:
        V = np.expand_dims(V, axis=1)

    # normalize the rows so that feature vectors are unit vectors
    if row_norm:
        la = importLA()
        norms = la.norm(V, axis=1)
        N = np.diag(div0(1., norms))
        V = np.dot(N, V)
    
    # remove rows with all zeros
    m, _ = V.shape
    mask = np.ones(m, dtype=bool)
    if remove_zero_rows:
        mask = V.any(axis=1)
        V = V[mask]
    return V, mask
Example #27
0
def calcADPs(atom):
    """Calculate anisotropic displacement parameters (ADPs) from 
    anisotropic temperature factors (ATFs).
    
    *atom* must have ATF values set for ADP calculation. ADPs are returned
    as a tuple, i.e. (eigenvalues, eigenvectors)."""
    
    linalg = importLA()
    if not isinstance(atom, Atom):
        raise TypeError('atom must be of type Atom, not {0:s}'
                        .format(type(atom)))
    anisou = atom.getAnisou()
    if anisou is None:
        raise ValueError('atom does not have anisotropic temperature factors')
    element = zeros((3,3))
    element[0,0] = anisou[0]
    element[1,1] = anisou[1]
    element[2,2] = anisou[2]
    element[0,1] = element[1,0] = anisou[3]
    element[0,2] = element[2,0] = anisou[4]
    element[1,2] = element[2,1] = anisou[5]
    vals, vecs = linalg.eigh(element)
    return vals[[2,1,0]], vecs[:, [2,1,0]] 
Example #28
0
def calcADPs(atom):
    """Calculate anisotropic displacement parameters (ADPs) from
    anisotropic temperature factors (ATFs).

    *atom* must have ATF values set for ADP calculation. ADPs are returned
    as a tuple, i.e. (eigenvalues, eigenvectors)."""

    linalg = importLA()
    if not isinstance(atom, Atom):
        raise TypeError('atom must be of type Atom, not {0}'.format(
            type(atom)))
    anisou = atom.getAnisou()
    if anisou is None:
        raise ValueError('atom does not have anisotropic temperature '
                         'factors')
    element = zeros((3, 3))
    element[0, 0] = anisou[0]
    element[1, 1] = anisou[1]
    element[2, 2] = anisou[2]
    element[0, 1] = element[1, 0] = anisou[3]
    element[0, 2] = element[2, 0] = anisou[4]
    element[1, 2] = element[2, 1] = anisou[5]
    vals, vecs = linalg.eigh(element)
    return vals[[2, 1, 0]], vecs[:, [2, 1, 0]]
Example #29
0
# -*- coding: utf-8 -*-
"""This module defines a class and a function for explicit membrane ANM calculations."""

import numpy as np

from prody import LOGGER, PY3K
from prody.atomic import Atomic, AtomGroup
from prody.utilities import importLA, checkCoords, copy
from numpy import sqrt, zeros, array, ceil, dot

from .anm import ANM
from .gnm import checkENMParameters
from .editing import _reduceModel

LA = importLA()
inv = LA.inv
pinv = LA.pinv
norm = LA.norm

__all__ = ['exANM']


class exANM(ANM):
    """Class for explicit ANM (exANM) method ([FT00]_).
    Optional arguments build a membrane lattice permit analysis of membrane
     effect on elastic network models in *exANM* method described in [TL12]_.

    .. [TL12] Lezon TR, Bahar I, Constraints Imposed by the Membrane
       Selectively Guide the Alternating Access Dynamics of the Glutamate
       Transporter GltPh
Example #30
0
File: anm.py Project: hrch3n/cNMA
    def calcModes(self, n_modes=20, zeros=False, turbo=True):
        """Calculate normal modes.  This method uses :func:`scipy.linalg.eigh`
        function to diagonalize the Hessian matrix. When Scipy is not found,
        :func:`numpy.linalg.eigh` is used.

        :arg n_modes: number of non-zero eigenvalues/vectors to calculate.
            If ``None`` is given, all modes will be calculated.
        :type n_modes: int or None, default is 20

        :arg zeros: If ``True``, modes with zero eigenvalues will be kept.
        :type zeros: bool, default is ``False``

        :arg turbo: Use a memory intensive, but faster way to calculate modes.
        :type turbo: bool, default is ``True``
        """

        if self._hessian is None:
            raise ValueError('Hessian matrix is not built or set')
        assert n_modes is None or isinstance(n_modes, int) and n_modes > 0, \
            'n_modes must be a positive integer'
        assert isinstance(zeros, bool), 'zeros must be a boolean'
        assert isinstance(turbo, bool), 'turbo must be a boolean'
        linalg = importLA()
        LOGGER.timeit('_anm_calc_modes')
        shift = 5
        if linalg.__package__.startswith('scipy'):
            if n_modes is None:
                eigvals = None
                n_modes = self._dof
            else:
                if n_modes >= self._dof:
                    eigvals = None
                    n_modes = self._dof
                else:
                    eigvals = (0, n_modes + shift)
            if eigvals:
                turbo = False
            if isinstance(self._hessian, np.ndarray):
                values, vectors = linalg.eigh(self._hessian, turbo=turbo,
                                              eigvals=eigvals)
            else:
                try:
                    from scipy.sparse import linalg as scipy_sparse_la
                except ImportError:
                    raise ImportError('failed to import scipy.sparse.linalg, '
                                      'which is required for sparse matrix '
                                      'decomposition')
                try:
                    values, vectors = (
                        scipy_sparse_la.eigsh(self._hessian, k=n_modes+6,
                                              which='SA'))
                except:
                    values, vectors = (
                        scipy_sparse_la.eigen_symmetric(self._hessian,
                                                        k=n_modes+6,
                                                        which='SA'))

        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes are calculated.')
            values, vectors = linalg.eigh(self._hessian)
        n_zeros = sum(values < ZERO)
        if n_zeros < 6:
            LOGGER.warning('Less than 6 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        elif n_zeros > 6:
            LOGGER.warning('More than 6 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        if zeros:
            shift = -1
        self._eigvals = values[1+shift:]
        self._vars = 1 / self._eigvals
        self._trace = self._vars.sum()
        if shift:
            self._array = vectors[:, 1+shift:].copy()
        else:
            self._array = vectors
        self._n_modes = len(self._eigvals)
        LOGGER.report('{0} modes were calculated in %.2fs.'
                     .format(self._n_modes), label='_anm_calc_modes')
Example #31
0
def reduceModel(model, atoms, select):
    """Return reduced NMA model.  Reduces a :class:`.NMA` model to a subset of
    *atoms* matching *select*.  This function behaves differently depending on
    the type of the *model* argument.  For :class:`.ANM` and :class:`.GNM` or
    other :class:`.NMA` models, force constant matrix for system of interest
    (specified by the *select*) is derived from the force constant matrix for
    the *model* by assuming that for any given displacement of the system of
    interest, other atoms move along in such a way as to minimize the potential
    energy.  This is based on the formulation in [KH00]_.  For :class:`.PCA`
    models, this function simply takes the sub-covariance matrix for selection.

    .. [KH00] Konrad H, Andrei-Jose P, Serge D, Marie-Claire BF, Gerald RK.
       Harmonicity in slow protein dynamics. *Chem Phys* **2000** 261:25-37.

    :arg model: dynamics model
    :type model: :class:`.ANM`, :class:`.GNM`, or :class:`.PCA`

    :arg atoms: atoms that were used to build the model
    :type atoms: :class:`.Atomic`

    :arg select: an atom selection or a selection string
    :type select: :class:`.Selection`, str

    :returns: (:class:`.NMA`, :class:`.Selection`)"""

    linalg = importLA()

    if not isinstance(model, NMA):
        raise TypeError('model must be an NMA instance, not {0}'
                        .format(type(model)))
    if not isinstance(atoms, (AtomGroup, AtomSubset, AtomMap)):
        raise TypeError('atoms type is not valid')
    if len(atoms) <= 1:
        raise TypeError('atoms must contain more than 1 atoms')

    if isinstance(model, GNM):
        matrix = model._kirchhoff
    elif isinstance(model, ANM):
        matrix = model._hessian
    elif isinstance(model, PCA):
        matrix = model._cov
    else:
        raise TypeError('model does not have a valid type derived from NMA')
    if matrix is None:
        raise ValueError('model matrix (Hessian/Kirchhoff/Covariance) is not '
                         'built')

    if isinstance(select, str):
        system = SELECT.getBoolArray(atoms, select)
        n_sel = sum(system)
        if n_sel == 0:
            raise ValueError('select matches 0 atoms')
        if len(atoms) == n_sel:
            raise ValueError('select matches all atoms')

        if isinstance(atoms, AtomGroup):
            ag = atoms
            which = np.arange(len(atoms))[system]
        else:
            ag = atoms.getAtomGroup()
            which = atoms._getIndices()[system]
        sel = Selection(ag, which, select, atoms.getACSIndex())

    elif isinstance(select, AtomSubset):
        sel = select
        if isinstance(atoms, AtomGroup):
            if sel.getAtomGroup() != atoms:
                raise ValueError('select and atoms do not match')
            system = np.zeros(len(atoms), bool)
            system[sel._getIndices()] = True
        else:
            if atoms.getAtomGroup() != sel.getAtomGroup():
                raise ValueError('select and atoms do not match')
            elif not sel in atoms:
                raise ValueError('select is not a subset of atoms')
            idxset = set(atoms._getIndices())
            system = np.array([idx in idxset for idx in sel._getIndices()])

    else:
        raise TypeError('select must be a string or a Selection instance')

    other = np.invert(system)

    if model.is3d():
        system = np.tile(system, (3, 1)).transpose().flatten()
        other = np.tile(other, (3, 1)).transpose().flatten()
    ss = matrix[system, :][:, system]
    if isinstance(model, PCA):
        eda = PCA(model.getTitle() + ' reduced')
        eda.setCovariance(ss)
        return eda, system
    so = matrix[system, :][:, other]
    os = matrix[other, :][:, system]
    oo = matrix[other, :][:, other]
    matrix = ss - np.dot(so, np.dot(linalg.inv(oo), os))

    if isinstance(model, GNM):
        gnm = GNM(model.getTitle() + ' reduced')
        gnm.setKirchhoff(matrix)
        return gnm, sel
    elif isinstance(model, ANM):
        anm = ANM(model.getTitle() + ' reduced')
        anm.setHessian(matrix)
        return anm, sel
    elif isinstance(model, PCA):
        eda = PCA(model.getTitle() + ' reduced')
        eda.setCovariance(matrix)
        return eda, sel
Example #32
0
def solveEig(M, n_modes=None, zeros=False, turbo=True, is3d=False):
    linalg = importLA()
    dof = M.shape[0]

    expct_n_zeros = 6 if is3d else 1

    if n_modes is None:
        eigvals = None
        n_modes = dof
    else:
        if n_modes >= dof:
            eigvals = None
            n_modes = dof
        else:
            eigvals = (0, n_modes+expct_n_zeros-1)

    def _eigh(M, eigvals=None, turbo=True):
        if linalg.__package__.startswith('scipy'):
            from scipy.sparse import issparse

            if eigvals:
                turbo = False
            if not issparse(M):
                values, vectors = linalg.eigh(M, turbo=turbo, eigvals=eigvals)
            else:
                try:
                    from scipy.sparse import linalg as scipy_sparse_la
                except ImportError:
                    raise ImportError('failed to import scipy.sparse.linalg, '
                                      'which is required for sparse matrix '
                                      'decomposition')
                if eigvals:
                    j = eigvals[0]
                    k = eigvals[-1] + 1
                else:
                    j = 0
                    k = dof

                if k >= dof:
                    k -= 1
                    LOGGER.warning('Cannot calculate all eigenvalues for sparse matrices, thus '
                                   'the last eigenvalue is omitted. See scipy.sparse.linalg.eigsh '
                                   'for more information')
                values, vectors = scipy_sparse_la.eigsh(M, k=k, which='SA')
                values = values[j:k]
                vectors = vectors[:, j:k]
        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes were calculated.')
            else:
                n_modes = dof
            values, vectors = linalg.eigh(M)
        return values, vectors

    def _calc_n_zero_modes(M):
        from scipy.sparse import issparse

        if not issparse(M):
            w = linalg.eigvalsh(M)
        else:
            try:
                from scipy.sparse import linalg as scipy_sparse_la
            except ImportError:
                raise ImportError('failed to import scipy.sparse.linalg, '
                                    'which is required for sparse matrix '
                                    'decomposition')
            w, _ = scipy_sparse_la.eigsh(M, k=dof-1, which='SA')
        n_zeros = sum(w < ZERO)
        return n_zeros

    values, vectors = _eigh(M, eigvals, turbo)
    n_zeros = sum(values < ZERO)

    if n_zeros < n_modes + expct_n_zeros:
        if n_zeros < expct_n_zeros:
            LOGGER.warning('Fewer than %d (%d) zero eigenvalues were calculated.'%(expct_n_zeros, n_zeros))
        elif n_zeros > expct_n_zeros:
            LOGGER.warning('More than %d (%d) zero eigenvalues were calculated.'%(expct_n_zeros, n_zeros))
    else:
        LOGGER.warning('More than %d zero eigenvalues were detected.'%expct_n_zeros)

    if not zeros:
        if n_zeros > expct_n_zeros:
            if n_zeros == n_modes + expct_n_zeros and n_modes != dof:
                LOGGER.debug('Determing the number of zero eigenvalues...')
                # find the actual number of zero modes
                n_zeros = _calc_n_zero_modes(M)
                LOGGER.debug('%d zero eigenvalues detected.'%n_zeros)
            LOGGER.debug('Solving for additional eigenvalues...')
            start = min(n_modes+expct_n_zeros, dof-1); end = min(n_modes+n_zeros-1, dof-1)
            values_, vectors_ = _eigh(M, eigvals=(start, end))
            values = np.concatenate((values, values_))
            vectors = np.hstack((vectors, vectors_))

        # final_n_modes may exceed len(eigvals) - no need to fix for the sake of the simplicity of the code
        final_n_modes = n_zeros + n_modes
        eigvals = values[n_zeros:final_n_modes]
        eigvecs = vectors[:, n_zeros:final_n_modes]
        vars = 1 / eigvals
    else:
        eigvals = values[:n_modes]
        eigvecs = vectors[:, :n_modes]
        vars = div0(1, values)
        vars[:n_zeros] = 0.
        vars = vars[:n_modes]

    return eigvals, eigvecs, vars
Example #33
0
def calcPairDeformationDist(model, coords, ind1, ind2, kbt=1.):
    """Returns distribution of the deformations in the distance contributed by each mode 
    for selected pair of residues *ind1* *ind2* using *model* from a :class:`.ANM`.
    Method described in [EB08]_ equation (10) and figure (2).     
    
    .. [EB08] Eyal E., Bahar I. Toward a Molecular Understanding of 
        the Anisotropic Response of Proteins to External Forces:
        Insights from Elastic Network Models. *Biophys J* **2008** 94:3424-34355. 
    
    :arg model: this is an 3-dimensional :class:`NMA` instance from a :class:`.ANM`
        calculations.
    :type model: :class:`.ANM`  

    :arg coords: a coordinate set or an object with :meth:`getCoords` method.
        Recommended: ``coords = parsePDB('pdbfile').select('protein and name CA')``.
    :type coords: :class:`~numpy.ndarray`.

    :arg ind1: first residue number.
    :type ind1: int 
    
    :arg ind2: secound residue number.
    :type ind2: int 
    """

    try:
        resnum_list = coords.getResnums()
        resnam_list = coords.getResnames()
        coords = (coords._getCoords()
                  if hasattr(coords, '_getCoords') else coords.getCoords())
    except AttributeError:
        try:
            checkCoords(coords)
        except TypeError:
            raise TypeError('coords must be a Numpy array or an object '
                            'with `getCoords` method')

    if not isinstance(model, NMA):
        raise TypeError('model must be a NMA instance')
    elif not model.is3d():
        raise TypeError('model must be a 3-dimensional NMA instance')
    elif len(model) == 0:
        raise ValueError('model must have normal modes calculated')
    elif model.getStiffness() is None:
        raise ValueError('model must have stiffness matrix calculated')

    linalg = importLA()
    n_atoms = model.numAtoms()
    n_modes = model.numModes()
    LOGGER.timeit('_pairdef')

    r_ij = np.zeros((n_atoms, n_atoms, 3))
    r_ij_norm = np.zeros((n_atoms, n_atoms, 3))

    for i in range(n_atoms):
        for j in range(i + 1, n_atoms):
            r_ij[i][j] = coords[j, :] - coords[i, :]
            r_ij[j][i] = r_ij[i][j]
            r_ij_norm[i][j] = r_ij[i][j] / linalg.norm(r_ij[i][j])
            r_ij_norm[j][i] = r_ij_norm[i][j]

    eigvecs = model.getEigvecs()
    eigvals = model.getEigvals()

    D_pair_k = []
    mode_nr = []
    ind1 = ind1 - resnum_list[0]
    ind2 = ind2 - resnum_list[0]

    for m in range(6, n_modes):
        U_ij_k = [(eigvecs[ind1*3][m] - eigvecs[ind2*3][m]), (eigvecs[ind1*3+1][m] \
            - eigvecs[ind2*3+1][m]), (eigvecs[ind1*3+2][m] - eigvecs[ind2*3+2][m])]
        D_ij_k = abs(
            sqrt(kbt / eigvals[m]) * (np.vdot(r_ij_norm[ind1][ind2], U_ij_k)))
        D_pair_k.append(D_ij_k)
        mode_nr.append(m)

    LOGGER.report('Deformation was calculated in %.2lfs.', label='_pairdef')

    return mode_nr, D_pair_k
Example #34
0
def reduceModel(model, atoms, select):
    """Returns reduced NMA model.  Reduces a :class:`.NMA` model to a subset of
    *atoms* matching *select*.  This function behaves differently depending on
    the type of the *model* argument.  For :class:`.ANM` and :class:`.GNM` or
    other :class:`.NMA` models, force constant matrix for system of interest
    (specified by the *select*) is derived from the force constant matrix for
    the *model* by assuming that for any given displacement of the system of
    interest, other atoms move along in such a way as to minimize the potential
    energy.  This is based on the formulation in [KH00]_.  For :class:`.PCA`
    models, this function simply takes the sub-covariance matrix for selection.

    .. [KH00] Hinsen K, Petrescu A-J, Dellerue S, Bellissent-Funel M-C, Kneller GR.
       Harmonicity in slow protein dynamics. *Chem Phys* **2000** 261:25-37.

    :arg model: dynamics model
    :type model: :class:`.ANM`, :class:`.GNM`, or :class:`.PCA`

    :arg atoms: atoms that were used to build the model
    :type atoms: :class:`.Atomic`

    :arg select: an atom selection or a selection string
    :type select: :class:`.Selection`, str

    :returns: (:class:`.NMA`, :class:`.Selection`)"""

    linalg = importLA()

    if not isinstance(model, NMA):
        raise TypeError('model must be an NMA instance, not {0}'.format(
            type(model)))
    if not isinstance(atoms, (AtomGroup, AtomSubset, AtomMap)):
        raise TypeError('atoms type is not valid')
    if len(atoms) <= 1:
        raise TypeError('atoms must contain more than 1 atoms')

    if isinstance(model, GNM):
        matrix = model._kirchhoff
    elif isinstance(model, ANM):
        matrix = model._hessian
    elif isinstance(model, PCA):
        matrix = model._cov
    else:
        raise TypeError('model does not have a valid type derived from NMA')
    if matrix is None:
        raise ValueError('model matrix (Hessian/Kirchhoff/Covariance) is not '
                         'built')

    which, select = sliceAtoms(atoms, select)
    system = np.zeros(model.numAtoms(), dtype=bool)
    system[which] = True

    if model.is3d():
        system = np.repeat(system, 3)

    if isinstance(model, PCA):
        ss = matrix[system, :][:, system]
        eda = PCA(model.getTitle() + ' reduced')
        eda.setCovariance(ss)

        return eda, system
    else:
        matrix = _reduceModel(matrix, system)

        if isinstance(model, GNM):
            gnm = GNM(model.getTitle() + ' reduced')
            gnm.setKirchhoff(matrix)
            return gnm, select
        elif isinstance(model, ANM):
            anm = ANM(model.getTitle() + ' reduced')
            anm.setHessian(matrix)
            return anm, select
        elif isinstance(model, PCA):
            eda = PCA(model.getTitle() + ' reduced')
            eda.setCovariance(matrix)
            return eda, select
Example #35
0
from .functions import calcENM
from .modeset import ModeSet

__all__ = [
    'calcAdaptiveANM', 'AANM_ONEWAY', 'AANM_ALTERNATING', 'AANM_BOTHWAYS',
    'AANM_DEFAULT'
]

AANM_ALTERNATING = 0
AANM_ONEWAY = 1
AANM_BOTHWAYS = 2

AANM_DEFAULT = AANM_ALTERNATING

norm = importLA().norm


def checkInput(a, b, **kwargs):
    coordsA = getCoords(a)
    if isinstance(a, Atomic):
        title = a.getTitle()
        atoms = a
    else:
        title = None
        atoms = None

    coordsB = getCoords(b)

    if title is None:
        if isinstance(b, Atomic):
Example #36
0
File: anm.py Project: njekin/ProDy
    def calcModes(self, n_modes=20, zeros=False, turbo=True):
        """Calculate normal modes.  This method uses :func:`scipy.linalg.eigh`
        function to diagonalize the Hessian matrix. When Scipy is not found,
        :func:`numpy.linalg.eigh` is used.

        :arg n_modes: number of non-zero eigenvalues/vectors to calculate.
            If ``None`` is given, all modes will be calculated.
        :type n_modes: int or None, default is 20

        :arg zeros: If ``True``, modes with zero eigenvalues will be kept.
        :type zeros: bool, default is ``False``

        :arg turbo: Use a memory intensive, but faster way to calculate modes.
        :type turbo: bool, default is ``True``
        """

        if self._hessian is None:
            raise ValueError("Hessian matrix is not built or set")
        assert n_modes is None or isinstance(n_modes, int) and n_modes > 0, "n_modes must be a positive integer"
        assert isinstance(zeros, bool), "zeros must be a boolean"
        assert isinstance(turbo, bool), "turbo must be a boolean"
        linalg = importLA()
        start = time.time()
        shift = 5
        if linalg.__package__.startswith("scipy"):
            if n_modes is None:
                eigvals = None
                n_modes = self._dof
            else:
                if n_modes >= self._dof:
                    eigvals = None
                    n_modes = self._dof
                else:
                    eigvals = (0, n_modes + shift)
            if eigvals:
                turbo = False
            if isinstance(self._hessian, np.ndarray):
                values, vectors = linalg.eigh(self._hessian, turbo=turbo, eigvals=eigvals)
            else:
                try:
                    from scipy.sparse import linalg as scipy_sparse_la
                except ImportError:
                    raise ImportError(
                        "failed to import scipy.sparse.linalg, " "which is required for sparse matrix " "decomposition"
                    )
                try:
                    values, vectors = scipy_sparse_la.eigsh(self._hessian, k=n_modes + 6, which="SA")
                except:
                    values, vectors = scipy_sparse_la.eigen_symmetric(self._hessian, k=n_modes + 6, which="SA")

        else:
            if n_modes is not None:
                LOGGER.info("Scipy is not found, all modes are calculated.")
            values, vectors = linalg.eigh(self._hessian)
        n_zeros = sum(values < ZERO)
        if n_zeros < 6:
            LOGGER.warning("Less than 6 zero eigenvalues are calculated.")
            shift = n_zeros - 1
        elif n_zeros > 6:
            LOGGER.warning("More than 6 zero eigenvalues are calculated.")
            shift = n_zeros - 1
        if zeros:
            shift = -1
        self._eigvals = values[1 + shift :]
        self._vars = 1 / self._eigvals
        self._trace = self._vars.sum()
        self._array = vectors[:, 1 + shift :]
        self._n_modes = len(self._eigvals)
        LOGGER.debug("{0} modes were calculated in {1:.2f}s.".format(self._n_modes, time.time() - start))
Example #37
0
from prody import LOGGER
from .anm import ANM
from .gnm import GNM, ZERO
from .rtb import RTB
from .imanm import imANM
from .exanm import exANM
from .editing import extendModel
from .sampling import sampleModes
from prody.atomic import AtomGroup
from prody.measure import calcTransformation, applyTransformation, calcRMSD
from prody.ensemble import Ensemble
from prody.proteins import writePDB, parsePDB, writePDBStream, parsePDBStream
from prody.utilities import createStringIO, importLA, mad

la = importLA()
norm = la.norm

__all__ = ['ClustENM', 'ClustRTB', 'ClustImANM', 'ClustExANM']

class ClustENM(Ensemble):

    '''
    ClustENMv2 is the new version of ClustENM(v1) conformation sampling algorithm [KZ16]_.
    This ANM-based hybrid algorithm requires PDBFixer and OpenMM for performing energy minimization and MD simulations in implicit/explicit solvent.
    It is Python 3.6 compatible and has been only tested on Linux machines.

    .. [KZ16] Kurkcuoglu Z., Bahar I., Doruker P., ClustENM: ENM-based sampling of essential conformational space at full atomic resolution. *J Chem* **2016** 12(9):4549-4562.

    .. [PE17] Eastman P., Swails J., Chodera J.D., McGibbon R.T., Zhao Y., Beauchamp K.A., Wang L.P., Simmonett A.C., Harrigan M.P., Stern C.D., Wiewiora R.P., Brooks B.R., Pande V.S., OpenMM 7: Rapid Development of High Performance Algorithms for Molecular Dynamics. *PLoS Comput Biol* **2017** 13:e1005659.
Example #38
0
# -*- coding: utf-8 -*-
""" This module defines a class for identifying contacts."""

import numpy as np

from prody import LOGGER
from prody.atomic import AtomPointer
from prody.utilities import importLA

from .measure import calcCenter

linalg = importLA()

__all__ = ['Transformation', 'applyTransformation', 'alignCoordsets',
           'calcRMSD', 'calcTransformation', 'superpose',
           'moveAtoms', 'wrapAtoms',
           'printRMSD']


class Transformation(object):

    """A class for storing a transformation matrix."""

    __slots__ = ['_matrix']

    def __init__(self, *args):
        """Either 4x4 transformation *matrix*, or *rotation* matrix and
        *translation* vector must be provided at instantiation."""

        nargs = len(args)
        if nargs == 1:
Example #39
0
File: gnm.py Project: sixpi/ProDy
    def calcModes(self, n_modes=20, zeros=False, turbo=True, hinges=True):
        """Calculate normal modes.  This method uses :func:`scipy.linalg.eigh`
        function to diagonalize the Kirchhoff matrix. When Scipy is not found,
        :func:`numpy.linalg.eigh` is used.

        :arg n_modes: number of non-zero eigenvalues/vectors to calculate.
              If ``None`` is given, all modes will be calculated.
        :type n_modes: int or None, default is 20

        :arg zeros: If ``True``, modes with zero eigenvalues will be kept.
        :type zeros: bool, default is ``False``

        :arg turbo: Use a memory intensive, but faster way to calculate modes.
        :type turbo: bool, default is ``True``

        :arg hinges: Identify hinge sites after modes are computed.
        :type hinges: bool, default is ``True``
        """

        if self._kirchhoff is None:
            raise ValueError('Kirchhoff matrix is not built or set')
        assert n_modes is None or isinstance(n_modes, int) and n_modes > 0, \
            'n_modes must be a positive integer'
        assert isinstance(zeros, bool), 'zeros must be a boolean'
        assert isinstance(turbo, bool), 'turbo must be a boolean'
        linalg = importLA()
        start = time.time()
        shift = 0
        if linalg.__package__.startswith('scipy'):
            if n_modes is None:
                eigvals = None
                n_modes = self._dof
            else:
                if n_modes >= self._dof:
                    eigvals = None
                    n_modes = self._dof
                else:
                    eigvals = (0, n_modes + shift)
            if eigvals:
                turbo = False
            if isinstance(self._kirchhoff, np.ndarray):
                values, vectors = linalg.eigh(self._kirchhoff, turbo=turbo,
                                              eigvals=eigvals)
            else:
                try:
                    from scipy.sparse import linalg as scipy_sparse_la
                except ImportError:
                    raise ImportError('failed to import scipy.sparse.linalg, '
                                      'which is required for sparse matrix '
                                      'decomposition')
                try:
                    values, vectors = (
                        scipy_sparse_la.eigsh(self._kirchhoff,
                                              k=n_modes + 1, which='SA'))
                except:
                    values, vectors = (
                        scipy_sparse_la.eigen_symmetric(self._kirchhoff,
                                                        k=n_modes + 1,
                                                        which='SA'))
        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes are calculated.')
            values, vectors = linalg.eigh(self._kirchhoff)
        n_zeros = sum(values < ZERO)
        if n_zeros < 1:
            LOGGER.warning('Less than 1 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        elif n_zeros > 1:
            LOGGER.warning('More than 1 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        if zeros:
            shift = -1
        self._eigvals = values[1+shift:]
        self._vars = 1 / self._eigvals
        self._trace = self._vars.sum()
        self._array = vectors[:, 1+shift:]
        self._n_modes = len(self._eigvals)
        if hinges:
            self.calcHinges()
        LOGGER.debug('{0} modes were calculated in {1:.2f}s.'
                     .format(self._n_modes, time.time()-start))
Example #40
0
    def calcModes(self, n_modes=20, zeros=False, turbo=True):
        """Calculate normal modes.  This method uses :func:`scipy.linalg.eigh`
        function to diagonalize the Hessian matrix. When Scipy is not found,
        :func:`numpy.linalg.eigh` is used.

        :arg n_modes: number of non-zero eigenvalues/vectors to calculate.
            If **None** or ``'all'`` is given, all modes will be calculated.
        :type n_modes: int or None, default is 20

        :arg zeros: If **True**, modes with zero eigenvalues will be kept.
        :type zeros: bool, default is **True**

        :arg turbo: Use a memory intensive, but faster way to calculate modes.
        :type turbo: bool, default is **True**
        """

        if self._hessian is None:
            raise ValueError('Hessian matrix is not built or set')
        if str(n_modes).lower() == 'all':
            n_modes = None
        assert n_modes is None or isinstance(n_modes, int) and n_modes > 0, \
            'n_modes must be a positive integer'
        assert isinstance(zeros, bool), 'zeros must be a boolean'
        assert isinstance(turbo, bool), 'turbo must be a boolean'
        self._clear()
        linalg = importLA()
        LOGGER.timeit('_anm_calc_modes')
        shift = 5
        if linalg.__package__.startswith('scipy'):
            if n_modes is None:
                eigvals = None
                n_modes = self._dof
            else:
                if n_modes >= self._dof:
                    eigvals = None
                    n_modes = self._dof
                else:
                    eigvals = (0, n_modes + shift)
            if eigvals:
                turbo = False
            if isinstance(self._hessian, np.ndarray):
                values, vectors = linalg.eigh(self._hessian, turbo=turbo,
                                              eigvals=eigvals)
            else:
                try:
                    from scipy.sparse import linalg as scipy_sparse_la
                except ImportError:
                    raise ImportError('failed to import scipy.sparse.linalg, '
                                      'which is required for sparse matrix '
                                      'decomposition')
                try:
                    values, vectors = (
                        scipy_sparse_la.eigsh(self._hessian, k=n_modes+6,
                                              which='SA'))
                except:
                    values, vectors = (
                        scipy_sparse_la.eigen_symmetric(self._hessian,
                                                        k=n_modes+6,
                                                        which='SA'))

        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes are calculated.')
            values, vectors = np.linalg.eigh(self._hessian)
        n_zeros = sum(values < ZERO)

        if n_zeros < 6:
            LOGGER.warning('Less than 6 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        elif n_zeros > 6:
            LOGGER.warning('More than 6 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        if zeros:
            shift = -1
        if n_zeros > n_modes:
            self._eigvals = values[1+shift:]
        else:
            self._eigvals = values[1+shift:]
        self._vars = 1 / self._eigvals
        self._trace = self._vars.sum()
        
        if shift:
            self._array = vectors[:, 1+shift:].copy()
        else:
            self._array = vectors
        self._n_modes = len(self._eigvals)
        LOGGER.report('{0} modes were calculated in %.2fs.'
                     .format(self._n_modes), label='_anm_calc_modes')
Example #41
0
def showEmbedding(modes, labels=None, trace=True, headtail=True, cmap='prism'):
    """Visualizes Laplacian embedding of Hi-C data. 

    :arg modes: modes in which loci are embedded. It can only have 2 or 3 modes for the purpose 
    of visualization.
    :type modes: :class:`ModeSet`

    :arg labels: a list of integers indicating the segmentation of the sequence.
    :type labels: list

    :arg trace: if **True** then the trace of the sequence will be indicated by a grey dashed line.
    :type trace: bool

    :arg headtail: if **True** then a star and a closed circle will indicate the head and the tail 
    of the sequence respectively.
    :type headtail: bool

    :arg cmap: the color map used to render the *labels*.
    :type cmap: str
    """
    V, _ = _getEigvecs(modes, True)
    m, n = V.shape

    if labels is not None:
        if len(labels) != m:
            raise ValueError(
                'Modes (%d) and the Hi-C map (%d) should have the same number'
                ' of atoms. Turn off "masked" if you intended to apply the'
                ' modes to the full map.' % (m, len(labels)))
    if n > 3:
        raise ValueError(
            'This function can only visualize the embedding of 2 or 3 modes.')

    from matplotlib.pyplot import figure, plot, scatter
    from mpl_toolkits.mplot3d import Axes3D

    if n == 2:
        la = importLA()

        X, Y = V[:, :2].T
        R = np.array(range(len(X)))
        R = R / la.norm(R)
        X *= R
        Y *= R

        f = figure()
        if trace:
            plot(X, Y, ':', color=[0.3, 0.3, 0.3])
        if labels is None:
            C = 'b'
        else:
            C = labels
        scatter(X, Y, s=30, c=C, cmap=cmap)
        if headtail:
            plot(X[:1], Y[:1], 'k*', markersize=12)
            plot(X[-1:], Y[-1:], 'ko', markersize=12)
    elif n == 3:
        X, Y, Z = V[:, :3].T

        f = figure()
        ax = Axes3D(f)
        if trace:
            ax.plot(X, Y, Z, ':', color=[0.3, 0.3, 0.3])
        if labels is None:
            C = 'b'
        else:
            C = labels
        ax.scatter(X, Y, Z, s=30, c=C, depthshade=True, cmap=cmap)
        if headtail:
            ax.plot(X[:1], Y[:1], Z[:1], 'k*', markersize=12)
            ax.plot(X[-1:], Y[-1:], Z[-1:], 'ko', markersize=12)

    if SETTINGS['auto_show']:
        showFigure()
    return f
Example #42
0
File: gnm.py Project: brezal/ProDy
    def calcModes(self, n_modes=20, zeros=False, turbo=True, hinges=True):
        """Calculate normal modes.  This method uses :func:`scipy.linalg.eigh`
        function to diagonalize the Kirchhoff matrix. When Scipy is not found,
        :func:`numpy.linalg.eigh` is used.

        :arg n_modes: number of non-zero eigenvalues/vectors to calculate.
              If **None** or ``'all'`` is given, all modes will be calculated.
        :type n_modes: int or None, default is 20

        :arg zeros: If **True**, modes with zero eigenvalues will be kept.
        :type zeros: bool, default is **True**

        :arg turbo: Use a memory intensive, but faster way to calculate modes.
        :type turbo: bool, default is **True**

        :arg hinges: Identify hinge sites after modes are computed.
        :type hinges: bool, default is **True**
        """

        if self._kirchhoff is None:
            raise ValueError('Kirchhoff matrix is not built or set')
        if str(n_modes).lower() == 'all':
            n_modes = None
        assert n_modes is None or isinstance(n_modes, int) and n_modes > 0, \
            'n_modes must be a positive integer'
        assert isinstance(zeros, bool), 'zeros must be a boolean'
        assert isinstance(turbo, bool), 'turbo must be a boolean'
        self._clear()
        linalg = importLA()
        start = time.time()
        shift = 0
        if linalg.__package__.startswith('scipy'):
            if n_modes is None:
                eigvals = None
                n_modes = self._dof
            else:
                if n_modes >= self._dof:
                    eigvals = None
                    n_modes = self._dof
                else:
                    eigvals = (0, n_modes + shift)
            if eigvals:
                turbo = False
            if isinstance(self._kirchhoff, np.ndarray):
                values, vectors = linalg.eigh(self._kirchhoff, turbo=turbo,
                                              eigvals=eigvals)
            else:
                try:
                    from scipy.sparse import linalg as scipy_sparse_la
                except ImportError:
                    raise ImportError('failed to import scipy.sparse.linalg, '
                                      'which is required for sparse matrix '
                                      'decomposition')
                try:
                    values, vectors = (
                        scipy_sparse_la.eigsh(self._kirchhoff,
                                              k=n_modes + 1, which='SA'))
                except:
                    values, vectors = (
                        scipy_sparse_la.eigen_symmetric(self._kirchhoff,
                                                        k=n_modes + 1,
                                                        which='SA'))
        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes are calculated.')
            values, vectors = linalg.eigh(self._kirchhoff)
        n_zeros = sum(values < ZERO)
        if n_zeros < 1:
            LOGGER.warning('Less than 1 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        elif n_zeros > 1:
            LOGGER.warning('More than 1 zero eigenvalues are calculated.')
            shift = n_zeros - 1
        if zeros:
            shift = -1
        self._eigvals = values[1+shift:]
        self._vars = 1 / self._eigvals
        self._trace = self._vars.sum()
        self._array = vectors[:, 1+shift:]
        self._n_modes = len(self._eigvals)
        if hinges:
            self.calcHinges()
        LOGGER.debug('{0} modes were calculated in {1:.2f}s.'
                     .format(self._n_modes, time.time()-start))
Example #43
0
File: gnm.py Project: prody/ProDy
def solveEig(M, n_modes=None, zeros=False, turbo=True, is3d=False):
    linalg = importLA()
    dof = M.shape[0]

    expct_n_zeros = 6 if is3d else 1

    if n_modes is None:
        eigvals = None
        n_modes = dof
    else:
        if n_modes >= dof:
            eigvals = None
            n_modes = dof
        else:
            eigvals = (0, n_modes+expct_n_zeros-1)

    def _eigh(M, eigvals=None, turbo=True):
        if linalg.__package__.startswith('scipy'):
            from scipy.sparse import issparse

            if eigvals:
                turbo = False
            if not issparse(M):
                values, vectors = linalg.eigh(M, turbo=turbo, eigvals=eigvals)
            else:
                try:
                    from scipy.sparse import linalg as scipy_sparse_la
                except ImportError:
                    raise ImportError('failed to import scipy.sparse.linalg, '
                                      'which is required for sparse matrix '
                                      'decomposition')
                if eigvals:
                    j = eigvals[0]
                    k = eigvals[-1] + 1
                else:
                    j = 0
                    k = dof

                if k >= dof:
                    k -= 1
                    LOGGER.warning('Cannot calculate all eigenvalues for sparse matrices, thus '
                                   'the last eigenvalue is omitted. See scipy.sparse.linalg.eigsh '
                                   'for more information')
                values, vectors = scipy_sparse_la.eigsh(M, k=k, which='SA')
                values = values[j:k]
                vectors = vectors[:, j:k]
        else:
            if n_modes is not None:
                LOGGER.info('Scipy is not found, all modes were calculated.')
            else:
                n_modes = dof
            values, vectors = linalg.eigh(M)
        return values, vectors

    def _calc_n_zero_modes(M):
        from scipy.sparse import issparse

        if not issparse(M):
            w = linalg.eigvalsh(M)
        else:
            try:
                from scipy.sparse import linalg as scipy_sparse_la
            except ImportError:
                raise ImportError('failed to import scipy.sparse.linalg, '
                                    'which is required for sparse matrix '
                                    'decomposition')
            w, _ = scipy_sparse_la.eigsh(M, k=dof-1, which='SA')
        n_zeros = sum(w < ZERO)
        return n_zeros

    values, vectors = _eigh(M, eigvals, turbo)
    n_zeros = sum(values < ZERO)

    if n_zeros < n_modes + expct_n_zeros:
        if n_zeros < expct_n_zeros:
            LOGGER.warning('Fewer than %d (%d) zero eigenvalues were calculated.'%(expct_n_zeros, n_zeros))
        elif n_zeros > expct_n_zeros:
            LOGGER.warning('More than %d (%d) zero eigenvalues were calculated.'%(expct_n_zeros, n_zeros))
    else:
        LOGGER.warning('More than %d zero eigenvalues were detected.'%expct_n_zeros)

    if not zeros:
        if n_zeros > expct_n_zeros:
            if n_zeros == n_modes + expct_n_zeros and n_modes != dof:
                LOGGER.debug('Determing the number of zero eigenvalues...')
                # find the actual number of zero modes
                n_zeros = _calc_n_zero_modes(M)
                LOGGER.debug('%d zero eigenvalues detected.'%n_zeros)
            LOGGER.debug('Solving for additional eigenvalues...')
            start = min(n_modes+expct_n_zeros, dof-1); end = min(n_modes+n_zeros-1, dof-1)
            values_, vectors_ = _eigh(M, eigvals=(start, end))
            values = np.concatenate((values, values_))
            vectors = np.hstack((vectors, vectors_))

        # final_n_modes may exceed len(eigvals) - no need to fix for the sake of the simplicity of the code
        final_n_modes = n_zeros + n_modes
        eigvals = values[n_zeros:final_n_modes]
        eigvecs = vectors[:, n_zeros:final_n_modes]
        vars = 1 / eigvals
    else:
        eigvals = values[:n_modes]
        eigvecs = vectors[:, :n_modes]
        vars = div0(1, values)
        vars[:n_zeros] = 0.
        vars = vars[:n_modes]

    return eigvals, eigvecs, vars
Example #44
0
def showEmbedding(modes, labels=None, trace=True, headtail=True, cmap='prism'):
    """Visualizes Laplacian embedding of Hi-C data. 

    :arg modes: modes in which loci are embedded. It can only have 2 or 3 modes for the purpose 
    of visualization.
    :type modes: :class:`ModeSet`

    :arg labels: a list of integers indicating the segmentation of the sequence.
    :type labels: list

    :arg trace: if **True** then the trace of the sequence will be indicated by a grey dashed line.
    :type trace: bool

    :arg headtail: if **True** then a star and a closed circle will indicate the head and the tail 
    of the sequence respectively.
    :type headtail: bool

    :arg cmap: the color map used to render the *labels*.
    :type cmap: str
    """
    V, mask = _getEigvecs(modes, True)
    m,n = V.shape

    if labels is not None:
        if len(labels) != m:
            raise ValueError('Modes (%d) and the Hi-C map (%d) should have the same number'
                                ' of atoms. Turn off "masked" if you intended to apply the'
                                ' modes to the full map.'
                                %(m, len(labels)))
    if n > 3:
        raise ValueError('This function can only visualize the embedding of 2 or 3 modes.')
    
    from matplotlib.pyplot import figure, plot, scatter
    from mpl_toolkits.mplot3d import Axes3D

    if n == 2:
        la = importLA()

        X, Y = V[:,:2].T
        R = np.array(range(len(X)))
        R = R / la.norm(R)
        X *= R; Y *= R
        
        f = figure()
        if trace:
            plot(X, Y, ':', color=[0.3, 0.3, 0.3])
        if labels is None:
            C = 'b'
        else:
            C = labels
        scatter(X, Y, s=30, c=C, cmap=cmap)
        if headtail:
            plot(X[:1], Y[:1], 'k*', markersize=12)
            plot(X[-1:], Y[-1:], 'ko', markersize=12)
    elif n == 3:
        X, Y, Z = V[:,:3].T
        
        f = figure()
        ax = Axes3D(f)
        if trace:
            ax.plot(X, Y, Z, ':', color=[0.3, 0.3, 0.3])
        if labels is None:
            C = 'b'
        else:
            C = labels
        ax.scatter(X, Y, Z, s=30, c=C, depthshade=True, cmap=cmap)
        if headtail:
            ax.plot(X[:1], Y[:1], Z[:1], 'k*', markersize=12)
            ax.plot(X[-1:], Y[-1:], Z[-1:], 'ko', markersize=12)

    if SETTINGS['auto_show']:
        showFigure()
    return f
Example #45
0
def calcPairDeformationDist(model, coords, ind1, ind2, kbt=1.):
                                                
    """Returns distribution of the deformations in the distance contributed by each mode 
    for selected pair of residues *ind1* *ind2* using *model* from a :class:`.ANM`.
    Method described in [EB08]_ equation (10) and figure (2).     
    
    .. [EB08] Eyal E., Bahar I. Toward a Molecular Understanding of 
        the Anisotropic Response of Proteins to External Forces:
        Insights from Elastic Network Models. *Biophys J* **2008** 94:3424-34355. 
    
    :arg model: this is an 3-dimensional NMA instance from a :class:`.ANM
    calculations.
    :type model: :class:`.ANM`  
    :arg coords: a coordinate set or an object with ``getCoords`` method.
      Recommended: coords = parsePDB('pdbfile').select('protein and name CA').
    :type coords: :class:`numpy.ndarray`.
    :arg ind1: first residue number.
    :type ind1: int 
    :arg ind2: secound residue number.
    :type ind2: int 
    """

    try:
        resnum_list = coords.getResnums()
        resnam_list = coords.getResnames()
        coords = (coords._getCoords() if hasattr(coords, '_getCoords') else
                coords.getCoords())
    except AttributeError:
        try:
            checkCoords(coords)
        except TypeError:
            raise TypeError('coords must be a Numpy array or an object '
                            'with `getCoords` method')
    
    if not isinstance(model, NMA):
        raise TypeError('model must be a NMA instance')
    elif not model.is3d():
        raise TypeError('model must be a 3-dimensional NMA instance')
    elif len(model) == 0:
        raise ValueError('model must have normal modes calculated')
    elif model.getStiffness() is None:
        raise ValueError('model must have stiffness matrix calculated')
    
    linalg = importLA()
    n_atoms = model.numAtoms()
    n_modes = model.numModes()
    LOGGER.timeit('_pairdef')

    r_ij = np.zeros((n_atoms,n_atoms,3))
    r_ij_norm = np.zeros((n_atoms,n_atoms,3))

    for i in range(n_atoms):
        for j in range(i+1,n_atoms):
            r_ij[i][j] = coords[j,:] - coords[i,:]
            r_ij[j][i] = r_ij[i][j]
            r_ij_norm[i][j] = r_ij[i][j]/linalg.norm(r_ij[i][j])
            r_ij_norm[j][i] = r_ij_norm[i][j]

    eigvecs = model.getEigvecs()
    eigvals = model.getEigvals()
    
    D_pair_k = []
    mode_nr = []
    ind1 = ind1 - resnum_list[0]
    ind2 = ind2 - resnum_list[0]

    for m in xrange(6,n_modes):
        U_ij_k = [(eigvecs[ind1*3][m] - eigvecs[ind2*3][m]), (eigvecs[ind1*3+1][m] \
            - eigvecs[ind2*3+1][m]), (eigvecs[ind1*3+2][m] - eigvecs[ind2*3+2][m])] 
        D_ij_k = abs(np.sqrt(kbt/eigvals[m])*(np.vdot(r_ij_norm[ind1][ind2], U_ij_k)))  
        D_pair_k.append(D_ij_k)
        mode_nr.append(m)

    LOGGER.report('Deformation was calculated in %.2lfs.', label='_pairdef')
    
    return mode_nr, D_pair_k
Example #46
0
def calcPairDeformationDist(model, coords, ind1, ind2, kbt=1., saveFile=False, filename='out', savePlot=False):
    """Return distribution of the deformations in the distance contributed by each mode 
    for selected pair of residues *ind1* *ind2* using *model* from a :class:`.ANM`.
    Method described in [EB08]_ equation (10) and figure (2).     
    
    .. [EB08] Eyal E., Bahar I. Toward a Molecular Understanding of 
        the Anisotropic Response of Proteins to External Forces:
        Insights from Elastic Network Models. *Biophys J* **2008** 94:3424-34355. 
    
    :arg model: this is an 3-dimensional NMA instance from a :class:`.ANM
    calculations.
    :type model: :class:`.ANM`  
    :arg coords: a coordinate set or an object with ``getCoords`` method.
      Recommended: coords = parsePDB('pdbfile').select('protein and name CA').
    :type coords: :class:`numpy.ndarray`.
    :arg ind1: first residue number.
    :type ind1: int 
    :arg ind2: secound residue number.
    :type ind2: int 
    
    By default results will not be saved to a *filename* file. To save plot and
    data file use ``saveFile=True`` and ``savePlot=True``.   
    """

    try:
        resnum_list = coords.getResnums()
        resnam_list = coords.getResnames()
        coords = (coords._getCoords() if hasattr(coords, '_getCoords') else
                coords.getCoords())
    except AttributeError:
        try:
            checkCoords(coords)
        except TypeError:
            raise TypeError('coords must be a Numpy array or an object '
                            'with `getCoords` method')
    
    if not isinstance(model, NMA):
        raise TypeError('model must be an NMA instance')
    elif not model.is3d():
        raise TypeError('model must be a 3-dimensional NMA instance')
    elif len(model) == 0:
        raise ValueError('model must have normal modes calculated')
    elif model.getStiffness() is None:
        raise ValueError('model must have stiffness matrix calculated')
    
    linalg = importLA()
    n_atoms = model.numAtoms()
    n_modes = model.numModes()
    LOGGER.timeit('_pairdef')

    r_ij = np.zeros((n_atoms,n_atoms,3))
    r_ij_norm = np.zeros((n_atoms,n_atoms,3))

    for i in range(n_atoms):
        for j in range(i+1,n_atoms):
            r_ij[i][j] = coords[j,:] - coords[i,:]
            r_ij[j][i] = r_ij[i][j]
            r_ij_norm[i][j] = r_ij[i][j]/linalg.norm(r_ij[i][j])
            r_ij_norm[j][i] = r_ij_norm[i][j]

    eigvecs = model.getEigvecs()
    eigvals = model.getEigvals()
    
    D_pair_k = []
    mode_nr = []
    ind1 = ind1 - resnum_list[0]
    ind2 = ind2 - resnum_list[0]

    for m in xrange(6,n_modes):
        U_ij_k = [(eigvecs[ind1*3][m] - eigvecs[ind2*3][m]), (eigvecs[ind1*3+1][m] \
            - eigvecs[ind2*3+1][m]), (eigvecs[ind1*3+2][m] - eigvecs[ind2*3+2][m])] 
        D_ij_k = abs(np.sqrt(kbt/eigvals[m])*(np.vdot(r_ij_norm[ind1][ind2], U_ij_k)))  
        D_pair_k.append(D_ij_k)
        mode_nr.append(m)

    LOGGER.report('Deformation was calculated in %.2lfs.', label='_pairdef')
    
    if(saveFile == True):
        fout = open(filename+".txt", 'w')
        for i in xrange(len(mode_nr)):
            fout.write("{} {}\n".format(mode_nr[i], D_pair_k[i]))
        fout.close()
        LOGGER.info('Data file has been saved.')
    
    if(savePlot == True):
        import matplotlib
        import matplotlib.pylab as plt
        
        matplotlib.rcParams['font.size'] = '16'
        fig = plt.figure(num=None, figsize=(12,8), dpi=100, facecolor='w')
        plt.plot(mode_nr, D_pair_k)
        plt.xlabel('mode (k)', fontsize = '18')
        plt.ylabel('d$^k$' '($\AA$)', fontsize = '18')    
        plt.savefig(filename+'.png', dpi=100)
        LOGGER.info('Plot has been saved.')
    
    return mode_nr, D_pair_k
Example #47
0
def calcADPAxes(atoms, **kwargs):
    """Return a 3Nx3 array containing principal axes defining anisotropic
    displacement parameter (ADP, or anisotropic temperature factor) ellipsoids.

    :arg atoms: a ProDy object for handling atomic data
    :type atoms: :class:`~.Atomic`

    :kwarg fract: For an atom, if the fraction of anisotropic displacement
        explained by its largest axis/eigenvector is less than given value,
        all axes for that atom will be set to zero. Values
        larger than 0.33 and smaller than 1.0 are accepted.
    :type fract: float

    :kwarg ratio2: For an atom, if the ratio of the second-largest eigenvalue
        to the largest eigenvalue axis less than or equal to the given value,
        all principal axes for that atom will be returned.
        Values less than 1 and greater than 0 are accepted.
    :type ratio2: float

    :kwarg ratio3: For an atom, if the ratio of the smallest eigenvalue
        to the largest eigenvalue is less than or equal to the given value,
        all principal axes for that atom will be returned.
        Values less than 1 and greater than 0 are accepted.
    :type ratio3: float

    :kwarg ratio: Same as *ratio3*.
    :type ratio: float


    Keyword arguments *fract*, *ratio3*, or *ratio3* can be used to set
    principal axes to 0 for atoms showing relatively lower degree of
    anisotropy.

    3Nx3 axis contains N times 3x3 matrices, one for each given atom. Columns
    of these 3x3 matrices are the principal axes which are weighted by
    square root of their eigenvalues. The first columns correspond to largest
    principal axes.

    The direction of the principal axes for an atom is determined based on the
    correlation of the axes vector with the principal axes vector of the
    previous atom.

    .. ipython:: python

       from prody import *
       protein = parsePDB('1ejg')
       calphas = protein.select('calpha')
       adp_axes = calcADPAxes( calphas )
       adp_axes.shape

    These can be written in NMD format as follows:

    .. ipython:: python

       nma = NMA('ADPs')
       nma.setEigens(adp_axes)
       nma
       writeNMD('adp_axes.nmd', nma, calphas)"""

    linalg = importLA()
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be of type Atomic, not {0}'.format(
            type(atoms)))
    anisous = atoms.getAnisous()
    if anisous is None:
        raise ValueError('anisotropic temperature factors are not set')
    n_atoms = atoms.numAtoms()

    axes = zeros((n_atoms * 3, 3))
    variances = zeros((n_atoms, 3))
    stddevs = zeros((n_atoms, 3))
    anisou = anisous[0]
    element = zeros((3, 3))
    element[0, 0] = anisou[0]
    element[1, 1] = anisou[1]
    element[2, 2] = anisou[2]
    element[0, 1] = element[1, 0] = anisou[3]
    element[0, 2] = element[2, 0] = anisou[4]
    element[1, 2] = element[2, 1] = anisou[5]
    vals, vecs = linalg.eigh(element)
    # If negative eigenvalues are found (when ADP matrix is not positive
    # definite) set them to 0
    vals[vals < 0] = 0
    variances[0] = vals
    vals = vals**0.5
    stddevs[0] = vals
    axes[0:3, :] = vals * vecs

    for i in range(1, n_atoms):
        anisou = anisous[i]
        element[0, 0] = anisou[0]
        element[1, 1] = anisou[1]
        element[2, 2] = anisou[2]
        element[0, 1] = element[1, 0] = anisou[3]
        element[0, 2] = element[2, 0] = anisou[4]
        element[1, 2] = element[2, 1] = anisou[5]
        vals, vecs = linalg.eigh(element)
        # If negative eigenvalues are found (when ADP matrix is not positive
        # definite) set them to 0
        vals[vals < 0] = 0
        variances[i] = vals
        vals = vals**0.5
        stddevs[i] = vals
        # Make sure the direction that correlates with the previous atom
        # is selected
        vals = vals * sign((vecs * axes[(i - 1) * 3:(i) * 3, :]).sum(0))
        axes[i * 3:(i + 1) * 3, :] = vals * vecs
    # Resort the columns before returning array
    axes = axes[:, [2, 1, 0]]
    torf = None
    if 'fract' in kwargs:
        fract = float(kwargs['fract'])
        assert 0.33 < fract < 1.0, 'fract must be > 0.33 and < 1.0'
        variances = variances[:, [2, 1, 0]]
        torf = variances[:, 0] / variances.sum(1) > fract
    elif 'ratio' in kwargs or 'ratio3' in kwargs or 'ratio2' in kwargs:
        if 'ratio2' in kwargs:
            ratio = float(kwargs['ratio2'])
            assert 0 < ratio < 1.0, 'ratio2 must be > 0 and < 1.0'
            dim = 1
        else:
            ratio = float(kwargs.get('ratio', kwargs.get('ratio3')))
            assert 0 < ratio < 1.0, 'ratio or ratio3 must be > 0 and < 1.0'
            dim = 2
        variances = variances[:, [2, 1, 0]]
        torf = variances[:, dim] / variances[:, 0] <= ratio
    if torf is not None:
        torf = tile(torf.reshape((n_atoms, 1)), (1, 3)).reshape(
            (n_atoms * 3, 1))
        axes = axes * torf
    return axes
Example #48
0
def calcADPAxes(atoms, **kwargs):
    """Returns a 3Nx3 array containing principal axes defining anisotropic
    displacement parameter (ADP, or anisotropic temperature factor) ellipsoids.

    :arg atoms: a ProDy object for handling atomic data
    :type atoms: :class:`~.Atomic`

    :kwarg fract: For an atom, if the fraction of anisotropic displacement
        explained by its largest axis/eigenvector is less than given value,
        all axes for that atom will be set to zero. Values
        larger than 0.33 and smaller than 1.0 are accepted.
    :type fract: float

    :kwarg ratio2: For an atom, if the ratio of the second-largest eigenvalue
        to the largest eigenvalue axis less than or equal to the given value,
        all principal axes for that atom will be returned.
        Values less than 1 and greater than 0 are accepted.
    :type ratio2: float

    :kwarg ratio3: For an atom, if the ratio of the smallest eigenvalue
        to the largest eigenvalue is less than or equal to the given value,
        all principal axes for that atom will be returned.
        Values less than 1 and greater than 0 are accepted.
    :type ratio3: float

    :kwarg ratio: Same as *ratio3*.
    :type ratio: float


    Keyword arguments *fract*, *ratio3*, or *ratio3* can be used to set
    principal axes to 0 for atoms showing relatively lower degree of
    anisotropy.

    3Nx3 axis contains N times 3x3 matrices, one for each given atom. Columns
    of these 3x3 matrices are the principal axes which are weighted by
    square root of their eigenvalues. The first columns correspond to largest
    principal axes.

    The direction of the principal axes for an atom is determined based on the
    correlation of the axes vector with the principal axes vector of the
    previous atom.

    .. ipython:: python

       from prody import *
       protein = parsePDB('1ejg')
       calphas = protein.select('calpha')
       adp_axes = calcADPAxes( calphas )
       adp_axes.shape

    These can be written in NMD format as follows:

    .. ipython:: python

       nma = NMA('ADPs')
       nma.setEigens(adp_axes)
       nma
       writeNMD('adp_axes.nmd', nma, calphas)"""

    linalg = importLA()
    if not isinstance(atoms, Atomic):
        raise TypeError('atoms must be of type Atomic, not {0}'
                        .format(type(atoms)))
    anisous = atoms.getAnisous()
    if anisous is None:
        raise ValueError('anisotropic temperature factors are not set')
    n_atoms = atoms.numAtoms()

    axes = zeros((n_atoms*3, 3))
    variances = zeros((n_atoms, 3))
    stddevs = zeros((n_atoms, 3))
    anisou = anisous[0]
    element = zeros((3, 3))
    element[0, 0] = anisou[0]
    element[1, 1] = anisou[1]
    element[2, 2] = anisou[2]
    element[0, 1] = element[1, 0] = anisou[3]
    element[0, 2] = element[2, 0] = anisou[4]
    element[1, 2] = element[2, 1] = anisou[5]
    vals, vecs = linalg.eigh(element)
    # If negative eigenvalues are found (when ADP matrix is not positive
    # definite) set them to 0
    vals[vals < 0] = 0
    variances[0] = vals
    vals = vals**0.5
    stddevs[0] = vals
    axes[0:3, :] = vals * vecs

    for i in range(1, n_atoms):
        anisou = anisous[i]
        element[0, 0] = anisou[0]
        element[1, 1] = anisou[1]
        element[2, 2] = anisou[2]
        element[0, 1] = element[1, 0] = anisou[3]
        element[0, 2] = element[2, 0] = anisou[4]
        element[1, 2] = element[2, 1] = anisou[5]
        vals, vecs = linalg.eigh(element)
        # If negative eigenvalues are found (when ADP matrix is not positive
        # definite) set them to 0
        vals[vals < 0] = 0
        variances[i] = vals
        vals = vals**0.5
        stddevs[i] = vals
        # Make sure the direction that correlates with the previous atom
        # is selected
        vals = vals * sign((vecs * axes[(i-1)*3:(i)*3, :]).sum(0))
        axes[i*3:(i+1)*3, :] = vals * vecs
    # Resort the columns before returning array
    axes = axes[:, [2, 1, 0]]
    torf = None
    if 'fract' in kwargs:
        fract = float(kwargs['fract'])
        assert 0.33 < fract < 1.0, 'fract must be > 0.33 and < 1.0'
        variances = variances[:, [2, 1, 0]]
        torf = variances[:, 0] / variances.sum(1) > fract
    elif 'ratio' in kwargs or 'ratio3' in kwargs or 'ratio2' in kwargs:
        if 'ratio2' in kwargs:
            ratio = float(kwargs['ratio2'])
            assert 0 < ratio < 1.0, 'ratio2 must be > 0 and < 1.0'
            dim = 1
        else:
            ratio = float(kwargs.get('ratio', kwargs.get('ratio3')))
            assert 0 < ratio < 1.0, 'ratio or ratio3 must be > 0 and < 1.0'
            dim = 2
        variances = variances[:, [2, 1, 0]]
        torf = variances[:, dim] / variances[:, 0] <= ratio
    if torf is not None:
        torf = tile(torf.reshape((n_atoms, 1)), (1, 3)).reshape((n_atoms*3, 1))
        axes = axes * torf
    return axes
Example #49
0
# -*- coding: utf-8 -*-
""" This module defines a class for identifying contacts."""

import numpy as np

from prody import LOGGER
from prody.atomic import AtomPointer
from prody.utilities import importLA

from .measure import calcCenter

linalg = importLA()

__all__ = ['Transformation', 'applyTransformation', 'alignCoordsets',
           'calcRMSD', 'calcTransformation', 'superpose',
           'moveAtoms', 'wrapAtoms',
           'printRMSD']


class Transformation(object):

    """A class for storing a transformation matrix."""

    __slots__ = ['_matrix']

    def __init__(self, *args):
        """Either 4x4 transformation *matrix*, or *rotation* matrix and
        *translation* vector must be provided at instantiation."""

        nargs = len(args)
        if nargs == 1:
Example #50
0
def reduceModel(model, atoms, select):
    """Returns reduced NMA model.  Reduces a :class:`.NMA` model to a subset of
    *atoms* matching *select*.  This function behaves differently depending on
    the type of the *model* argument.  For :class:`.ANM` and :class:`.GNM` or
    other :class:`.NMA` models, force constant matrix for system of interest
    (specified by the *select*) is derived from the force constant matrix for
    the *model* by assuming that for any given displacement of the system of
    interest, other atoms move along in such a way as to minimize the potential
    energy.  This is based on the formulation in [KH00]_.  For :class:`.PCA`
    models, this function simply takes the sub-covariance matrix for selection.

    .. [KH00] Hinsen K, Petrescu A-J, Dellerue S, Bellissent-Funel M-C, Kneller GR.
       Harmonicity in slow protein dynamics. *Chem Phys* **2000** 261:25-37.

    :arg model: dynamics model
    :type model: :class:`.ANM`, :class:`.GNM`, or :class:`.PCA`

    :arg atoms: atoms that were used to build the model
    :type atoms: :class:`.Atomic`

    :arg select: an atom selection or a selection string
    :type select: :class:`.Selection`, str

    :returns: (:class:`.NMA`, :class:`.Selection`)"""

    linalg = importLA()

    if not isinstance(model, NMA):
        raise TypeError('model must be an NMA instance, not {0}'
                        .format(type(model)))
    if not isinstance(atoms, (AtomGroup, AtomSubset, AtomMap)):
        raise TypeError('atoms type is not valid')
    if len(atoms) <= 1:
        raise TypeError('atoms must contain more than 1 atoms')

    if isinstance(model, GNM):
        matrix = model._kirchhoff
    elif isinstance(model, ANM):
        matrix = model._hessian
    elif isinstance(model, PCA):
        matrix = model._cov
    else:
        raise TypeError('model does not have a valid type derived from NMA')
    if matrix is None:
        raise ValueError('model matrix (Hessian/Kirchhoff/Covariance) is not '
                         'built')

    which, select = sliceAtoms(atoms, select)
    system = np.zeros(model.numAtoms(), dtype=bool)
    system[which] = True

    other = np.invert(system)

    if model.is3d():
        system = np.repeat(system, 3)
        other = np.repeat(other, 3)
    ss = matrix[system, :][:, system]
    if isinstance(model, PCA):
        eda = PCA(model.getTitle() + ' reduced')
        eda.setCovariance(ss)
        return eda, system
    so = matrix[system, :][:, other]
    os = matrix[other, :][:, system]
    oo = matrix[other, :][:, other]

    if other.any():
        try:
            invoo = linalg.inv(oo)
        except:
            invoo = linalg.pinv(oo)
        
        matrix = ss - np.dot(so, np.dot(invoo, os))
    else:
        matrix = ss

    if isinstance(model, GNM):
        gnm = GNM(model.getTitle() + ' reduced')
        gnm.setKirchhoff(matrix)
        return gnm, select
    elif isinstance(model, ANM):
        anm = ANM(model.getTitle() + ' reduced')
        anm.setHessian(matrix)
        return anm, select
    elif isinstance(model, PCA):
        eda = PCA(model.getTitle() + ' reduced')
        eda.setCovariance(matrix)
        return eda, select