Source code for mordred.surface_area._sasa

from __future__ import division

from collections import defaultdict

import numpy as np

from ._mesh import SphereMesh
from .._util import atoms_to_numpy
from .._atomic_property import GetAtomicNumber, vdw_radii


[docs]class SurfaceArea(object): r"""calculate solvent accessible surface area. :type radiuses: np.ndarray(dtype=float, shape=(N,)) :param radiuses: atomic radius + solvent radius vector :type xyzs: np.ndarray(dtype=float, shape=(N, 3)) :param xyzs: atomic position matrix :type level: int :param level: mesh level. subdivide icosahedron n-1 times. .. math:: N_{\rm points} = 5 \times 4^{level} - 8 """ def __init__(self, radiuses, xyzs, level=4): self.rads = radiuses self.rads2 = radiuses ** 2 self.xyzs = xyzs self._gen_neighbor_list() self.sphere = SphereMesh(level).vertices.T def _gen_neighbor_list(self): r = self.rads[:, np.newaxis] + self.rads d = np.sqrt( np.sum( (self.xyzs[:, np.newaxis] - self.xyzs) ** 2, axis=2, ), ) ns = defaultdict(list) for i, j in np.transpose(np.nonzero(d <= r)): if i == j: continue ns[i].append((j, d[i, j])) for _, l in ns.items(): l.sort(key=lambda i: i[1]) self.neighbors = ns
[docs] def atomic_sa(self, i): r"""Calculate atomic surface area. :type i: int :param i: atom index :rtype: float """ sa = 4.0 * np.pi * self.rads2[i] neighbors = self.neighbors.get(i) if neighbors is None: return sa XYZi = self.xyzs[i, np.newaxis].T sphere = self.sphere * self.rads[i] + XYZi N = sphere.shape[1] for j, _ in neighbors: XYZj = self.xyzs[j, np.newaxis].T d2 = (sphere - XYZj) ** 2 mask = (d2[0] + d2[1] + d2[2]) > self.rads2[j] sphere = np.compress(mask, sphere, axis=1) return sa * sphere.shape[1] / N
[docs] def surface_area(self): r"""Calculate all atomic surface area. :rtype: [float] """ return [self.atomic_sa(i) for i in range(len(self.rads))]
[docs] @classmethod def from_mol(cls, mol, conformer=-1, solvent_radius=1.4, level=4): r"""Construct SurfaceArea from rdkit Mol type. :type mol: rdkit.Chem.Mol :param mol: input molecule :type conformer: int :param conformer: conformer id :type solvent_radius: float :param solvent_radius: solvent radius :type level: int :param level: mesh level :rtype: SurfaceArea """ rs = atoms_to_numpy(lambda a: vdw_radii[a.GetAtomicNum()] + solvent_radius, mol) conf = mol.GetConformer(conformer) ps = np.array([list(conf.GetAtomPosition(i)) for i in range(mol.GetNumAtoms())]) return cls(rs, ps, level)
[docs] @classmethod def from_pdb(cls, pdb, solvent_radius=1.4, level=3): try: from Bio.PDB import PDBParser except ImportError: raise ImportError("There isn't biopython package.") rs = [] coords = [] for atom in PDBParser().get_structure("", pdb).get_atoms(): rs.append(vdw_radii[GetAtomicNumber(atom.element)] + solvent_radius) coords.append(atom.coord) return cls(np.array(rs), np.array(coords), level)