def _getKDTree(self, index=None): """Return KDTree for coordinate set at given index.""" if self._n_csets: if index is None: index = self._acsi kdtree = self._kdtrees[index] if kdtree is None: kdtree = getKDTree(self._coords[index]) self._kdtrees[index] = kdtree return kdtree else: return None
def buildHessian(self, coords, cutoff=15.0, gamma=1.0, **kwargs): """Build Hessian matrix for given coordinate set. :arg coords: a coordinate set or anything with getCoordinates method :type coords: :class:`~numpy.ndarray` or :class:`~prody.atomic.Atomic` :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: slect to use sparse matrices. Default is ``False``. If Scipy is not found, :class:`ImportError` is raised. :type sparse: 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.""" slow = kwargs.get("slow", False) try: from KDTree import KDTree except ImportError: KDTree = False if not slow and not KDTree: LOGGER.info("Using a slower method for building the Hessian " "matrix.") if not isinstance(coords, np.ndarray): try: coords = coords.getCoords() except AttributeError: raise TypeError("coords must be a Numpy array or must have " "getCoordinates attribute") coords = checkCoords(coords, "coords") cutoff, g, gamma = checkENMParameters(cutoff, gamma) self._reset() self._cutoff = cutoff self._gamma = g n_atoms = coords.shape[0] dof = n_atoms * 3 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)) hessian = scipy_sparse.lil_matrix((dof, dof)) else: kirchhoff = np.zeros((n_atoms, n_atoms), "d") hessian = np.zeros((dof, dof), float) if not slow and KDTree: kdtree = getKDTree(coords) kdtree.all_search(cutoff) for i, j in kdtree.all_get_indices(): 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 xyz_i = coords[i, :] for j in range(i + 1, n_atoms): i2j = coords[j, :] - xyz_i dist2 = np.dot(i2j, i2j) if dist2 > cutoff2: continue 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.info("Hessian was built in {0:.2f}s.".format(time.time() - start)) self._kirchhoff = kirchhoff self._hessian = hessian self._n_atoms = n_atoms self._dof = dof
def buildKirchhoff(self, coords, cutoff=10., gamma=1., **kwargs): """Build Kirchhoff matrix for given coordinate set. :arg coords: a coordinate set or anything with getCoordinates method :type coords: :class:`~numpy.ndarray` or :class:`~prody.atomic.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 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.""" slow = kwargs.get('slow', False) try: from KDTree import KDTree except ImportError: KDTree = False if not slow and not KDTree: LOGGER.info('Using a slower method for building the Kirchhoff ' 'matrix.') if not isinstance(coords, np.ndarray): try: coords = coords.getCoords() except AttributeError: raise TypeError('coords must be a Numpy array or must have ' 'getCoordinates attribute') coords = checkCoords(coords, 'coords') 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 not slow and KDTree: kdtree = getKDTree(coords) kdtree.all_search(cutoff) radii = kdtree.all_get_radii() r = 0 for i, j in kdtree.all_get_indices(): g = gamma(radii[r]**2, 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: cutoff2 = cutoff * cutoff for i in range(n_atoms): xyz_i = coords[i, :] for j in range(i+1, n_atoms): i2j = coords[j, :] - xyz_i dist2 = np.dot(i2j, i2j) if dist2 > cutoff2: continue 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