def setCoords(self, coords): """Set *coords* as the ensemble reference coordinate set. *coords* may be an array with suitable data type, shape, and dimensionality, or an object with :meth:`getCoords` method.""" atoms = coords try: if isinstance(coords, Ensemble): coords = copy(coords._coords) else: coords = coords.getCoords() except AttributeError: pass finally: if coords is None: raise ValueError('coordinates of {0} are not set' .format(str(atoms))) try: checkCoords(coords, natoms=self._n_atoms) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') self._coords = coords self._n_atoms = coords.shape[0]
def addCoordset(self, coords): """Add coordinate set(s) to the ensemble. *coords* must be a Numpy array with suitable data type, shape and dimensionality, or an object with :meth:`getCoordsets` method.""" n_atoms = self._n_atoms n_select = self.numSelected() try: if self._coords is not None: if isinstance(coords, Ensemble): coords = coords._getCoordsets(selected=False) elif hasattr(coords, '_getCoordsets'): coords = coords._getCoordsets() elif hasattr(coords, '_getCoords'): coords = coords._getCoords() coords = array(coords) else: if isinstance(coords, Ensemble): coords = coords.getCoordsets(selected=False) elif hasattr(coords, 'getCoordsets'): coords = coords.getCoordsets() elif hasattr(coords, 'getCoords'): coords = coords.getCoords() coords = array(coords) except AttributeError: pass else: if coords is None: raise ValueError('coordinates are not set') try: checkCoords(coords, csets=True, natoms=n_atoms) except: try: checkCoords(coords, csets=True, natoms=n_select) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') if coords.ndim == 2: n_nodes, _ = coords.shape coords = coords.reshape((1, n_nodes, 3)) n_confs = 1 else: n_confs, n_nodes, _ = coords.shape if not n_atoms: self._n_atoms = n_atoms = n_nodes if n_nodes == n_select and self.isSelected(): full_coords = repeat(self._coords[newaxis, :, :], n_confs, axis=0) full_coords[:, self._indices, :] = coords coords = full_coords if self._confs is None: self._confs = coords else: self._confs = concatenate((self._confs, coords), axis=0) self._n_csets += n_confs
def setCoords(self, coords, label=None): """Set coordinates of atoms. *coords* may be any array like object or an object instance with :meth:`getCoords` method. If the shape of coordinate array is ``(n_csets > 1, n_atoms, 3)``, it will replace all coordinate sets and the active coordinate set index will reset to zero. This situation can be avoided using :meth:`addCoordset`. If shape of *coords* is ``(n_atoms, 3)`` or ``(1, n_atoms, 3)``, it will replace the active coordinate set. *label* argument may be used to label coordinate set(s). *label* may be a string or a list of strings length equal to the number of coordinate sets.""" atoms = coords try: if self._coords is None and hasattr(atoms, '_getCoords'): coords = atoms._getCoords() else: coords = atoms.getCoords() except AttributeError: if self._coords is None: coords = np.array(coords) else: if coords is None: raise ValueError('coordinates of {0} are not set' .format(str(atoms))) try: checkCoords(coords, csets=True, dtype=(float, np.float32)) except TypeError: raise TypeError('coords must be a numpy array or an ' 'object with `getCoords` method') self._setCoords(coords, label=label)
def buildHessian(self, coords, blocks, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg blocks: a list or array of block identifiers :type blocks: list, :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float """ try: 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') super(RTB, self).buildHessian(coords, cutoff=cutoff, gamma=gamma, **kwargs) self.calcProjection(coords, blocks, **kwargs)
def calcCenter(atoms, weights=None): """Returns geometric center of *atoms*. If *weights* is given it must be a flat array with length equal to number of atoms. Mass center of atoms can be calculated by setting weights equal to atom masses, i.e. ``weights=atoms.getMasses()``.""" try: coords = atoms._getCoords() except AttributeError: try: coords = atoms.getCoords() except AttributeError: coords = atoms try: checkCoords(coords, csets=True, dtype=None, name='atoms') except TypeError: raise TypeError('atoms must be an Atomic instance') if weights is not None: try: ndim, shape = weights.ndim, weights.shape except AttributeError: raise TypeError('weights must be a numpy array') else: if shape[0] != coords.shape[-2]: raise ValueError('weights.shape[0] must be equal to number of ' 'atoms') if ndim != 2: try: weights = weights.reshape((shape[0], 1)) except ValueError: raise ValueError('weights.shape must be a (n_atoms, 1)') return getCenter(coords, weights)
def calcCenter(atoms, weights=None): """Return geometric center of *atoms*. If *weights* is given it must be a flat array with length equal to number of atoms. Mass center of atoms can be calculated by setting weights equal to atom masses, i.e. ``weights=atoms.getMasses()``.""" try: coords = atoms._getCoords() except AttributeError: try: coords = atoms.getCoords() except AttributeError: coords = atoms try: checkCoords(coords, csets=True, dtype=None, name='atoms') except TypeError: raise TypeError('atoms must be an Atomic instance') if weights is not None: try: ndim, shape = weights.ndim, weights.shape except AttributeError: raise TypeError('weights must be a numpy array') else: if shape[0] != coords.shape[-2]: raise ValueError('weights.shape[0] must be equal to number of ' 'atoms') if ndim != 2: try: weights = weights.reshape((shape[0], 1)) except ValueError: raise ValueError('weights.shape must be a (n_atoms, 1)') return getCenter(coords, weights)
def calcMechStiff(modes, coords, kbt=1.): """Calculate stiffness matrix calculated using :class:`.ANM` instance. Method described in [EB08]_ and [KMR17]_. .. [KMR] Mikulska-Ruminska K., Kulik A.J., Benadiba C., Bahar I., Dietler G., Nowak W. Nanomechanics of multidomain neuronal cell adhesion protein contactin revealed by single molecule AFM and SMD. *Sci Rep* **2017** 7:8852. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray`. :arg n_modes: number of non-zero eigenvalues/vectors to calculate. If **None** is given, all modes will be calculated (3x number of atoms). :type n_modes: int or **None**, default is 20. Authors: Mustafa Tekpinar & Karolina Mikulska-Ruminska & Cihan Kaya """ try: 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') try: is3d = modes.is3d() eigvecs = modes.getArray().T.flatten() eigvals = modes.getEigvals() except: raise TypeError('modes must be either an NMA or ModeSet object') if not is3d: raise TypeError('modes must be 3-dimensional') n_atoms = modes.numAtoms() n_modes = modes.numModes() LOGGER.timeit('_sm') sm = np.zeros((n_atoms, n_atoms), np.double) from .smtools import calcSM LOGGER.info('Calculating stiffness matrix.') calcSM(coords, sm, eigvecs, eigvals, n_atoms, n_modes, float(kbt)) LOGGER.report('Stiffness matrix calculated in %.2lfs.', label='_sm') LOGGER.info('The range of effective force constant is: {0} to {1}.'.format( *calcStiffnessRange(sm))) return sm
def buildHessian(self, coords, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. **kwargs** are passed to :method:`.buildMembrane`. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float """ atoms = coords turbo = kwargs.pop('turbo', True) try: 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') n_atoms = int(coords.shape[0]) if self._membrane is None: coords = self.buildMembrane(atoms, **kwargs) else: coords = self._combined.getCoords() system = zeros(coords.shape[0], dtype=bool) system[:n_atoms] = True LOGGER.timeit('_exanm') if turbo: self._hessian = buildReducedHessian(coords, system, cutoff, gamma, **kwargs) else: super(exANM, self).buildHessian(coords, cutoff, gamma, **kwargs) system = np.repeat(system, 3) self._hessian = _reduceModel(self._hessian, system) LOGGER.report('Hessian was built in %.2fs.', label='_exanm') self._dof = self._hessian.shape[0] self._n_atoms = n_atoms
def calcMechStiff(modes, coords, kbt=1.): """Calculate stiffness matrix calculated using :class:`.ANM` instance. Method described in [EB08]_. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray`. :arg n_modes: number of non-zero eigenvalues/vectors to calculate. If **None** is given, all modes will be calculated (3x number of atoms). :type n_modes: int or **None**, default is 20. Author: Mustafa Tekpinar & Karolina Mikulska-Ruminska & Cihan Kaya """ try: 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') try: is3d = modes.is3d() eigvecs = modes.getArray().T.flatten() eigvals = modes.getEigvals() except: raise TypeError('modes must be either an NMA or ModeSet object') if not is3d: raise TypeError('modes must be 3-dimensional') n_atoms = modes.numAtoms() n_modes = modes.numModes() LOGGER.timeit('_sm') sm = np.zeros((n_atoms, n_atoms), np.double) from .smtools import calcSM LOGGER.info('Calculating stiffness matrix.') calcSM(coords, sm, eigvecs, eigvals, n_atoms, n_modes, float(kbt)) LOGGER.report('Stiffness matrix calculated in %.2lfs.', label='_sm') LOGGER.info('The range of effective force constant is: {0} to {1}.' .format(*calcStiffnessRange(sm))) return sm
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
def buildMechStiff(self, coords, n_modes=None, kbt=1.): """Calculate stiffness matrix calculated using :class:`.ANM` instance. Method described in [EB08]_. .. [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 coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray`. :arg n_modes: number of non-zero eigenvalues/vectors to calculate. If ``None`` is given, all modes will be calculated (3x number of atoms). :type n_modes: int or ``None``, default is 20. Author: Mustafa Tekpinar & Karolina Mikulska-Ruminska & Cihan Kaya """ try: 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') n_atoms = natoms = self._n_atoms n_modes = 3 * n_atoms self.calcModes(n_modes=None, zeros=True) LOGGER.timeit('_sm') eigvecs = (np.transpose(self._array)).flatten() eigvals = np.transpose(self._eigvals) natoms = n_atoms sm = np.zeros((n_atoms, n_atoms), np.double) from .smtools import calcSM LOGGER.info('Calculating stiffness matrix.') calcSM(coords, sm, eigvecs, eigvals, natoms, n_modes, float(kbt)) LOGGER.report('Stiffness matrix calculated in %.2lfs.', label='_sm') self._stiffness = sm LOGGER.info('The range of effective force constant is: {0} to {1}.' .format(np.min(sm[np.nonzero(sm)]), np.amax(sm)))
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
def addCoordset(self, coords, label=None): """Add a coordinate set. *coords* argument may be an object with :meth:`getCoordsets` method.""" if self._coords is None: return self.setCoords(coords) n_atoms = self._n_atoms atoms = coords try: coords = (atoms._getCoordsets() if hasattr(coords, '_getCoordsets') else atoms.getCoordsets()) except AttributeError: pass else: if coords is None: raise ValueError('coordinates of {0} are not set' .format(str(atoms))) try: checkCoords(coords, csets=True, natoms=n_atoms, dtype=None) except TypeError: raise TypeError('coords must be a numpy array or an ' 'object with `getCoords` method') if coords.ndim == 2: coords = coords.reshape((1, n_atoms, 3)) diff = coords.shape[0] self._coords = np.concatenate((self._coords, coords), axis=0) self._n_csets = self._coords.shape[0] timestamps = self._timestamps self._timestamps = np.zeros(self._n_csets) self._timestamps[:len(timestamps)] = timestamps self._timestamps[len(timestamps):] = time() self._kdtrees.extend([None] * diff) if label is None or isinstance(label, str): self._cslabels.extend([label] * diff) elif isinstance(label, (list, tuple)): if len(label) == diff: self._cslabels.extend([str(lbl) for lbl in label]) else: LOGGER.warn('Number of labels does not match number ' 'of coordinate sets.') else: LOGGER.warn('Wrong type for `label` argument.')
def addCoordset(self, coords): """Add coordinate set(s) to the ensemble. *coords* must be a Numpy array with suitable data type, shape and dimensionality, or an object with :meth:`getCoordsets` method.""" n_atoms = self._n_atoms try: if self._coords is not None: if hasattr(coords, '_getCoordsets'): coords = coords._getCoordsets() elif hasattr(coords, '_getCoords'): coords = coords._getCoords() coords = array(coords) else: if hasattr(coords, 'getCoordsets'): coords = coords.getCoordsets() elif hasattr(coords, 'getCoords'): coords = coords.getCoords() coords = array(coords) except AttributeError: pass else: if coords is None: raise ValueError('coordinates are not set') try: checkCoords(coords, csets=True, natoms=n_atoms) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') if not n_atoms: self._n_atoms = n_atoms = coords.shape[-2] if coords.ndim == 2: coords = coords.reshape((1, n_atoms, 3)) n_confs = 1 else: n_confs = coords.shape[0] if self._confs is None: self._confs = coords else: self._confs = concatenate((self._confs, coords), axis=0) self._n_csets += n_confs
def calcDistanceMatrix(coords, cutoff=None): """Calculate matrix of distances between coordinates within *cutoff*. Other matrix entries are set to maximum of calculated distances. :arg coords: a coordinate set or an object with :meth:`getCoords` method. :type coords: :class:`~numpy.ndarray`, :class:`.Atomic` :arg cutoff: cutoff distance for searching the KDTree. Default (**None**) is to use the length of the longest coordinate axis. :type cutoff: None, float """ try: 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') n_atoms = coords.shape[0] dist_mat = zeros((n_atoms, n_atoms)) if cutoff is None: cutoff = max(coords.max(axis=0) - coords.min(axis=0)) kdtree = KDTree(coords) kdtree.search(cutoff) dists = kdtree.getDistances() r = 0 for i, j in kdtree.getIndices(): dist_mat[i, j] = dist_mat[j, i] = dists[r] r += 1 for i in range(n_atoms): for j in range(i + 1, n_atoms): if dist_mat[i, j] == 0.: dist_mat[i, j] = dist_mat[j, i] = max(dists) return dist_mat
def buildHessian(self, coords, blocks, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float""" try: 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') LOGGER.timeit('_rtb') natoms = coords.shape[0] if (natoms,) != blocks.shape: raise ValueError('blocks.shape must be (natoms,)') nblocks = len(set(blocks)) nb6 = nblocks * 6 coords = coords.T.copy() self._hessian = hessian = np.zeros((nb6, nb6), float) self._project = project = np.zeros((natoms * 3, nb6), float) from rtbtools import buildhessian buildhessian(coords, blocks, hessian, project, natoms, nblocks, float(cutoff), float(gamma)) LOGGER.report('Hessian was built in %.2fs.', label='_rtb')
def buildHessian(self, coords, blocks, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float""" try: 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') LOGGER.timeit('_rtb') natoms = coords.shape[0] if (natoms, ) != blocks.shape: raise ValueError('blocks.shape must be (natoms,)') nblocks = len(set(blocks)) nb6 = nblocks * 6 coords = coords.T.copy() self._hessian = hessian = np.zeros((nb6, nb6), float) self._project = project = np.zeros((natoms * 3, nb6), float) from rtbtools import buildhessian buildhessian(coords, blocks, hessian, project, natoms, nblocks, float(cutoff), float(gamma)) LOGGER.report('Hessian was built in %.2fs.', label='_rtb')
def setCoords(self, coords): """Set *coords* as the trajectory reference coordinate set. *coords* must be an object with :meth:`getCoords` method, or a Numpy array with suitable data type, shape, and dimensionality.""" atoms = coords try: coords = atoms.getCoords() except AttributeError: pass else: if coords is None: raise ValueError('coordinates of {0:s} are not set' .format(str(atoms))) try: checkCoords(coords, natoms=self._n_atoms) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') self._coords = coords
def setCoords(self, coords): """Set *coords* as the trajectory reference coordinate set. *coords* must be an object with :meth:`getCoords` method, or a Numpy array with suitable data type, shape, and dimensionality.""" atoms = coords try: coords = atoms.getCoords() except AttributeError: pass else: if coords is None: raise ValueError('coordinates of {0} are not set'.format( str(atoms))) try: checkCoords(coords, natoms=self._n_atoms) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') self._coords = coords
def buildHessian(self, coords, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg membrane_hi: the maximum z coordinate of the pdb default is 13.0 :type membrane_hi: float :arg membrane_lo: the minimum z coordinate of the pdb default is -13.0 :type membrane_lo: float :arg R: radius of all membrane in x-y direction default is 80. :type R: float :arg r: radius of individual barrel-type membrane protein default is 2.5. :type :arg lat: lattice type which could be FCC(face-centered-cubic)(default), SC(simple cubic), SH(simple hexagonal) :type lat: str """ try: 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') self._n_atoms = natoms = int(coords.shape[0]) if self._membrane is None: membrane_hi = float(kwargs.get('membrane_hi', 13.0)) membrane_lo = float(kwargs.get('membrane_lo', -13.0)) R = float(kwargs.get('R', 80)) r = float(kwargs.get('r', 5)) lat = str(kwargs.get('lat', 'FCC')) buildMembrane(self,coords,membrane_hi=membrane_hi, membrane_lo=membrane_lo,R=R,r=r,lat=lat) LOGGER.timeit('_exanm') coords = np.concatenate((coords,self._membrane.getCoords()),axis=0) self._combined_coords = coords total_natoms = int(coords.shape[0]) self._hessian = np.zeros((natoms*3, natoms*3), float) total_hessian = np.zeros((total_natoms*3, total_natoms*3), float) cutoff, g, gamma = checkENMParameters(cutoff, gamma) cutoff2 = cutoff * cutoff for i in range(total_natoms): res_i3 = i*3 res_i33 = res_i3+3 i_p1 = i+1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all ** 2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma(dist2, i, j) res_j3 = j*3 res_j33 = res_j3+3 super_element = np.outer(i2j, i2j) * (- g / dist2) total_hessian[res_i3:res_i33, res_j3:res_j33] = super_element total_hessian[res_j3:res_j33, res_i3:res_i33] = super_element total_hessian[res_i3:res_i33, res_i3:res_i33] = total_hessian[res_i3:res_i33, res_i3:res_i33] - super_element total_hessian[res_j3:res_j33, res_j3:res_j33] = total_hessian[res_j3:res_j33, res_j3:res_j33] - super_element ss = total_hessian[:natoms*3, :natoms*3] so = total_hessian[:natoms*3, natoms*3+1:] os = total_hessian[natoms*3+1:,:natoms*3] oo = total_hessian[natoms*3+1:, natoms*3+1:] self._hessian = ss - np.dot(so, np.dot(linalg.inv(oo), os)) LOGGER.report('Hessian was built in %.2fs.', label='_exanm') self._dof = self._hessian.shape[0]
def buildKirchhoff(self, coords, cutoff=10., gamma=1., **kwargs): """Build Kirchhoff matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` or :class:`.Atomic` :arg cutoff: cutoff distance (Å) for pairwise interactions default is 10.0 Å, , minimum is 4.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg sparse: elect to use sparse matrices, default is **False**. If Scipy is not found, :class:`ImportError` is raised. :type sparse: bool :arg kdtree: elect to use KDTree for building Kirchhoff matrix faster, default is **True** :type kdtree: bool Instances of :class:`Gamma` classes and custom functions are accepted as *gamma* argument. When Scipy is available, user can select to use sparse matrices for efficient usage of memory at the cost of computation speed.""" try: 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') cutoff, g, gamma = checkENMParameters(cutoff, gamma) self._reset() self._cutoff = cutoff self._gamma = g n_atoms = coords.shape[0] start = time.time() if kwargs.get('sparse', False): try: from scipy import sparse as scipy_sparse except ImportError: raise ImportError('failed to import scipy.sparse, which is ' 'required for sparse matrix calculations') kirchhoff = scipy_sparse.lil_matrix((n_atoms, n_atoms)) else: kirchhoff = np.zeros((n_atoms, n_atoms), 'd') if kwargs.get('kdtree', True): kdtree = KDTree(coords) kdtree.search(cutoff) dist2 = kdtree.getDistances() ** 2 r = 0 for i, j in kdtree.getIndices(): g = gamma(dist2[r], i, j) kirchhoff[i, j] = -g kirchhoff[j, i] = -g kirchhoff[i, i] = kirchhoff[i, i] + g kirchhoff[j, j] = kirchhoff[j, j] + g r += 1 else: LOGGER.info('Using slower method for building the Kirchhoff.') cutoff2 = cutoff * cutoff mul = np.multiply for i in range(n_atoms): xyz_i = coords[i, :] i_p1 = i+1 i2j = coords[i_p1:, :] - xyz_i mul(i2j, i2j, i2j) for j, dist2 in enumerate(i2j.sum(1)): if dist2 > cutoff2: continue j += i_p1 g = gamma(dist2, i, j) kirchhoff[i, j] = -g kirchhoff[j, i] = -g kirchhoff[i, i] = kirchhoff[i, i] + g kirchhoff[j, j] = kirchhoff[j, j] + g LOGGER.debug('Kirchhoff was built in {0:.2f}s.' .format(time.time()-start)) self._kirchhoff = kirchhoff self._n_atoms = n_atoms self._dof = n_atoms
def addCoordset(self, coords, weights=None, label=None): """Add coordinate set(s) to the ensemble. *coords* must be a Numpy array with suitable shape and dimensionality, or an object with :meth:`getCoordsets` method. *weights* is an optional argument. If provided, its length must match number of atoms. Weights of missing (not resolved) atoms must be ``0`` and weights of those that are resolved can be anything greater than ``0``. If not provided, weights of all atoms for this coordinate set will be set equal to ``1``. *label*, which may be a PDB identifier or a list of identifiers, is used to label conformations.""" atoms = coords try: if self._coords is not None and hasattr(coords, '_getCoordsets'): coords = coords._getCoordsets() else: coords = coords.getCoordsets() except AttributeError: label = label or 'Unknown' else: if coords is None: raise ValueError('coordinates are not set') elif label is None and isinstance(atoms, Atomic): ag = atoms if not isinstance(atoms, AtomGroup): ag = atoms.getAtomGroup() label = ag.getTitle() if coords.shape[0] < ag.numCoordsets(): label += 'm' + str(atoms.getACSIndex()) else: label = label or str(coords) try: checkCoords(coords, csets=True, natoms=self._n_atoms) except TypeError: raise TypeError('coords must be a Numpy array or must have ' '`getCoords` attribute') if coords.ndim == 2: coords = coords.reshape((1, self._n_atoms, 3)) n_csets, n_atoms, _ = coords.shape if not self._n_atoms: self._n_atoms = n_atoms if weights is None: weights = np.ones((n_csets, n_atoms, 1), dtype=float) else: weights = checkWeights(weights, n_atoms, n_csets) if n_csets > 1: if isinstance(label, str): self._labels.extend('{0}_m{1}' .format(label, i+1) for i in range(n_csets)) else: if len(label) != n_csets: raise ValueError('length of label and number of ' 'coordinate sets must be the same') self._labels.extend(label) else: self._labels.append(label) if self._confs is None and self._weights is None: self._confs = coords self._weights = weights self._n_csets = n_csets elif self._confs is not None and self._weights is not None: self._confs = np.concatenate((self._confs, coords), axis=0) self._weights = np.concatenate((self._weights, weights), axis=0) self._n_csets += n_csets else: raise RuntimeError('_confs and _weights must be set or None at ' 'the same time')
def buildMembrane(self, coords, **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg membrane_hi: the maximum z coordinate of the pdb default is 13.0 :type membrane_hi: float :arg membrane_lo: the minimum z coordinate of the pdb default is -13.0 :type membrane_lo: float :arg R: radius of all membrane in x-y direction default is 80. :type R: float :arg r: radius of individual barrel-type membrane protein default is 2.5. :type :arg lat: lattice type which could be FCC(face-centered-cubic)(default), SC(simple cubic), SH(simple hexagonal) :type lat: str """ if type(coords) is AtomGroup: buildAg = True else: buildAg = False try: 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') self._n_atoms = natoms = int(coords.shape[0]) pxlo = min(np.append(coords[:, 0], 10000)) pxhi = max(np.append(coords[:, 0], -10000)) pylo = min(np.append(coords[:, 1], 10000)) pyhi = max(np.append(coords[:, 1], -10000)) pzlo = min(np.append(coords[:, 2], 10000)) pzhi = max(np.append(coords[:, 2], -10000)) membrane_hi = float(kwargs.get('membrane_hi', 13.0)) membrane_lo = float(kwargs.get('membrane_lo', -13.0)) R = float(kwargs.get('R', 80)) r = float(kwargs.get('r', 5)) lat = str(kwargs.get('lat', 'FCC')) lpv = assign_lpvs(lat) imax = (R + lpv[0, 2] * (membrane_hi - membrane_lo) / 2.) / r jmax = (R + lpv[1, 2] * (membrane_hi - membrane_lo) / 2.) / r kmax = (R + lpv[2, 2] * (membrane_hi - membrane_lo) / 2.) / r #print pxlo, pxhi, pylo, pyhi, pzlo, pzhi #print lpv[0,2],lpv[1,2],lpv[2,2] #print R,r,imax,jmax,kmax membrane = zeros((1, 3)) LOGGER.timeit('_membrane') membrane = zeros((1, 3)) atm = 0 for i in range(-int(imax), int(imax + 1)): for j in range(-int(jmax), int(jmax + 1)): for k in range(-int(kmax), int(kmax + 1)): X = zeros((1, 3)) for p in range(3): X[0, p] = 2. * r * (i * lpv[0, p] + j * lpv[1, p] + k * lpv[2, p]) dd = 0 for p in range(3): dd += X[0, p]**2 if dd < R**2 and X[0, 2] > membrane_lo and X[0, 2] < membrane_hi: if X[0, 0] > pxlo - R / 2 and X[ 0, 0] < pxhi + R / 2 and X[ 0, 1] > pylo - R / 2 and X[ 0, 1] < pyhi + R / 2 and X[ 0, 2] > pzlo and X[0, 2] < pzhi: if checkClash(X, coords[:natoms, :], radius=5): if atm == 0: membrane = X else: membrane = np.append(membrane, X, axis=0) atm = atm + 1 #print atm self._membrane = AtomGroup(title="Membrane") self._membrane.setCoords(membrane) self._membrane.setResnums(list(range(atm))) self._membrane.setResnames(["NE1" for i in range(atm)]) self._membrane.setChids(["Q" for i in range(atm)]) self._membrane.setElements(["Q1" for i in range(atm)]) self._membrane.setNames(["Q1" for i in range(atm)]) LOGGER.report('Membrane was built in %2.fs.', label='_membrane')
def testCoords(self): self.assertTrue(checkCoords(COORDS))
def buildMembrane(self, coords, **kwargs): """Build membrane lattice around **coords**. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg membrane_high: the maximum z coordinate of the membrane. Default is **13.0** :type membrane_high: float :arg membrane_low: the minimum z coordinate of the membrane. Default is **-13.0** :type membrane_low: float :arg R: radius of all membrane in x-y direction. Default is **80** :type R: float :arg Ri: inner radius of the membrane in x-y direction if it needs to be hollow. Default is **0**, which is not hollow :type Ri: float :arg r: radius of each membrane node. Default is **3.1** :type r: float :arg lat: lattice type which could be **FCC** (face-centered-cubic, default), **SC** (simple cubic), **SH** (simple hexagonal) :type lat: str :arg exr: exclusive radius of each protein node. Default is **5.0** :type exr: float :arg hull: whether use convex hull to determine the protein's interior. Turn it off if protein is multimer. Default is **True** :type hull: bool :arg center: whether transform the structure to the origin (only x- and y-axis). Default is **True** :type center: bool """ atoms = coords try: 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') self._n_atoms = int(coords.shape[0]) LOGGER.timeit('_membrane') depth = kwargs.pop('depth', None) h = depth / 2 if depth is not None else None h = kwargs.pop('h', h) if h is not None: h = float(h) hu = h hl = -h else: hu = kwargs.pop('membrane_high', 13.0) hu = kwargs.pop('high', hu) hu = float(hu) hl = kwargs.pop('membrane_low', -13.0) hl = kwargs.pop('low', hl) hl = float(hl) R = float(kwargs.pop('R', 80.)) Ri = float(kwargs.pop('Ri', 0.)) r = float(kwargs.pop('r', 3.1)) lat = str(kwargs.pop('lat', 'FCC')) exr = float(kwargs.pop('exr', 5.)) use_hull = kwargs.pop('hull', True) centering = kwargs.pop('center', True) V = assign_lpvs(lat) if centering: c0 = coords.mean(axis=0) c0[-1] = 0. coords -= c0 # determine transmembrane part torf = np.logical_and(coords[:, -1] < hu, coords[:, -1] > hl) transmembrane = coords[torf, :] if not np.any(torf): raise ValueError( 'No region was identified as membrane. Please use a structure from opm/ppm.' ) if use_hull: from scipy.spatial import ConvexHull hull = ConvexHull(transmembrane) else: hull = transmembrane ## determine the bound for ijk imax = (R + V[0, 2] * (hu - hl) / 2.) / r jmax = (R + V[1, 2] * (hu - hl) / 2.) / r kmax = (R + V[2, 2] * (hu - hl) / 2.) / r imax = int(ceil(imax)) jmax = int(ceil(jmax)) kmax = int(ceil(kmax)) membrane = [] atm = 0 for i in range(-imax, imax): for j in range(-jmax, jmax): for k in range(-kmax, kmax): c = array([i, j, k]) xyz = 2. * r * dot(c, V) if xyz[2]>hl and xyz[2]<hu and \ xyz[0]>-R and xyz[0]<R and \ xyz[1]>-R and xyz[1]<R: dd = norm(xyz[:2]) if dd < R and dd > Ri: if checkClash(xyz, hull, radius=exr): membrane.append(xyz) atm = atm + 1 membrane = array(membrane) if len(membrane) == 0: self._membrane = None LOGGER.warn( 'no membrane is built. The protein should be transformed to the correct origin as in OPM' ) return coords else: self._membrane = AtomGroup(title="Membrane") self._membrane.setCoords(membrane) self._membrane.setResnums(range(atm)) self._membrane.setResnames(["NE1" for i in range(atm)]) self._membrane.setChids(["Q" for i in range(atm)]) self._membrane.setElements(["Q1" for i in range(atm)]) self._membrane.setNames(["Q1" for i in range(atm)]) LOGGER.report('Membrane was built in %2.fs.', label='_membrane') coords = self._combineMembraneProtein(atoms) return coords
def addCoordset(self, coords, **kwargs): """Add coordinate set(s) to the ensemble. :arg coords: must be a :class:`~numpy.ndarray` with suitable data type, shape and dimensionality, or an object with :meth:`getCoordsets` method. :kwarg data: associated data to be added along with *coords*. :type data: dict """ n_atoms = self._n_atoms n_select = self.numSelected() adddata = kwargs.pop('data', {}) try: if self._coords is not None: if isinstance(coords, Ensemble): coords = coords._getCoordsets(selected=False) elif hasattr(coords, '_getCoordsets'): coords = coords._getCoordsets() elif hasattr(coords, '_getCoords'): coords = coords._getCoords() coords = array(coords) else: if isinstance(coords, Ensemble): coords = coords.getCoordsets(selected=False) elif hasattr(coords, 'getCoordsets'): coords = coords.getCoordsets() elif hasattr(coords, 'getCoords'): coords = coords.getCoords() coords = array(coords) except AttributeError: pass else: if coords is None: raise ValueError('coordinates are not set') try: checkCoords(coords, csets=True, natoms=n_atoms) except: try: checkCoords(coords, csets=True, natoms=n_select) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') # update coordinates if coords.ndim == 2: n_nodes, _ = coords.shape coords = coords.reshape((1, n_nodes, 3)) n_confs = 1 else: n_confs, n_nodes, _ = coords.shape if not n_atoms: self._n_atoms = n_atoms = n_nodes if n_nodes == n_select and self.isSelected(): full_coords = repeat(self._coords[newaxis, :, :], n_confs, axis=0) full_coords[:, self._indices, :] = coords coords = full_coords if self._confs is None: self._confs = coords else: self._confs = concatenate((self._confs, coords), axis=0) # appending new data if self._data is None: self._data = {} all_keys = set(list(self._data.keys()) + list(adddata.keys())) for key in all_keys: if key in self._data: data = self._data[key] if key not in adddata: shape = [n_confs] for s in data.shape[1:]: shape.append(s) newdata = zeros(shape, dtype=data.dtype) else: newdata = asarray(adddata[key]) if newdata.shape[0] != n_confs: raise ValueError( 'the length of data["%s"] does not match that of coords' % key) else: newdata = asarray(adddata[key]) shape = [self._n_csets] for s in newdata.shape[1:]: shape.append(s) data = zeros(shape, dtype=newdata.dtype) self._data[key] = concatenate((data, newdata), axis=0) # update the number of coordinate sets self._n_csets += n_confs
def addCoordset(self, coords, weights=None, label=None, **kwargs): """Add coordinate set(s) to the ensemble. *coords* must be a Numpy array with suitable shape and dimensionality, or an object with :meth:`getCoordsets`. *weights* is an optional argument. If provided, its length must match number of atoms. Weights of missing (not resolved) atoms must be ``0`` and weights of those that are resolved can be anything greater than ``0``. If not provided, weights of all atoms for this coordinate set will be set equal to ``1``. *label*, which may be a PDB identifier or a list of identifiers, is used to label conformations.""" degeneracy = kwargs.pop('degeneracy', False) adddata = kwargs.pop('data', None) atoms = coords n_atoms = self._n_atoms n_select = self.numSelected() n_confs = self.numCoordsets() try: if degeneracy: if self._coords is not None: if isinstance(coords, Ensemble): coords = coords._getCoords(selected=False) elif hasattr(coords, '_getCoords'): coords = coords._getCoords() else: if isinstance(coords, Ensemble): coords = coords.getCoords(selected=False) elif hasattr(coords, 'getCoords'): coords = coords.getCoords() else: if self._coords is not None: if isinstance(coords, Ensemble): coords = coords._getCoordsets(selected=False) elif hasattr(coords, '_getCoordsets'): coords = coords._getCoordsets() else: if isinstance(coords, Ensemble): coords = coords.getCoordsets(selected=False) elif hasattr(coords, 'getCoordsets'): coords = coords.getCoordsets() except AttributeError: label = label or 'Unknown' else: if coords is None: raise ValueError('coordinates are not set') elif label is None and isinstance(atoms, Atomic): if not isinstance(atoms, AtomGroup): ag = atoms.getAtomGroup() else: ag = atoms label = ag.getTitle() if coords.shape[0] < ag.numCoordsets(): label += '_m' + str(atoms.getACSIndex()) else: label = label or 'Unknown' # check coordinates try: checkCoords(coords, csets=True, natoms=n_atoms) except: try: checkCoords(coords, csets=True, natoms=n_select) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') if coords.ndim == 2: n_nodes, _ = coords.shape coords = coords.reshape((1, n_nodes, 3)) n_csets = 1 else: n_csets, n_nodes, _ = coords.shape if degeneracy: coords = coords[:1] n_repeats = 1 if degeneracy else n_csets if not n_atoms: self._n_atoms = n_nodes n_atoms = self._n_atoms if n_nodes == n_select and self.isSelected(): full_coords = np.repeat(self._coords[np.newaxis, :, :], n_csets, axis=0) full_coords[:, self._indices, :] = coords coords = full_coords # check weights if weights is None: weights = np.ones((n_csets, n_atoms, 1), dtype=float) else: weights = checkWeights(weights, n_atoms, n_csets) if degeneracy: weights = weights[:1] # check sequences seqs = None sequence = kwargs.pop('sequence', None) if hasattr(atoms, 'getSequence'): if sequence is not None: LOGGER.warn( 'sequence is supplied though coords has getSequence') sequence = atoms.getSequence() seqs = [sequence for _ in range(n_repeats)] else: if sequence is None: try: sequence = self._atoms.getSequence() except AttributeError: if self._msa: sequence = ''.join('X' for _ in range(n_atoms)) # sequence and seqs remains to be None if MSA has not been created if isinstance(sequence, Sequence): seqs = [str(sequence)] elif isinstance(sequence, MSA): seqs = [str(seq) for seq in sequence] elif np.isscalar(sequence): seqs = [sequence for _ in range(n_repeats)] if seqs: if len(seqs) != n_repeats: raise ValueError( 'the number of sequences should be either one or ' 'that of coordsets') # assign new values # update labels if n_csets > 1 and not degeneracy: if isinstance(label, str): labels = [ '{0}_m{1}'.format(label, i + 1) for i in range(n_csets) ] else: if len(label) != n_csets: raise ValueError('length of label and number of ' 'coordinate sets must be the same') labels = label else: labels = [label] if np.isscalar(label) else label self._labels.extend(labels) # update sequences if seqs: msa = MSA(seqs, title=self.getTitle(), labels=labels) if self._msa is None: if n_confs > 0: def_seqs = np.chararray((n_confs, n_atoms)) def_seqs[:] = 'X' old_labels = [self._labels[i] for i in range(n_confs)] self._msa = MSA(def_seqs, title=self.getTitle(), labels=old_labels) self._msa.extend(msa) else: self._msa = msa else: self._msa.extend(msa) # update coordinates if self._confs is None and self._weights is None: self._confs = coords self._weights = weights elif self._confs is not None and self._weights is not None: self._confs = np.concatenate((self._confs, coords), axis=0) self._weights = np.concatenate((self._weights, weights), axis=0) else: raise RuntimeError('_confs and _weights must be set or None at ' 'the same time') # appending new data if self._data is not None and adddata is not None: if self._data is None: self._data = {} if adddata is None: adddata = {} all_keys = set(list(self._data.keys()) + list(adddata.keys())) for key in all_keys: if key in self._data: data = self._data[key] if key not in adddata: shape = [n_repeats] for s in data.shape[1:]: shape.append(s) newdata = np.zeros(shape, dtype=data.dtype) else: newdata = np.asarray(adddata[key]) if newdata.shape[0] != n_repeats: raise ValueError( 'the length of data["%s"] does not match that of coords' % key) else: newdata = np.asarray(adddata[key]) shape = [self._n_csets] for s in newdata.shape[1:]: shape.append(s) data = np.zeros(shape, dtype=newdata.dtype) self._data[key] = np.concatenate((data, newdata), axis=0) # update the number of coordinate sets self._n_csets += n_repeats
def buildHessian(self, coords, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg membrane_hi: the maximum z coordinate of the pdb default is 13.0 :type membrane_hi: float :arg membrane_lo: the minimum z coordinate of the pdb default is -13.0 :type membrane_lo: float :arg R: radius of all membrane in x-y direction default is 80. :type R: float :arg r: radius of individual barrel-type membrane protein default is 2.5. :type :arg lat: lattice type which could be FCC(face-centered-cubic)(default), SC(simple cubic), SH(simple hexagonal) :type lat: str """ try: 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') self._n_atoms = natoms = int(coords.shape[0]) pxlo = min(np.append(coords[:,0],10000)) pxhi = max(np.append(coords[:,0],-10000)) pylo = min(np.append(coords[:,1],10000)) pyhi = max(np.append(coords[:,1],-10000)) pzlo = min(np.append(coords[:,2],10000)) pzhi = max(np.append(coords[:,2],-10000)) membrane_hi = float(kwargs.get('membrane_hi', 13.0)) membrane_lo = float(kwargs.get('membrane_lo', -13.0)) R = float(kwargs.get('R', 80)) r = float(kwargs.get('r', 2.5)) lat = str(kwargs.get('lat', 'FCC')) lpv = assign_lpvs(lat) imax = (R + lpv[0,2] * (membrane_hi - membrane_lo)/2.)/r jmax = (R + lpv[1,2] * (membrane_hi - membrane_lo)/2.)/r kmax = (R + lpv[2,2] * (membrane_hi - membrane_lo)/2.)/r self._membrane = membrane = zeros((1,3)) LOGGER.timeit('_membrane') atm = 0 for i in range(-int(imax),int(imax+1)): for j in range(-int(jmax),int(jmax+1)): for k in range(-int(kmax),int(kmax+1)): X = zeros((1,3)) for p in range(3): X[0,p]=2.*r*(i*lpv[0,p]+j*lpv[1,p]+k*lpv[2,p]) dd=0 for p in range(3): dd += X[0,p] ** 2 if dd<R**2 and X[0,2]>membrane_lo and X[0,2]<membrane_hi: if X[0,0]>pxlo and X[0,0]<pxhi and X[0,1]>pylo and X[0,1]<pyhi and X[0,2]>pzlo and X[0,2]<pzhi: if checkClash(X, coords[:natoms,:], radius=5): if atm ==0: membrane = X else: membrane = np.append(membrane, X, axis=0) atm = atm + 1 coords = np.append(coords, X, axis=0) self._membrane = membrane LOGGER.report('Membrane was built in %2.fs.', label='_membrane') LOGGER.timeit('_exanm') total_natoms = int(coords.shape[0]) self._hessian = np.zeros((natoms*3, natoms*3), float) total_hessian = np.zeros((total_natoms*3, total_natoms*3), float) cutoff, g, gamma = checkENMParameters(cutoff, gamma) cutoff2 = cutoff * cutoff for i in range(total_natoms): res_i3 = i*3 res_i33 = res_i3+3 i_p1 = i+1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all ** 2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma(dist2, i, j) res_j3 = j*3 res_j33 = res_j3+3 super_element = np.outer(i2j, i2j) * (- g / dist2) total_hessian[res_i3:res_i33, res_j3:res_j33] = super_element total_hessian[res_j3:res_j33, res_i3:res_i33] = super_element total_hessian[res_i3:res_i33, res_i3:res_i33] = total_hessian[res_i3:res_i33, res_i3:res_i33] - super_element total_hessian[res_j3:res_j33, res_j3:res_j33] = total_hessian[res_j3:res_j33, res_j3:res_j33] - super_element ss = total_hessian[:natoms*3, :natoms*3] so = total_hessian[:natoms*3, natoms*3+1:] os = total_hessian[natoms*3+1:,:natoms*3] oo = total_hessian[natoms*3+1:, natoms*3+1:] self._hessian = ss - np.dot(so, np.dot(linalg.inv(oo), os)) LOGGER.report('Hessian was built in %.2fs.', label='_exanm') self._dof = self._hessian.shape[0]
def writeVMDstiffness(stiffness, pdb, indices, k_range, filename='vmd_out', \ select='protein and name CA', loadToVMD=False): """ Returns three files starting with the provided filename and having their own extensions: (1) A PDB file that can be used in the TCL script. (2) TCL file containing vmd commands for loading PDB file with accurate vmd representation. Pair of residues with selected *k_range* of effective spring constant are shown in VMD respresentation with solid line between them. If more than one residue is selected in *indices*, different pair for each residue will be colored in the different colors. (3) TXT file containing pair of residues with effective spring constant in selected range *k_range*. .. note:: #. This function skips modes with zero eigenvalues. #. If a :class:`.Vector` instance is given, it will be normalized before it is written. It's length before normalization will be written as the scaling factor of the vector. :arg stiffness: mechanical stiffness profile calculated with :func:`.calcMechStiff` :type stiffness: :class:`~numpy.ndarray` :arg pdb: a coordinate set or an object with ``getCoords`` method :type pdb: :class:`~numpy.ndarray`, :class:`.Atomic` :arg indices: an amino acid number or a pair of amino acid numbers :type indices: list :arg k_range: effective force constant value or range of values :type k_range: int, float, list :arg select: a selection or selection string default is 'protein and name CA' :type select: :class:`.Select`, str :arg loadToVMD: whether to load VMD and run the tcl file default is False :type loadToVMD: bool """ if not isinstance(filename, str): raise TypeError('filename should be a string') try: _, coords_sel = sliceAtoms(pdb, select) resnum_list = coords_sel.getResnums() coords = (coords_sel._getCoords() if hasattr(coords_sel, '_getCoords') else coords_sel.getCoords()) except AttributeError: try: checkCoords(coords_sel) except TypeError: raise TypeError('pdb must be a Numpy array or an object ' 'with `getCoords` method') if len(indices) == 0: raise ValueError('indices cannot be an empty array') if len(indices) == 1: indices0 = indices[0] - resnum_list[0] indices1 = indices[0] - resnum_list[0] elif len(indices) == 2: indices0 = indices[0] - resnum_list[0] indices1 = indices[1] - resnum_list[0] out = openFile(addext(filename, '.tcl'), 'w') out_txt = openFile(addext(filename, '.txt'), 'w') writePDB(filename + '.pdb', pdb) LOGGER.info('Creating VMD file.') out.write('display rendermode GLSL \n') out.write('display projection orthographic\n') out.write('color Display Background white\n') out.write('display shadows on\n') out.write('display depthcue off\n') out.write('axes location off\n') out.write('stage location off\n') out.write('light 0 on\n') out.write('light 1 on\n') out.write('light 2 off\n') out.write('light 3 on\n') out.write('mol addrep 0\n') out.write('display resetview\n') out.write('mol new {./' + str(filename) + '.pdb} type {pdb} first 0 last -1 step 1 waitfor 1\n') out.write('mol modselect 0 0 protein\n') out.write('mol modstyle 0 0 NewCartoon 0.300000 10.000000 4.100000 0\n') out.write('mol modcolor 0 0 Structure\n') out.write('mol color Structure\n') out.write('mol representation NewCartoon 0.300000 10.000000 4.100000 0\n') out.write('mol selection protein\n') out.write('mol material Opaque\n') colors = ['blue', 'red', 'gray', 'orange','yellow', 'tan','silver', 'green', \ 'white', 'pink', 'cyan', 'purple', 'lime', 'mauve', 'ochre', 'iceblue', 'black', \ 'yellow2','yellow3','green2','green3','cyan2','cyan3','blue2','blue3','violet', \ 'violet2','magenta','magenta2','red2','red3','orange2','orange3']*50 color_nr = 1 # starting from red color in VMD ResCounter = [] for r in range(indices0, indices1 + 1): baza_col = [] # Value of Kij is here for each residue nr_baza_col = [] # Resid of aa are here out.write("draw color " + str(colors[color_nr]) + "\n") for nr_i, i in enumerate(stiffness[r]): if k_range[0] < float(i) < k_range[1]: baza_col.append(i) nr_baza_col.append(nr_i + resnum_list[0]) resid_r = str( coords_sel.getResnames()[r]) + str(r + resnum_list[0]) resid_r2 = str( coords_sel.getResnames()[nr_i]) + str(nr_i + resnum_list[0]) if len( baza_col ) == 0: # if base is empty then it will not change the color color_nr = 0 else: out.write("draw line "+'{'+str(coords[r])[1:-1]+'} {'+\ str(coords[nr_i])[1:-1]+'} width 3 style solid \n') out_txt.write(resid_r + '\t' + resid_r2 + '\t' + str(i) + '\n') ResCounter.append(len(baza_col)) else: pass if len(baza_col) != 0: out.write('mol addrep 0\n') out.write('mol modselect '+str(color_nr+1)+' 0 protein and name CA and resid '+ \ str(r+resnum_list[0])+' '+str(nr_baza_col)[1:-1].replace(',','')+'\n') out.write('mol modcolor ' + str(color_nr + 1) + ' 0 ColorID ' + str(color_nr) + '\n') out.write('mol modstyle ' + str(color_nr + 1) + ' 0 VDW 0.600000 12.000000\n') out.write('mol color ColorID ' + str(color_nr) + '\n') out.write('mol representation VDW 1.000000 12.000000 \n') out.write('mol selection protein and name CA and resid '+ \ str(r+resnum_list[0])+' '+str(nr_baza_col)[1:-1].replace(',','')+'\n') out.write('mol material Opaque \n') color_nr = color_nr + 1 out.write('mol addrep 0\n') out.close() out_txt.close() if loadToVMD: from prody import pathVMD LOGGER.info('File will be loaded to VMD program.') os.system(pathVMD() + " -e " + str(filename) + ".tcl") if len(ResCounter) > 0: return out elif len(ResCounter) == 0: LOGGER.info('There is no residue pair in this Kij range.') return 'None'
def write(self, coords, unitcell=None, **kwargs): """Write *coords* to a file open in 'a' or 'w' mode. *coords* may be a NUmpy array or a ProDy object that stores or points to coordinate data. Note that all coordinate sets of ProDy object will be written. Number of atoms will be determined from the file or based on the size of the first coordinate set written. If *unitcell* is provided for the first coordinate set, it will be expected for the following coordinate sets as well. If *coords* is an :class:`~.Atomic` or :class:`~.Ensemble` all coordinate sets will be written. Following keywords are used when writing the first coordinate set: :arg timestep: timestep used for integration, default is 1 :arg firsttimestep: number of the first timestep, default is 0 :arg framefreq: number of timesteps between frames, default is 1""" if self._closed: raise ValueError('I/O operation on closed file') if self._mode == 'r': raise IOError('File not open for writing') try: coords = coords._getCoordsets() except AttributeError: try: coords = coords._getCoords() except AttributeError: checkCoords(coords, csets=True, dtype=None) else: if unitcell is None: try: coords = coords.getUnitcell() except AttributeError: pass if coords.dtype != float32: coords = coords.astype(float32) n_atoms = coords.shape[-2] if self._n_atoms == 0: self._n_atoms = n_atoms elif self._n_atoms != n_atoms: raise ValueError('coords does not have correct number of atoms') if coords.ndim == 2: coords = [coords] dcd = self._file pack_i_4N = pack('i', self._n_atoms * 4) if self._n_csets == 0: if unitcell is None: self._unitcell = False else: self._unitcell = True timestep = float(kwargs.get('timestep', 1.0)) first_ts = int(kwargs.get('firsttimestep', 0)) framefreq = int(kwargs.get('framefreq', 1)) n_fixed = 0 pack_i_0 = pack(b'i', 0) pack_ix4_0x4 = pack(b'i' * 4, 0, 0, 0, 0) pack_i_1 = pack(b'i', 1) pack_i_2 = pack(b'i', 2) pack_i_4 = pack(b'i', 4) pack_i_84 = pack(b'i', 84) pack_i_164 = pack(b'i', 164) dcd.write(pack_i_84) dcd.write(b'CORD') dcd.write(pack_i_0) # 0 Number of frames in file, none written yet dcd.write(pack(b'i', first_ts)) # 1 Starting timestep dcd.write(pack(b'i', framefreq)) # 2 Timesteps between frames dcd.write(pack_i_0) # 3 Number of timesteps in simulation dcd.write(pack_i_0) # 4 NAMD writes NSTEP or ISTART - NSAVC here? dcd.write(pack_ix4_0x4) # 5, 6, 7, 8 dcd.write(pack('f', timestep)) # 9 timestep dcd.write(pack('i', int(self._unitcell))) # 10 with unitcell dcd.write(pack_ix4_0x4) # 11, 12, 13, 14 dcd.write(pack_ix4_0x4) # 15, 16, 17, 18 dcd.write(pack('i', 24)) # 19 Pretend to be CHARMM version 24 dcd.write(pack_i_84) dcd.write(pack_i_164) dcd.write(pack_i_2) dcd.write(b'Created by ProDy'.ljust(80)) temp = now().strftime('%d %B, %Y at %H:%M') try: temp = bytes(temp, encoding='utf-8') except TypeError: pass dcd.write((b'REMARKS Created ' + temp).ljust(80)) dcd.write(pack_i_164) dcd.write(pack_i_4) dcd.write(pack(b'i', n_atoms)) dcd.write(pack_i_4) self._first_byte = dcd.tell() if self._unitcell: if unitcell is None: raise TypeError('unitcell data is expected') else: uc = unitcell uc[3:] = np.sin((PISQUARE / 90) * (90 - uc[3:])) uc = uc[[0, 3, 1, 4, 5, 2]] pack_i_48 = pack('i', 48) dcd.seek(0, 2) for xyz in coords: if self._unitcell: dcd.write(pack_i_48) uc.tofile(dcd) dcd.write(pack_i_48) xyz = xyz.T dcd.write(pack_i_4N) xyz[0].tofile(dcd) dcd.write(pack_i_4N) dcd.write(pack_i_4N) xyz[1].tofile(dcd) dcd.write(pack_i_4N) dcd.write(pack_i_4N) xyz[2].tofile(dcd) dcd.write(pack_i_4N) self._n_csets += 1 dcd.seek(8, 0) dcd.write(pack('i', self._n_csets)) dcd.seek(0, 2) self._nfi = self._n_csets
def buildHessian(self, coords, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. **kwargs** are passed to :method:`.buildMembrane`. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float """ atoms = coords try: 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') self._n_atoms = natoms = int(coords.shape[0]) if self._membrane is None: coords = self.buildMembrane(atoms, **kwargs) else: coords = self._combined.getCoords() LOGGER.timeit('_exanm') total_natoms = int(coords.shape[0]) self._hessian = np.zeros((natoms * 3, natoms * 3), float) total_hessian = np.zeros((total_natoms * 3, total_natoms * 3), float) cutoff, g, gamma = checkENMParameters(cutoff, gamma) cutoff2 = cutoff * cutoff for i in range(total_natoms): res_i3 = i * 3 res_i33 = res_i3 + 3 i_p1 = i + 1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all**2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma(dist2, i, j) res_j3 = j * 3 res_j33 = res_j3 + 3 super_element = np.outer(i2j, i2j) * (-g / dist2) total_hessian[res_i3:res_i33, res_j3:res_j33] = super_element total_hessian[res_j3:res_j33, res_i3:res_i33] = super_element total_hessian[res_i3:res_i33, res_i3:res_i33] = total_hessian[ res_i3:res_i33, res_i3:res_i33] - super_element total_hessian[res_j3:res_j33, res_j3:res_j33] = total_hessian[ res_j3:res_j33, res_j3:res_j33] - super_element ss = total_hessian[:natoms * 3, :natoms * 3] so = total_hessian[:natoms * 3, natoms * 3:] os = total_hessian[natoms * 3:, :natoms * 3] oo = total_hessian[natoms * 3:, natoms * 3:] self._hessian = ss - np.dot(so, np.dot(inv(oo), os)) LOGGER.report('Hessian was built in %.2fs.', label='_exanm') self._dof = self._hessian.shape[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') 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
def addCoordset(self, coords, weights=None, label=None, **kwargs): """Add coordinate set(s) to the ensemble. *coords* must be a Numpy array with suitable shape and dimensionality, or an object with :meth:`getCoordsets`. *weights* is an optional argument. If provided, its length must match number of atoms. Weights of missing (not resolved) atoms must be ``0`` and weights of those that are resolved can be anything greater than ``0``. If not provided, weights of all atoms for this coordinate set will be set equal to ``1``. *label*, which may be a PDB identifier or a list of identifiers, is used to label conformations.""" degeneracy = kwargs.pop('degeneracy', False) atoms = coords n_atoms = self._n_atoms n_select = self.numSelected() n_confs = self.numCoordsets() try: if degeneracy: if self._coords is not None: if isinstance(coords, Ensemble): coords = coords._getCoords(selected=False) elif hasattr(coords, '_getCoords'): coords = coords._getCoords() else: if isinstance(coords, Ensemble): coords = coords.getCoords(selected=False) elif hasattr(coords, 'getCoords'): coords = coords.getCoords() else: if self._coords is not None: if isinstance(coords, Ensemble): coords = coords._getCoordsets(selected=False) elif hasattr(coords, '_getCoordsets'): coords = coords._getCoordsets() else: if isinstance(coords, Ensemble): coords = coords.getCoordsets(selected=False) elif hasattr(coords, 'getCoordsets'): coords = coords.getCoordsets() except AttributeError: label = label or 'Unknown' else: if coords is None: raise ValueError('coordinates are not set') elif label is None and isinstance(atoms, Atomic): if not isinstance(atoms, AtomGroup): ag = atoms.getAtomGroup() else: ag = atoms label = ag.getTitle() if coords.shape[0] < ag.numCoordsets(): label += '_m' + str(atoms.getACSIndex()) else: label = label or 'Unknown' # check coordinates try: checkCoords(coords, csets=True, natoms=n_atoms) except: try: checkCoords(coords, csets=True, natoms=n_select) except TypeError: raise TypeError('coords must be a numpy array or an object ' 'with `getCoords` method') if coords.ndim == 2: n_nodes, _ = coords.shape coords = coords.reshape((1, n_nodes, 3)) n_csets = 1 else: n_csets, n_nodes, _ = coords.shape if degeneracy: coords = coords[:1] n_repeats = 1 if degeneracy else n_csets if not n_atoms: self._n_atoms = n_nodes if n_nodes == n_select and self.isSelected(): full_coords = np.repeat(self._coords[np.newaxis, :, :], n_csets, axis=0) full_coords[:, self._indices, :] = coords coords = full_coords # check weights if weights is None: weights = np.ones((n_csets, n_atoms, 1), dtype=float) else: weights = checkWeights(weights, n_atoms, n_csets) if degeneracy: weights = weights[:1] # check sequences seqs = None sequence = kwargs.pop('sequence', None) if hasattr(atoms, 'getSequence'): if sequence is not None: LOGGER.warn('sequence is supplied though coords has getSequence') sequence = atoms.getSequence() seqs = [sequence for _ in range(n_repeats)] else: if sequence is None: try: sequence = self.getAtoms().getSequence() except AttributeError: if self._msa: sequence = ''.join('X' for _ in range(n_atoms)) # sequence and seqs remains to be None if MSA has not been created if isinstance(sequence, Sequence): seqs = [str(sequence)] elif isinstance(sequence, MSA): seqs = [str(seq) for seq in sequence] elif np.isscalar(sequence): seqs = [sequence for _ in range(n_repeats)] if seqs: if len(seqs) != n_repeats: raise ValueError('the number of sequences should be either one or ' 'that of coordsets') # assign new values # update labels if n_csets > 1 and not degeneracy: if isinstance(label, str): labels = ['{0}_m{1}'.format(label, i+1) for i in range(n_csets)] else: if len(label) != n_csets: raise ValueError('length of label and number of ' 'coordinate sets must be the same') labels = label else: labels = [label] if np.isscalar(label) else label self._labels.extend(labels) # update sequences if seqs: msa = MSA(seqs, title=self.getTitle(), labels=labels) if self._msa is None: if n_confs > 0: def_seqs = np.chararray((n_confs, n_atoms)) def_seqs[:] = 'X' old_labels = [self._labels[i] for i in range(n_confs)] self._msa = MSA(def_seqs, title=self.getTitle(), labels=old_labels) self._msa.extend(msa) else: self._msa = msa else: self._msa.extend(msa) # update coordinates if self._confs is None and self._weights is None: self._confs = coords self._weights = weights self._n_csets = n_repeats elif self._confs is not None and self._weights is not None: self._confs = np.concatenate((self._confs, coords), axis=0) self._weights = np.concatenate((self._weights, weights), axis=0) self._n_csets += n_repeats else: raise RuntimeError('_confs and _weights must be set or None at ' 'the same time')
def testCoordset(self): self.assertTrue(checkCoords(COORDSET, csets=True))
def buildHessian(self, coords, blocks, cutoff=15.0, gamma=1.0, **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg blocks: a list or array of block identifiers :type blocks: list, :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg scale: scaling factor for force constant along Z-direction, default is 1.0 :type scale: float :arg membrane_low: minimum z-coordinate at which membrane scaling is applied default is 1.0 :type membrane_low: float :arg membrane_high: maximum z-coordinate at which membrane scaling is applied. If membrane_high < membrane_low, scaling will be applied to the entire structure default is -1.0 :type membrane_high: float """ try: 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") LOGGER.timeit("_rtb") self._n_atoms = natoms = int(coords.shape[0]) if natoms != len(blocks): raise ValueError("len(blocks) must match number of atoms") from collections import defaultdict i = Increment() d = defaultdict(i) blocks = np.array([d[b] for b in blocks], np.int64) try: from collections import Counter except ImportError: counter = defaultdict(int) for b in blocks: counter[b] += 1 else: counter = Counter(blocks) nblocks = len(counter) maxsize = 1 nones = 0 while counter: _, size = counter.popitem() if size == 1: nones += 1 if size > maxsize: maxsize = size LOGGER.info("System has {0} blocks largest with {1} of {2} units.".format(nblocks, maxsize, natoms)) nb6 = nblocks * 6 - nones * 3 coords = coords.T.copy() self._hessian = hessian = np.zeros((nb6, nb6), float) self._project = project = np.zeros((natoms * 3, nb6), float) from .rtbtools import buildhessian buildhessian( coords, blocks, hessian, project, natoms, nblocks, maxsize, float(cutoff), float(gamma), scale=float(kwargs.get("scale", 1.0)), memlo=float(kwargs.get("membrane_low", 1.0)), memhi=float(kwargs.get("membrane_high", 1.0)), ) self._dof = self._hessian.shape[0] LOGGER.report("Hessian was built in %.2fs.", label="_rtb")
def buildHessian(self, coords, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg membrane_hi: the maximum z coordinate of the pdb default is 13.0 :type membrane_hi: float :arg membrane_lo: the minimum z coordinate of the pdb default is -13.0 :type membrane_lo: float :arg R: radius of all membrane in x-y direction default is 80. :type R: float :arg r: radius of individual barrel-type membrane protein default is 2.5. :type :arg lat: lattice type which could be FCC(face-centered-cubic)(default), SC(simple cubic), SH(simple hexagonal) :type lat: str """ try: 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') self._n_atoms = natoms = int(coords.shape[0]) center = mean(coords, axis=0) coords = coords - center pxlo = min(np.append(coords[:,0],10000)) pxhi = max(np.append(coords[:,0],-10000)) pylo = min(np.append(coords[:,1],10000)) pyhi = max(np.append(coords[:,1],-10000)) pzlo = min(np.append(coords[:,2],10000)) pzhi = max(np.append(coords[:,2],-10000)) membrane_hi = float(kwargs.get('membrane_hi', 13.0)) membrane_lo = float(kwargs.get('membrane_lo', -13.0)) R = float(kwargs.get('R', 80)) r = float(kwargs.get('r', 5)) lat = str(kwargs.get('lat', 'FCC')) lpv = assign_lpvs(lat) imax = R/r jmax = R/r kmax = membrane_hi/r kmin = membrane_lo/r self._membrane = membrane = zeros((1,3)) LOGGER.timeit('_membrane') membrane = zeros((1,3)) membrane1 = zeros((1,3)) atm = 0 a = 0 b = 0 scale = 3 lim = range(-int(scale/2), int(scale/2)+1) for i in range(-int(imax),int(imax+1)): for j in range(-int(jmax),int(jmax+1)): for k in range(int(kmin),int(kmax+1)): X = zeros((1,3)) X[0,0]=-R+(2*i+1)*r X[0,1]=-R+(2*j+1)*r X[0,2]=-membrane_lo+(2*k+1)*r dd=0 for p in range(3): dd += X[0,p] ** 2 if dd<R**2 and X[0,2]>membrane_lo and X[0,2]<membrane_hi: if X[0,2]-6<membrane_lo or k==int(kmin): if X[0,0]>pxlo and X[0,0]<pxhi and X[0,1]>pylo and X[0,1]<pyhi and X[0,2]>pzlo and X[0,2]<pzhi: if checkClash(X, coords[:natoms,:], radius=5): if atm ==0: membrane = X else: membrane = np.append(membrane, X, axis=0) atm = atm + 1 coords = np.append(coords, X, axis=0) else: if atm==0: membrane = X else: membrane = np.append(membrane, X, axis=0) atm = atm + 1 coords = np.append(coords, X, axis=0) elif X[0,2]+6>membrane_hi or k==int(kmax): if X[0,0]>pxlo and X[0,0]<pxhi and X[0,1]>pylo and X[0,1]<pyhi and X[0,2]>pzlo and X[0,2]<pzhi: if checkClash(X, coords[:natoms,:], radius=5): if atm ==0: membrane = X else: membrane = np.append(membrane, X, axis=0) atm = atm + 1 coords = np.append(coords, X, axis=0) else: if atm==0: membrane = X else: membrane = np.append(membrane, X, axis=0) atm = atm + 1 coords = np.append(coords, X, axis=0) else: T1 = zeros((scale,3)) for l in range(scale): T1[l,0]=X[0,0] T1[l,1]=X[0,1] T1[l,2]=X[0,2]-(1.*(lim[l])/(scale-1))*r if X[0,0]>pxlo and X[0,0]<pxhi and X[0,1]>pylo and X[0,1]<pyhi and X[0,2]>pzlo and X[0,2]<pzhi: if checkClash(X, coords[:natoms,:], radius=5): if atm ==0: membrane1 = X else: membrane1 = np.append(membrane1, X, axis=0) atm = atm + 1 coords = np.append(coords, X, axis=0) else: if atm==0: membrane1 = X else: membrane1 = np.append(membrane1, X, axis=0) atm = atm + 1 coords = np.append(coords, X, axis=0) for l in range(scale): if T1[l,0]>pxlo and T1[l,0]<pxhi and T1[l,1]>pylo and T1[l,1]<pyhi and T1[l,2]>pzlo and T1[l,2]<pzhi: if checkClash(T1[l,:], coords[:natoms,:], radius=5): membrane1 = np.append(membrane1, T1[l,:].reshape(1,3), axis=0) atm = atm + 1 coords = np.append(coords, T1[l,:].reshape(1,3), axis=0) else: membrane1 = np.append(membrane1, T1[l,:].reshape(1,3), axis=0) atm = atm + 1 coords = np.append(coords, T1[l,:].reshape(1,3), axis=0) # length = membrane.shape[0] # f = open(filename, 'w') # for i in range(length): # f.write('ATOM%7d Q1 NE1 Q%4d% 12.3f% 8.3f% 8.3f\n' % (i,i,membrane[i,0],membrane[i,1],membrane[i,2])) # f.close() # length = membrane1.shape[0] # f = open(filename2, 'w') # for i in range(length): # f.write('ATOM%7d Q1 NE1 Q%4d% 12.3f% 8.3f% 8.3f\n' % (i,i,membrane1[i,0],membrane1[i,1],membrane1[i,2])) # f.close() self._membrane = membrane LOGGER.report('Membrane was built in %2.fs.', label='_membrane') LOGGER.timeit('_exanm') total_natoms = int(coords.shape[0]) self._hessian = np.zeros((natoms*3, natoms*3), float) total_hessian = np.zeros((total_natoms*3, total_natoms*3), float) cutoff, g, gamma = checkENMParameters(cutoff, gamma) cutoff2 = cutoff * cutoff for i in range(total_natoms): res_i3 = i*3 res_i33 = res_i3+3 i_p1 = i+1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all ** 2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma(dist2, i, j) res_j3 = j*3 res_j33 = res_j3+3 super_element = np.outer(i2j, i2j) * (- g / dist2) total_hessian[res_i3:res_i33, res_j3:res_j33] = super_element total_hessian[res_j3:res_j33, res_i3:res_i33] = super_element total_hessian[res_i3:res_i33, res_i3:res_i33] = total_hessian[res_i3:res_i33, res_i3:res_i33] - super_element total_hessian[res_j3:res_j33, res_j3:res_j33] = total_hessian[res_j3:res_j33, res_j3:res_j33] - super_element ss = total_hessian[:natoms*3, :natoms*3] so = total_hessian[:natoms*3, natoms*3+1:] os = total_hessian[natoms*3+1:,:natoms*3] oo = total_hessian[natoms*3+1:, natoms*3+1:] self._hessian = ss - np.dot(so, np.dot(linalg.inv(oo), os)) LOGGER.report('Hessian was built in %.2fs.', label='_exanm') self._dof = self._hessian.shape[0]
def buildHessian(self, coords, B=1., cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg b: bond-bending constant, default is 1.0 :type b: float :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :type scale: float """ try: 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') LOGGER.timeit('_bbenm') self._n_atoms = natoms = int(coords.shape[0]) self._hessian = hessian = np.zeros((3*natoms, 3*natoms), float) self._dof = 3*natoms - 6 cutoffd = cutoff gammad = gamma #anm hessian calculation cutoff, g, gamma = checkENMParameters(cutoff, gamma) cutoff2 = cutoff * cutoff for i in range(natoms): res_i3 = i*3 res_i33 = res_i3+3 i_p1 = i+1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all ** 2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma(dist2, i, j) res_j3 = j*3 res_j33 = res_j3+3 super_element = np.outer(i2j, i2j) * (- g / dist2) hessian[res_i3:res_i33, res_j3:res_j33] = super_element hessian[res_j3:res_j33, res_i3:res_i33] = super_element hessian[res_i3:res_i33, res_i3:res_i33] = \ hessian[res_i3:res_i33, res_i3:res_i33] - super_element hessian[res_j3:res_j33, res_j3:res_j33] = \ hessian[res_j3:res_j33, res_j3:res_j33] - super_element # hessian updates from .bbenmtools import buildhessian buildhessian(coords, hessian, natoms, float(cutoffd), float(gammad),) LOGGER.report('Hessian was built in %.2fs.', label='_bbenm')
def buildKirchhoff(self, coords, cutoff=10., gamma=1., **kwargs): """Build Kirchhoff matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` or :class:`.Atomic` :arg cutoff: cutoff distance (Å) for pairwise interactions default is 10.0 Å, , minimum is 4.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg sparse: elect to use sparse matrices, default is **False**. If Scipy is not found, :class:`ImportError` is raised. :type sparse: bool :arg kdtree: elect to use KDTree for building Kirchhoff matrix faster, default is **True** :type kdtree: bool Instances of :class:`Gamma` classes and custom functions are accepted as *gamma* argument. When Scipy is available, user can select to use sparse matrices for efficient usage of memory at the cost of computation speed.""" try: 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') cutoff, g, gamma = checkENMParameters(cutoff, gamma) self._reset() self._cutoff = cutoff self._gamma = g n_atoms = coords.shape[0] start = time.time() if kwargs.get('sparse', False): try: from scipy import sparse as scipy_sparse except ImportError: raise ImportError('failed to import scipy.sparse, which is ' 'required for sparse matrix calculations') kirchhoff = scipy_sparse.lil_matrix((n_atoms, n_atoms)) else: kirchhoff = np.zeros((n_atoms, n_atoms), 'd') if kwargs.get('kdtree', True): kdtree = KDTree(coords) kdtree.search(cutoff) dist2 = kdtree.getDistances()**2 r = 0 for i, j in kdtree.getIndices(): g = gamma(dist2[r], i, j) kirchhoff[i, j] = -g kirchhoff[j, i] = -g kirchhoff[i, i] = kirchhoff[i, i] + g kirchhoff[j, j] = kirchhoff[j, j] + g r += 1 else: LOGGER.info('Using slower method for building the Kirchhoff.') cutoff2 = cutoff * cutoff mul = np.multiply for i in range(n_atoms): xyz_i = coords[i, :] i_p1 = i + 1 i2j = coords[i_p1:, :] - xyz_i mul(i2j, i2j, i2j) for j, dist2 in enumerate(i2j.sum(1)): if dist2 > cutoff2: continue j += i_p1 g = gamma(dist2, i, j) kirchhoff[i, j] = -g kirchhoff[j, i] = -g kirchhoff[i, i] = kirchhoff[i, i] + g kirchhoff[j, j] = kirchhoff[j, j] + g LOGGER.debug('Kirchhoff was built in {0:.2f}s.'.format(time.time() - start)) self._kirchhoff = kirchhoff self._n_atoms = n_atoms self._dof = n_atoms
def buildHessian(self, coords, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg membrane_hi: the maximum z coordinate of the pdb default is 13.0 :type membrane_hi: float :arg membrane_lo: the minimum z coordinate of the pdb default is -13.0 :type membrane_lo: float :arg R: radius of all membrane in x-y direction default is 80. :type R: float :arg r: radius of individual barrel-type membrane protein default is 2.5. :type :arg lat: lattice type which could be FCC(face-centered-cubic)(default), SC(simple cubic), SH(simple hexagonal) :type lat: str """ try: 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') self._n_atoms = natoms = int(coords.shape[0]) if self._membrane is None: membrane_hi = float(kwargs.get('membrane_hi', 13.0)) membrane_lo = float(kwargs.get('membrane_lo', -13.0)) R = float(kwargs.get('R', 80)) r = float(kwargs.get('r', 5)) lat = str(kwargs.get('lat', 'FCC')) self.buildMembrane(coords, membrane_hi=membrane_hi, membrane_lo=membrane_lo, R=R, r=r, lat=lat) LOGGER.timeit('_exanm') coords = np.concatenate((coords, self._membrane.getCoords()), axis=0) self._combined_coords = coords total_natoms = int(coords.shape[0]) self._hessian = np.zeros((natoms * 3, natoms * 3), float) total_hessian = np.zeros((total_natoms * 3, total_natoms * 3), float) cutoff, g, gamma = checkENMParameters(cutoff, gamma) cutoff2 = cutoff * cutoff for i in range(total_natoms): res_i3 = i * 3 res_i33 = res_i3 + 3 i_p1 = i + 1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all**2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma(dist2, i, j) res_j3 = j * 3 res_j33 = res_j3 + 3 super_element = np.outer(i2j, i2j) * (-g / dist2) total_hessian[res_i3:res_i33, res_j3:res_j33] = super_element total_hessian[res_j3:res_j33, res_i3:res_i33] = super_element total_hessian[res_i3:res_i33, res_i3:res_i33] = total_hessian[ res_i3:res_i33, res_i3:res_i33] - super_element total_hessian[res_j3:res_j33, res_j3:res_j33] = total_hessian[ res_j3:res_j33, res_j3:res_j33] - super_element ss = total_hessian[:natoms * 3, :natoms * 3] so = total_hessian[:natoms * 3, natoms * 3 + 1:] os = total_hessian[natoms * 3 + 1:, :natoms * 3] oo = total_hessian[natoms * 3 + 1:, natoms * 3 + 1:] self._hessian = ss - np.dot(so, np.dot(linalg.inv(oo), os)) LOGGER.report('Hessian was built in %.2fs.', label='_exanm') self._dof = self._hessian.shape[0]
def buildHessian(self, coords, blocks, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg blocks: a list or array of block identifiers :type blocks: list, :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :arg scale: scaling factor for force constant along Z-direction, default is 1.0 :type scale: float """ try: 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') LOGGER.timeit('_rtb') self._n_atoms = natoms = int(coords.shape[0]) if natoms != len(blocks): raise ValueError('len(blocks) must match number of atoms') from collections import defaultdict i = Increment() d = defaultdict(i) blocks = np.array([d[b] for b in blocks], np.int64) try: from collections import Counter except ImportError: counter = defaultdict(int) for b in blocks: counter[b] += 1 else: counter = Counter(blocks) nblocks = len(counter) maxsize = 1 nones = 0 while counter: _, size = counter.popitem() if size == 1: nones += 1 if size > maxsize: maxsize = size LOGGER.info( 'System has {0} blocks largest with {1} of {2} units.'.format( nblocks, maxsize, natoms)) nb6 = nblocks * 6 - nones * 3 coords = coords.T.copy() self._hessian = hessian = np.zeros((nb6, nb6), float) self._project = project = np.zeros((natoms * 3, nb6), float) from .rtbtools import buildhessian buildhessian( coords, blocks, hessian, project, natoms, nblocks, maxsize, float(cutoff), float(gamma), scale=float(kwargs.get('scale', 1.0)), memlo=float(kwargs.get('membrane_low', 1.0)), memhi=float(kwargs.get('membrane_high', -1.0)), ) LOGGER.report('Hessian was built in %.2fs.', label='_rtb')
def write(self, coords, unitcell=None, **kwargs): """Write *coords* to a file open in 'a' or 'w' mode. *coords* may be a NUmpy array or a ProDy object that stores or points to coordinate data. Note that all coordinate sets of ProDy object will be written. Number of atoms will be determined from the file or based on the size of the first coordinate set written. If *unitcell* is provided for the first coordinate set, it will be expected for the following coordinate sets as well. If *coords* is an :class:`~.Atomic` or :class:`~.Ensemble` all coordinate sets will be written. Following keywords are used when writing the first coordinate set: :arg timestep: timestep used for integration, default is 1 :arg firsttimestep: number of the first timestep, default is 0 :arg framefreq: number of timesteps between frames, default is 1""" if self._closed: raise ValueError('I/O operation on closed file') if self._mode == 'r': raise IOError('File not open for writing') try: coords = coords._getCoordsets() except AttributeError: try: coords = coords._getCoords() except AttributeError: checkCoords(coords, csets=True, dtype=None) else: if unitcell is None: try: coords = coords.getUnitcell() except AttributeError: pass if coords.dtype != float32: coords = coords.astype(float32) n_atoms = coords.shape[-2] if self._n_atoms == 0: self._n_atoms = n_atoms elif self._n_atoms != n_atoms: raise ValueError('coords does not have correct number of atoms') if coords.ndim == 2: coords = [coords] dcd = self._file pack_i_4N = pack('i', self._n_atoms * 4) if self._n_csets == 0: if unitcell is None: self._unitcell = False else: self._unitcell = True timestep = float(kwargs.get('timestep', 1.0)) first_ts = int(kwargs.get('firsttimestep', 0)) framefreq = int(kwargs.get('framefreq', 1)) n_fixed = 0 pack_i_0 = pack('i', 0) pack_ix4_0x4 = pack('i'*4, 0, 0, 0, 0) pack_i_1 = pack('i', 1) pack_i_2 = pack('i', 2) pack_i_4 = pack('i', 4) pack_i_84 = pack('i', 84) pack_i_164 = pack('i', 164) dcd.write(pack_i_84) dcd.write('CORD') dcd.write(pack_i_0) # 0 Number of frames in file, none written yet dcd.write(pack('i', first_ts)) # 1 Starting timestep dcd.write(pack('i', framefreq)) # 2 Timesteps between frames dcd.write(pack_i_0) # 3 Number of timesteps in simulation dcd.write(pack_i_0) # 4 NAMD writes NSTEP or ISTART - NSAVC here? dcd.write(pack_ix4_0x4) # 5, 6, 7, 8 dcd.write(pack('f', timestep)) # 9 timestep dcd.write(pack('i', int(self._unitcell))) # 10 with unitcell dcd.write(pack_ix4_0x4) # 11, 12, 13, 14 dcd.write(pack_ix4_0x4) # 15, 16, 17, 18 dcd.write(pack('i', 24)) # 19 Pretend to be CHARMM version 24 dcd.write(pack_i_84) dcd.write(pack_i_164) dcd.write(pack_i_2) dcd.write('{0:80s}'.format('Created by ProDy')) dcd.write('{0:80s}'.format('REMARKS Created ' + now().strftime('%d %B, %Y at %H:%M'))) dcd.write(pack_i_164) dcd.write(pack_i_4) dcd.write(pack('i', n_atoms)) dcd.write(pack_i_4) self._first_byte = dcd.tell() if self._unitcell: if unitcell is None: raise TypeError('unitcell data is expected') else: uc = unitcell uc[3:] = np.sin((PISQUARE/90) * (90-uc[3:])) uc = uc[[0,3,1,4,5,2]] pack_i_48 = pack('i', 48) dcd.seek(0, 2) for xyz in coords: if self._unitcell: dcd.write(pack_i_48) uc.tofile(dcd) dcd.write(pack_i_48) xyz = xyz.T dcd.write(pack_i_4N) xyz[0].tofile(dcd) dcd.write(pack_i_4N) dcd.write(pack_i_4N) xyz[1].tofile(dcd) dcd.write(pack_i_4N) dcd.write(pack_i_4N) xyz[2].tofile(dcd) dcd.write(pack_i_4N) self._n_csets += 1 dcd.seek(8, 0) dcd.write(pack('i', self._n_csets)) dcd.seek(0, 2) self._nfi = self._n_csets
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
def buildHessian(self, coords, cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å, minimum is 4.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float, :class:`Gamma` :arg sparse: elect to use sparse matrices, default is **False**. If Scipy is not found, :class:`ImportError` is raised. :type sparse: bool :arg kdtree: elect to use KDTree for building Hessian matrix, default is **False** since KDTree method is slower :type kdtree: bool Instances of :class:`Gamma` classes and custom functions are accepted as *gamma* argument. When Scipy is available, user can select to use sparse matrices for efficient usage of memory at the cost of computation speed.""" try: 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') cutoff, g, gamma = checkENMParameters(cutoff, gamma) self._reset() self._cutoff = cutoff self._gamma = g n_atoms = coords.shape[0] dof = n_atoms * 3 LOGGER.timeit('_anm_hessian') if kwargs.get('sparse', False): try: from scipy import sparse as scipy_sparse except ImportError: raise ImportError('failed to import scipy.sparse, which is ' 'required for sparse matrix calculations') kirchhoff = scipy_sparse.lil_matrix((n_atoms, n_atoms)) hessian = scipy_sparse.lil_matrix((dof, dof)) else: kirchhoff = np.zeros((n_atoms, n_atoms), 'd') hessian = np.zeros((dof, dof), float) if kwargs.get('kdtree', False): LOGGER.info('Using KDTree for building the Hessian.') kdtree = KDTree(coords) kdtree.search(cutoff) for i, j in kdtree.getIndices(): i2j = coords[j] - coords[i] dist2 = np.dot(i2j, i2j) g = gamma(dist2, i, j) super_element = np.outer(i2j, i2j) * (- g / dist2) res_i3 = i*3 res_i33 = res_i3+3 res_j3 = j*3 res_j33 = res_j3+3 hessian[res_i3:res_i33, res_j3:res_j33] = super_element hessian[res_j3:res_j33, res_i3:res_i33] = super_element hessian[res_i3:res_i33, res_i3:res_i33] = \ hessian[res_i3:res_i33, res_i3:res_i33] - super_element hessian[res_j3:res_j33, res_j3:res_j33] = \ hessian[res_j3:res_j33, res_j3:res_j33] - super_element kirchhoff[i, j] = -g kirchhoff[j, i] = -g kirchhoff[i, i] = kirchhoff[i, i] - g kirchhoff[j, j] = kirchhoff[j, j] - g else: cutoff2 = cutoff * cutoff for i in range(n_atoms): res_i3 = i*3 res_i33 = res_i3+3 i_p1 = i+1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all ** 2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma(dist2, i, j) res_j3 = j*3 res_j33 = res_j3+3 super_element = np.outer(i2j, i2j) * (- g / dist2) hessian[res_i3:res_i33, res_j3:res_j33] = super_element hessian[res_j3:res_j33, res_i3:res_i33] = super_element hessian[res_i3:res_i33, res_i3:res_i33] = \ hessian[res_i3:res_i33, res_i3:res_i33] - super_element hessian[res_j3:res_j33, res_j3:res_j33] = \ hessian[res_j3:res_j33, res_j3:res_j33] - super_element kirchhoff[i, j] = -g kirchhoff[j, i] = -g kirchhoff[i, i] = kirchhoff[i, i] - g kirchhoff[j, j] = kirchhoff[j, j] - g LOGGER.report('Hessian was built in %.2fs.', label='_anm_hessian') self._kirchhoff = kirchhoff self._hessian = hessian self._n_atoms = n_atoms self._dof = dof
def buildSM(self, coords, n_modes=None, kbt=1., saveMap=False, saveMatrix=False, filename='sm'): """Calculate stiffness matrix calculated using :class:`.ANM` instance. Method described in [EB08]_. .. [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 coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray`. :arg n_modes: number of non-zero eigenvalues/vectors to calculate. If ``None`` is given, all modes will be calculated (3x number of atoms). :type n_modes: int or ``None``, default is 20. By default results are not saved to a *filename* file. To save data with stiffness matrix map and mean value of effective force constant for each residue use: ``saveMap=True`` and ``saveMatrix=True``. Author: Mustafa Tekpinar & Karolina Mikulska-Ruminska & Cihan Kaya """ try: 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') n_atoms = natoms = self._n_atoms n_modes = 3 * n_atoms self.calcModes(n_modes=None, zeros=True) LOGGER.timeit('_sm') eigvecs = (np.transpose(self._array)).flatten() eigvals = np.transpose(self._eigvals) natoms = n_atoms sm = np.zeros((n_atoms, n_atoms), np.double) from .smtools import calcSM LOGGER.info('Calculating stiffness matrix.') calcSM(coords, sm, eigvecs, eigvals, natoms, n_modes, float(kbt)) LOGGER.report('Stiffness matrix calculated in %.2lfs.', label='_sm') self._stiffness = sm meanSiff = np.mean(sm, axis=0) LOGGER.info('The range of effective force constant is: {0} to {1}.' .format(np.min(sm[np.nonzero(sm)]), np.amax(sm))) if (saveMatrix == True): np.savetxt(filename+'.txt', sm, fmt='%.6f') out_mean = open(filename+'_mean.txt','w') # mean value of Kij for each residue for nr_i, i in enumerate(meanSiff): out_mean.write("{} {}\n".format(nr_i, i)) out_mean.close() if (saveMap == True): import math import matplotlib import matplotlib.pylab as plt matplotlib.rcParams['font.size'] = '16' fig = plt.figure(num=None, figsize=(10,8), dpi=100, facecolor='w') plt.imshow(sm, origin='lower') plt.axis([0, n_atoms, n_atoms, 0]) plt.xlabel('residue', fontsize = '18') plt.ylabel('residue', fontsize = '18') cbar = plt.colorbar() #cbar.set_label('N/m', rotation=90, fontsize = '18') plt.clim(math.floor(np.min(sm[np.nonzero(sm)])), round(np.amax(sm),1)) plt.savefig(filename+'.png', dpi=100)
def buildHessian(self, coords, B=1., cutoff=15., gamma=1., **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg b: bond-bending constant, default is 1.0 :type b: float :arg cutoff: cutoff distance (Å) for pairwise interactions, default is 15.0 Å :type cutoff: float :arg gamma: spring constant, default is 1.0 :type gamma: float :type scale: float """ try: 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') LOGGER.timeit('_bbenm') self._n_atoms = natoms = int(coords.shape[0]) self._hessian = hessian = np.zeros((3 * natoms, 3 * natoms), float) self._dof = 3 * natoms - 6 # anm hessian calculation cutoff, gamma, gamma_func = checkENMParameters(cutoff, gamma) cutoff2 = cutoff * cutoff for i in range(natoms): res_i3 = i * 3 res_i33 = res_i3 + 3 i_p1 = i + 1 i2j_all = coords[i_p1:, :] - coords[i] for j, dist2 in enumerate((i2j_all**2).sum(1)): if dist2 > cutoff2: continue i2j = i2j_all[j] j += i_p1 g = gamma_func(dist2, i, j) res_j3 = j * 3 res_j33 = res_j3 + 3 super_element = np.outer(i2j, i2j) * (-g / dist2) hessian[res_i3:res_i33, res_j3:res_j33] = super_element hessian[res_j3:res_j33, res_i3:res_i33] = super_element hessian[res_i3:res_i33, res_i3:res_i33] = \ hessian[res_i3:res_i33, res_i3:res_i33] - super_element hessian[res_j3:res_j33, res_j3:res_j33] = \ hessian[res_j3:res_j33, res_j3:res_j33] - super_element # hessian updates from .bbenmtools import buildhessian buildhessian( coords, hessian, natoms, float(cutoff), float(gamma), ) LOGGER.report('Hessian was built in %.2fs.', label='_bbenm')
def buildMembrane(self, coords, **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or an object with ``getCoords`` method :type coords: :class:`numpy.ndarray` :arg membrane_hi: the maximum z coordinate of the pdb default is 13.0 :type membrane_hi: float :arg membrane_lo: the minimum z coordinate of the pdb default is -13.0 :type membrane_lo: float :arg R: radius of all membrane in x-y direction default is 80. :type R: float :arg r: radius of individual barrel-type membrane protein default is 2.5. :type :arg lat: lattice type which could be FCC(face-centered-cubic)(default), SC(simple cubic), SH(simple hexagonal) :type lat: str """ if type(coords) is AtomGroup: buildAg = True else: buildAg = False try: 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') self._n_atoms = natoms = int(coords.shape[0]) pxlo = min(np.append(coords[:,0],10000)) pxhi = max(np.append(coords[:,0],-10000)) pylo = min(np.append(coords[:,1],10000)) pyhi = max(np.append(coords[:,1],-10000)) pzlo = min(np.append(coords[:,2],10000)) pzhi = max(np.append(coords[:,2],-10000)) membrane_hi = float(kwargs.get('membrane_hi', 13.0)) membrane_lo = float(kwargs.get('membrane_lo', -13.0)) R = float(kwargs.get('R', 80)) r = float(kwargs.get('r', 5)) lat = str(kwargs.get('lat', 'FCC')) lpv = assign_lpvs(lat) imax = (R + lpv[0,2] * (membrane_hi - membrane_lo)/2.)/r jmax = (R + lpv[1,2] * (membrane_hi - membrane_lo)/2.)/r kmax = (R + lpv[2,2] * (membrane_hi - membrane_lo)/2.)/r #print pxlo, pxhi, pylo, pyhi, pzlo, pzhi #print lpv[0,2],lpv[1,2],lpv[2,2] #print R,r,imax,jmax,kmax membrane = zeros((1,3)) LOGGER.timeit('_membrane') membrane = zeros((1,3)) atm = 0 for i in range(-int(imax),int(imax+1)): for j in range(-int(jmax),int(jmax+1)): for k in range(-int(kmax),int(kmax+1)): X = zeros((1,3)) for p in range(3): X[0,p]=2.*r*(i*lpv[0,p]+j*lpv[1,p]+k*lpv[2,p]) dd=0 for p in range(3): dd += X[0,p] ** 2 if dd<R**2 and X[0,2]>membrane_lo and X[0,2]<membrane_hi: if X[0,0]>pxlo-R/2 and X[0,0]<pxhi+R/2 and X[0,1]>pylo-R/2 and X[0,1]<pyhi+R/2 and X[0,2]>pzlo and X[0,2]<pzhi: if checkClash(X, coords[:natoms,:], radius=5): if atm == 0: membrane = X else: membrane = np.append(membrane, X, axis=0) atm = atm + 1 #print atm self._membrane = AtomGroup(title="Membrane") self._membrane.setCoords(membrane) self._membrane.setResnums(range(atm)) self._membrane.setResnames(["NE1" for i in range(atm)]) self._membrane.setChids(["Q" for i in range(atm)]) self._membrane.setElements(["Q1" for i in range(atm)]) self._membrane.setNames(["Q1" for i in range(atm)]) LOGGER.report('Membrane was built in %2.fs.', label='_membrane')
def writeVMDstiffness(stiffness, pdb, indices, k_range, filename='vmd_out', \ select='protein and name CA', loadToVMD=False): """ Returns three files starting with the provided filename and having their own extensions: (1) A PDB file that can be used in the TCL script. (2) TCL file containing vmd commands for loading PDB file with accurate vmd representation. Pair of residues with selected *k_range* of effective spring constant are shown in VMD respresentation with solid line between them. If more than one residue is selected in *indices*, different pair for each residue will be colored in the different colors. (3) TXT file containing pair of residues with effective spring constant in selected range *k_range*. .. note:: #. This function skips modes with zero eigenvalues. #. If a :class:`.Vector` instance is given, it will be normalized before it is written. It's length before normalization will be written as the scaling factor of the vector. :arg stiffness: mechanical stiffness profile calculated with :func:`.calcMechStiff` :type stiffness: :class:`~numpy.ndarray` :arg pdb: a coordinate set or an object with ``getCoords`` method :type pdb: :class:`~numpy.ndarray`, :class:`.Atomic` :arg indices: an amino acid number or a pair of amino acid numbers :type indices: list :arg k_range: effective force constant value or range of values :type k_range: int, float, list :arg select: a selection or selection string default is 'protein and name CA' :type select: :class:`.Select`, str :arg loadToVMD: whether to load VMD and run the tcl file default is False :type loadToVMD: bool """ if not isinstance(filename, str): raise TypeError('filename should be a string') try: _, coords_sel = sliceAtoms(pdb, select) resnum_list = coords_sel.getResnums() coords = (coords_sel._getCoords() if hasattr(coords_sel, '_getCoords') else coords_sel.getCoords()) except AttributeError: try: checkCoords(coords_sel) except TypeError: raise TypeError('pdb must be a Numpy array or an object ' 'with `getCoords` method') if len(indices) == 0: raise ValueError('indices cannot be an empty array') if len(indices) == 1: indices0 = indices[0] - resnum_list[0] indices1 = indices[0] - resnum_list[0] elif len(indices) == 2: indices0 = indices[0] - resnum_list[0] indices1 = indices[1] - resnum_list[0] out = openFile(addext(filename, '.tcl'), 'w') out_txt = openFile(addext(filename,'.txt'), 'w') writePDB(filename + '.pdb', pdb) LOGGER.info('Creating VMD file.') out.write('display rendermode GLSL \n') out.write('display projection orthographic\n') out.write('color Display Background white\n') out.write('display shadows on\n') out.write('display depthcue off\n') out.write('axes location off\n') out.write('stage location off\n') out.write('light 0 on\n') out.write('light 1 on\n') out.write('light 2 off\n') out.write('light 3 on\n') out.write('mol addrep 0\n') out.write('display resetview\n') out.write('mol new {./'+str(filename)+'.pdb} type {pdb} first 0 last -1 step 1 waitfor 1\n') out.write('mol modselect 0 0 protein\n') out.write('mol modstyle 0 0 NewCartoon 0.300000 10.000000 4.100000 0\n') out.write('mol modcolor 0 0 Structure\n') out.write('mol color Structure\n') out.write('mol representation NewCartoon 0.300000 10.000000 4.100000 0\n') out.write('mol selection protein\n') out.write('mol material Opaque\n') colors = ['blue', 'red', 'gray', 'orange','yellow', 'tan','silver', 'green', \ 'white', 'pink', 'cyan', 'purple', 'lime', 'mauve', 'ochre', 'iceblue', 'black', \ 'yellow2','yellow3','green2','green3','cyan2','cyan3','blue2','blue3','violet', \ 'violet2','magenta','magenta2','red2','red3','orange2','orange3']*50 color_nr = 1 # starting from red color in VMD ResCounter = [] for r in range(indices0, indices1 + 1): baza_col = [] # Value of Kij is here for each residue nr_baza_col = [] # Resid of aa are here out.write("draw color "+str(colors[color_nr])+"\n") for nr_i, i in enumerate(stiffness[r]): if k_range[0] < float(i) < k_range[1]: baza_col.append(i) nr_baza_col.append(nr_i+resnum_list[0]) resid_r = str(coords_sel.getResnames()[r])+str(r+resnum_list[0]) resid_r2 = str(coords_sel.getResnames()[nr_i])+str(nr_i+resnum_list[0]) if len(baza_col) == 0: # if base is empty then it will not change the color color_nr = 0 else: out.write("draw line "+'{'+str(coords[r])[1:-1]+'} {'+\ str(coords[nr_i])[1:-1]+'} width 3 style solid \n') out_txt.write(resid_r + '\t' + resid_r2 + '\t' + str(i) + '\n') ResCounter.append(len(baza_col)) else: pass if len(baza_col) != 0: out.write('mol addrep 0\n') out.write('mol modselect '+str(color_nr+1)+' 0 protein and name CA and resid '+ \ str(r+resnum_list[0])+' '+str(nr_baza_col)[1:-1].replace(',','')+'\n') out.write('mol modcolor '+str(color_nr+1)+' 0 ColorID '+str(color_nr)+'\n') out.write('mol modstyle '+str(color_nr+1)+' 0 VDW 0.600000 12.000000\n') out.write('mol color ColorID '+str(color_nr)+'\n') out.write('mol representation VDW 1.000000 12.000000 \n') out.write('mol selection protein and name CA and resid '+ \ str(r+resnum_list[0])+' '+str(nr_baza_col)[1:-1].replace(',','')+'\n') out.write('mol material Opaque \n') color_nr = color_nr + 1 out.write('mol addrep 0\n') out.close() out_txt.close() if loadToVMD: from prody import pathVMD LOGGER.info('File will be loaded to VMD program.') os.system(pathVMD()+" -e "+str(filename)+".tcl") if len(ResCounter) > 0: return out elif len(ResCounter) == 0: LOGGER.info('There is no residue pair in this Kij range.') return 'None'