Commit 028c208d authored by Bharath Ramsundar's avatar Bharath Ramsundar
Browse files

PDBBind expansion

parent 110dc734
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -227,6 +227,8 @@ class AtomicConvFeaturizer(ComplexFeaturizer):
    # TODO(rbharath): extend to more fragments
    if len(frag_num_atoms) != 2:
      raise ValueError("Currently only supports two fragments")
    self.frag1_num_atoms = frag_num_atoms[0]
    self.frag2_num_atoms = frag_num_atoms[0]
    self.complex_num_atoms = sum(frag_num_atoms)
    self.max_num_neighbors = max_num_neighbors
    self.neighbor_cutoff = neighbor_cutoff
+391 −4
Original line number Diff line number Diff line
@@ -147,6 +147,391 @@ def load_pdbbind_grid(split="random",

    return tasks, (train, valid, test), transformers

def download_pdbbind(data_dir=None,
                     subset="refined",
                     version="v2015",
                     interactions="protein-ligand"):
  """Downloads PDBBind data to a local directory.

  This utility function will download the raw PDBBind dataset into a
  local directory. If you don't specify `data_dir`, it will default to
  `deepchem.utils.get_data_dir()`. You can download either the 2015 or
  2019 versions of PDBBind data with this function by specifying the
  subset in question.

  Parameters
  ----------
  data_dir: Str, optional
    Specifies the directory storing the raw dataset.
  subset: str, optional
    This is one of "refined", or "other". These are subsets of
    the protein-ligand interactions (if `interactions !=
    "protein-ligand"` this field is ignored). If `version=="v2015"`,
    then this field is ignored since everything is stored in one
    big gzip together. If `version=="v2019"`, then "refined" and
    "other" are separate datasets which must be downloaded separately.
  version: str, optional
    Either "v2015" or "v2019". Only "v2015" is supported for now.
  interactions: str, optional
    Must be one of "protein-ligand", "protein-protein",
    "protein-nucleic-acid", "nucleic-acid-ligand". If
    `version=='v2015'`, only "protein-ligand" is supported.
  """
  if version == "v2015" and interactions != "protein-ligand":
    raise ValueError("Only protein-ligand interactions supported for v2015")
  if data_dir == None:
    data_dir = deepchem.utils.get_data_dir()

  if version == "v2015":
    data_folder = os.path.join(data_dir, "pdbbind", "v2015")
    dataset_file = os.path.join(data_dir, "pdbbind_v2015.tar.gz")
    if not os.path.exists(dataset_file):
      logger.warning("About to download PDBBind full dataset. Large file, 2GB")
      deepchem.utils.download_url(
          'http://deepchem.io.s3-website-us-west-1.amazonaws.com/datasets/' +
          "pdbbind_v2015.tar.gz",
          dest_dir=data_dir)
    if os.path.exists(data_folder):
      logger.info("PDBBind v2015 full dataset already exists.")
    else:
      logger.info("Untarring PDBBind v2015 full dataset...")
      deepchem.utils.untargz_file(
          dataset_file, dest_dir=os.path.join(data_dir, "pdbbind"))
  elif version == "v2019":
    data_folder = os.path.join(data_dir, "pdbbind", "v2019")
    # Download the index file since we'll always need it
    index_file = os.path.join(data_dir, "PDBbind_2019_plain_text_index.tar.gz")
    index_folder = os.path.join(data_folder, "plain-text-index")
    if not os.path.exists(index_file):
      logger.info("About to download PDBBind 2019 index file.")
      deepchem.utils.download_url(
        'https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/pdbbindv2019/PDBbind_2019_plain_text_index.tar.gz')

    if not os.path.exists(index_folder):
      logger.info("Untarring 2019 index dataset...")
      deepchem.utils.untargz_file(
          index_file, dest_dir=data_folder)

    if interactions == "protein-protein":
      pp_file = os.path.join(data_dir, "pdbbind_v2019_PP.tar.gz")
      if not os.path.exists(pp_file):
        logger.warning("About to download PDBBind 2019 protein-protein interactions. Large file of 688 MB")
        deepchem.utils.download_url(
          'https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/pdbbindv2019/pdbbind_v2019_PP.tar.gz')
      pp_folder = os.path.join(data_folder, "PP")
      if not os.path.exists(pp_folder):
        logger.info("Untarring 2019 protein-protein dataset...")
        deepchem.utils.untargz_file(
            pp_file, dest_dir=data_folder)
    elif interactions == "protein-nucleic-acid":
      pn_file = os.path.join(data_dir, "pdbbind_v2019_PN.tar.gz")
      if not os.path.exists(pn_file):
        logger.warning("About to download PDBBind 2019 protein-nucleic-acid interactions. Large file of 229 MB")
        deepchem.utils.download_url(
          'https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/pdbbindv2019/pdbbind_v2019_PN.tar.gz')
      pn_folder = os.path.join(data_folder, "PN")
      if not os.path.exists(pn_folder):
        logger.info("Untarring 2019 protein-nucleic-acid dataset...")
        deepchem.utils.untargz_file(
            pn_file, dest_dir=data_folder)
    elif interactions == "nucleic-acid-ligand":
      nl_file = os.path.join(data_dir, "pdbbind_v2019_NL.tar.gz")
      if not os.path.exists(nl_file):
        logger.warning("About to download PDBBind 2019 nucleic-acid-ligand interactions. File of 17 MB")
        deepchem.utils.download_url(
          'https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/pdbbindv2019/pdbbind_v2019_NL.tar.gz')
      nl_folder = os.path.join(data_folder, "NL")
      if not os.path.exists(nl_folder):
        logger.info("Untarring 2019 nucleic-acid-ligand dataset...")
        deepchem.utils.untargz_file(
            nl_file, dest_dir=data_folder)
    elif interactions == "protein-ligand" and subset=="refined":
      pl_refined_file = os.path.join(data_dir, "pdbbind_v2019_refined.tar.gz")
      if not os.path.exists(pl_refined_file):
        logger.warning("About to download PDBBind 2019 protein-ligand refined interactions. Large File of 622 MB")
        deepchem.utils.download_url(
          'https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/pdbbindv2019/pdbbind_v2019_refined.tar.gz')
      pl_refined_folder = os.path.join(data_folder, "refined-set")
      if not os.path.exists(pl_refined_folder):
        logger.info("Untarring 2019 protein-ligand refined dataset...")
        deepchem.utils.untargz_file(
            pl_refined_file, dest_dir=data_folder)
    elif interactions == "protein-ligand" and subset=="other":
      pl_other_file = os.path.join(data_dir, "pdbbind_v2019_other_PL.tar.gz")
      if not os.path.exists(pl_other_file):
        logger.warning("About to download PDBBind 2019 protein-ligand other interactions. Large File of 1.6 GB")
        deepchem.utils.download_url(
          'https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/pdbbindv2019/pdbbind_v2019_other_PL.tar.gz')
      pl_other_folder = os.path.join(data_folder, "v2019-other-PL")
      if not os.path.exists(pl_other_folder):
        logger.info("Untarring 2019 protein-ligand other dataset...")
        deepchem.utils.untargz_file(
            pl_other_file, dest_dir=data_folder)

def get_pdbbind_molecular_complex_files(data_dir=None,
                                        subset="refined",
                                        version="v2015",
                                        interactions="protein-ligand",
                                        load_binding_pocket=False):
  """Get a list of the structure files for each dataset.

  A macromolecular complex is typically specified by one or more
  molecular structure files (PDB/sdf/mol2). This function returns a
  list of the structure files associated with various PDBBind
  datasets. This is needed for downstream processing by
  ComplexFeaturizers which work from these structure files to produce
  vectorial or tensorial representations of the data.

  Parameters
  ----------
  data_dir: Str, optional
    Specifies the directory storing the raw dataset.
  subset: str, optional
    This is one of "core", "refined", "general". These are
    subsets of the protein-ligand interactions (if `interactions !=
    "protein-ligand"` this field is ignored). Note that v2019 doesn't
    have an included "core" set. 
  version: str, optional
    Either "v2015" or "v2019". Only "v2015" is supported for now.
  interactions: str, optional
    Must be one of "protein-ligand", "protein-protein",
    "protein-nucleic-acid", "nucleic-acid-ligand". If
    `version=='v2015'`, only "protein-ligand" is supported.
  load_binding_pocket: Bool, optional
    Load binding pocket or full protein. Only valid for v2015
    protein-ligand dataset.
                            
  Returns
  -------
  List. If a molecular complex has multiple files they are returned
  together as tuple.
  """
  if data_dir == None:
    data_dir = deepchem.utils.get_data_dir()

  if version == "v2015":
    data_folder = os.path.join(data_dir, "pdbbind", "v2015")
    if subset == "core":
      index_labels_file = os.path.join(data_folder, "INDEX_core_data.2013")
    elif subset == "refined":
      index_labels_file = os.path.join(data_folder, "INDEX_refined_data.2015")
    elif subset == "general":
      index_labels_file = os.path.join(data_folder, "INDEX_general_PL_data.2015")
    else:
      raise ValueError("Other subsets not supported")

    # Extract locations of data
    with open(index_labels_file, "r") as g:
      pdbs = [line[:4] for line in g.readlines() if line[0] != "#"]
    if load_binding_pocket:
      protein_files = [
          os.path.join(data_folder, pdb, "%s_pocket.pdb" % pdb) for pdb in pdbs
      ]
    else:
      protein_files = [
          os.path.join(data_folder, pdb, "%s_protein.pdb" % pdb) for pdb in pdbs
      ]
    ligand_files = [
        os.path.join(data_folder, pdb, "%s_ligand.sdf" % pdb) for pdb in pdbs
    ]
    return list(zip(protein_files, ligand_files))
  elif version == "v2019":
    data_folder = os.path.join(data_dir, "pdbbind", "v2019")
    if interactions == "protein-protein":
      index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_PP.2019")

      with open(index_labels_file, "r") as g:
        pdbs = [line[:4] for line in g.readlines() if line[0] != "#"]
      pp_folder = os.path.join(data_folder, "PP")
      protein_files = [
          os.path.join(pp_folder, "%s.ent.pdb" % pdb) for pdb in pdbs
      ]
      return protein_files
    elif interactions == "protein-nucleic-acid":
      index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_PN.2019")

      with open(index_labels_file, "r") as g:
        pdbs = [line[:4] for line in g.readlines() if line[0] != "#"]
      pn_folder = os.path.join(data_folder, "PN")
      protein_files = [
          os.path.join(pn_folder, "%s.ent.pdb" % pdb) for pdb in pdbs
      ]
      return protein_files
    elif interactions == "nucleic-acid-ligand":
      index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_NL.2019")

      with open(index_labels_file, "r") as g:
        pdbs = [line[:4] for line in g.readlines() if line[0] != "#"]
      nl_folder = os.path.join(data_folder, "NL")
      complex_files = [
          os.path.join(nl_folder, "%s.ent.pdb" % pdb) for pdb in pdbs
      ]
      return complex_files
    elif interactions == "protein-ligand":
      if subset == "refined":
        index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_refined_data.2019")

        with open(index_labels_file, "r") as g:
          pdbs = [line[:4] for line in g.readlines() if line[0] != "#"]
        refined_folder = os.path.join(data_folder, "refined-set")
        protein_files = [
            os.path.join(refined_folder, pdb, "%s_protein.pdb" % pdb) for pdb in pdbs
        ]
        ligand_files = [
            os.path.join(data_folder, pdb, "%s_ligand.sdf" % pdb) for pdb in pdbs
        ]
        return list(zip(protein_files, ligand_files))
      elif subset == "general":
        index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_PL_data.2019")

        with open(index_labels_file, "r") as g:
          pdbs = [line[:4] for line in g.readlines() if line[0] != "#"]
        general_folder = os.path.join(data_folder, "v2019-other-PL")
        protein_files = [
            os.path.join(general_folder, pdb, "%s_protein.pdb" % pdb) for pdb in pdbs
        ]
        ligand_files = [
            os.path.join(data_folder, pdb, "%s_ligand.sdf" % pdb) for pdb in pdbs
        ]
        return list(zip(protein_files, ligand_files))
      else:
        raise ValueError("Other subsets not supported")
  else:
    raise ValueError("Only v2015 and v2019 versions are supported.")

def get_pdbbind_molecular_complex_labels(data_dir=None,
                                         subset="refined",
                                         version="v2015",
                                         interactions="protein-ligand",
                                         load_binding_pocket=False):
  """Get a list of the labels for each dataset.

  This function returns a list of the labels associated with various
  PDBBind datasets. Labels will be returned in the same order as the
  raw files from `get_pdbbind_molecular_complex_files`.

  Protein-ligand datasets have units -log Kd/Ki, while the
  protein-protein, protein-nucleic-acid, nucleic-acid-ligand datasets
  have units as raw Kd/Ki/IC50 values. These later files are
  occasionally thresholded, with readings such as 'Ki<1fM' converted
  to '1fM'. If you'd like to do a more refined conversion, you'll need
  to refer to the source label file.

  Parameters
  ----------
  data_dir: Str, optional
    Specifies the directory storing the raw dataset.
  subset: str, optional
    This is one of "core", "refined", "general". These are
    subsets of the protein-ligand interactions (if `interactions !=
    "protein-ligand"` this field is ignored). Note that v2019 doesn't
    have an included "core" set. 
  version: str, optional
    Either "v2015" or "v2019". Only "v2015" is supported for now.
  interactions: str, optional
    Must be one of "protein-ligand", "protein-protein",
    "protein-nucleic-acid", "nucleic-acid-ligand". If
    `version=='v2015'`, only "protein-ligand" is supported.
  load_binding_pocket: Bool, optional
    Load binding pocket or full protein. Only valid for v2015
    protein-ligand dataset.
                            
  Returns
  -------
  List. If a molecular complex has multiple files they are returned
  together as tuple.
  """
  if data_dir == None:
    data_dir = deepchem.utils.get_data_dir()

  if version == "v2015":
    data_folder = os.path.join(data_dir, "pdbbind", "v2015")
    if subset == "core":
      index_labels_file = os.path.join(data_folder, "INDEX_core_data.2013")
    elif subset == "refined":
      index_labels_file = os.path.join(data_folder, "INDEX_refined_data.2015")
    elif subset == "general":
      index_labels_file = os.path.join(data_folder, "INDEX_general_PL_data.2015")
    else:
      raise ValueError("Other subsets not supported")
    # Extract labels
    with open(index_labels_file, "r") as g:
      labels = np.array([
          # Lines have format
          # PDB code, resolution, release year, -logKd/Ki, Kd/Ki, reference, ligand name
          # The base-10 logarithm, -log kd/pk
          float(line.split()[3]) for line in g.readlines() if line[0] != "#"
      ])
    return labels
  elif version == "v2019":
    data_folder = os.path.join(data_dir, "pdbbind", "v2019")
    # process interactions that have binding data
    if interactions in ["protein-protein", "protein-nucleic-acid", "nucleic-acid-ligand"]:
      if interactions == "protein-protein":
        index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_PP.2019")
      elif interactions == "protein-nucleic-acid":
        index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_PN.2019")
      elif interactions == "nucleic-acid-ligand":
        index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_NL.2019")

      # Lines have format
      # PDB code, resolution, release year, binding data, reference, ligand name
      # Extract labels
      with open(index_labels_file, "r") as g:
        raw_labels = [
            line.split()[3] for line in g.readlines() if line[0] != "#"
        ]
      clean_labels = []
      # Here are few types of raw labels we can see in the source
      # data: Kd=31.8uM, IC50=0.6nM, Kd=22.8pM, Kd~1nM, Kd>500uM,
      # Ki<0.002nM, Kd=1fM, Kd=3mM.

      # We have to do two steps of processing. The first is to remove
      # the separator. Possible values are ["=", "<", "~", ">"].
      # For the inequalities, we threshold so "<1fM" becomes "1fM".
      # This may cause some distortion in learning.
      separators = ["=", "<", "~", ">"]

      # The second step we have to do is separate the units
      unit_conversions = {"mM": 1e-3, "uM":1e-6, "nM":1e-9, "pM":1e-12, "fM":1e-15}
      number = None
      for raw in raw_labels:
        for separator in separators:
          if separator in raw:
            pieces = raw.split(separator)
            # This is something like "0.6nM"
            number = pieces[-1]
            break
        if number is None:
          raise ValueError("Don't know how to parse %s" % raw)
        # Shave off units
        mantissa = float(number[:-2] )
        units = unit_conversions[number[-2:]]
        clean_labels.append(mantissa * units)
      # Make sure we didn't miss any labels in processing
      assert len(clean_labels) == len(raw_labels)
      return clean_labels
    elif interactions == "protein-ligand":
      if subset == "refined":
        index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_refined_data.2019")
      elif subset == "general":
        index_labels_file = os.path.join(data_folder, "plain-text-index", "index", "INDEX_general_PL_data.2019")
      else:
        raise ValueError("Other subsets not supported")

      # Extract labels
      with open(index_labels_file, "r") as g:
        labels = np.array([
            # Lines have format
            # PDB code, resolution, release year, -logKd/Ki, Kd/Ki, reference, ligand name
            # The base-10 logarithm, -log kd/pk
            float(line.split()[3]) for line in g.readlines() if line[0] != "#"
        ])
      return labels
  else:
    raise ValueError("Only v2015 and v2019 versions are supported.")



def load_pdbbind(reload=True,
                 data_dir=None,
@@ -176,11 +561,13 @@ def load_pdbbind(reload=True,
  split_seed: Int, optional
    Specifies the random seed for splitter.
  save_dir: Str, optional
    Specifies the directory to store the featurized and splitted dataset when
    reload is False. If reload is True, it will load saved dataset inside save_dir.
    Specifies the directory to store the featurized and splitted
    dataset when reload is False. If reload is True, it will load
    saved dataset inside save_dir.
  save_timestamp: Bool, optional
    Save featurized and splitted dataset with timestamp or not. Set it as True
    when running similar or same jobs simultaneously on multiple compute nodes.
    Save featurized and splitted dataset with timestamp or not. Set it
    as True when running similar or same jobs simultaneously on
    multiple compute nodes.
  """

  pdbbind_tasks = ["-logKd/Ki"]
+22 −0
Original line number Diff line number Diff line
# This example featurizes a small subset of the PDBBind v2015 protein-ligand core data with the AtomicConvFeaturizer
import deepchem as dc
from deepchem.molnet.load_function.pdbbind_datasets import get_pdbbind_molecular_complex_files

complex_files = get_pdbbind_molecular_complex_files(subset="core", version="v2015", interactions="protein-ligand", load_binding_pocket=False)
core_subset = complex_files[:2]
ligand_files = [core[1] for core in core_subset]
protein_files = [core[0] for core in core_subset]

frag1_num_atoms = 70  # for ligand atoms
frag2_num_atoms = 24000  # for protein atoms
complex_num_atoms = 24070  # in total
max_num_neighbors = 4
# Cutoff in angstroms
neighbor_cutoff = 4
featurizer = dc.feat.AtomicConvFeaturizer(
    frag_num_atoms=[frag1_num_atoms,frag2_num_atoms],
    complex_num_atoms=complex_num_atoms,
    max_num_neighbors=max_num_neighbors,
    neighbor_cutoff=neighbor_cutoff)
features, failures = featurizer.featurize_complexes(
    ligand_files, protein_files, parallelize=False)
+24 −0
Original line number Diff line number Diff line
# This example demonstrates how to download the raw PDBBind data 
import deepchem as dc
import logging

logging.basicConfig(level=logging.INFO)


# Download 2015 protein-ligand dataset
dc.molnet.load_function.pdbbind_datasets.download_pdbbind(version="v2015", interactions="protein-ligand")

# Download 2019 protein-protein dataset
dc.molnet.load_function.pdbbind_datasets.download_pdbbind(version="v2019", interactions="protein-protein")

# Download 2019 protein-nucleic-acid dataset
dc.molnet.load_function.pdbbind_datasets.download_pdbbind(version="v2019", interactions="protein-nucleic-acid")

# Download 2019 nucleic-acid-ligand dataset
dc.molnet.load_function.pdbbind_datasets.download_pdbbind(version="v2019", interactions="nucleic-acid-ligand")

# Download 2019 protein-ligand refined dataset
dc.molnet.load_function.pdbbind_datasets.download_pdbbind(version="v2019", interactions="protein-ligand", subset="refined")

# Download 2019 protein-ligand other dataset
dc.molnet.load_function.pdbbind_datasets.download_pdbbind(version="v2019", interactions="protein-ligand", subset="other")
+27 −0
Original line number Diff line number Diff line
# This examples shows how to get the list of structure files for PDBBind datasets
import deepchem as dc
from deepchem.molnet.load_function.pdbbind_datasets import get_pdbbind_molecular_complex_files

pdbbind_v2015_core_files = get_pdbbind_molecular_complex_files(subset="core", version="v2015", interactions="protein-ligand", load_binding_pocket=False)
print("Number of files in PDBBind v2015 core set: %d" % len(pdbbind_v2015_core_files))

pdbbind_v2015_refined_files = get_pdbbind_molecular_complex_files(subset="refined", version="v2015", interactions="protein-ligand", load_binding_pocket=False)
print("Number of files in PDBBind v2015 refined set: %d" % len(pdbbind_v2015_refined_files))

pdbbind_v2015_general_files = get_pdbbind_molecular_complex_files(subset="general", version="v2015", interactions="protein-ligand", load_binding_pocket=False)
print("Number of files in PDBBind v2015 general set: %d" % len(pdbbind_v2015_general_files))

pdbbind_v2019_PP_files = get_pdbbind_molecular_complex_files(subset="general", version="v2019", interactions="protein-protein", load_binding_pocket=False)
print("Number of files in PDBBind v2019 PP set: %d" % len(pdbbind_v2019_PP_files))

pdbbind_v2019_PN_files = get_pdbbind_molecular_complex_files(subset="general", version="v2019", interactions="protein-nucleic-acid", load_binding_pocket=False)
print("Number of files in PDBBind v2019 PN set: %d" % len(pdbbind_v2019_PN_files))

pdbbind_v2019_NL_files = get_pdbbind_molecular_complex_files(subset="general", version="v2019", interactions="nucleic-acid-ligand", load_binding_pocket=False)
print("Number of files in PDBBind v2019 NL set: %d" % len(pdbbind_v2019_NL_files))

pdbbind_v2019_refined_files = get_pdbbind_molecular_complex_files(subset="refined", version="v2019", interactions="protein-ligand", load_binding_pocket=False)
print("Number of files in PDBBind v2019 refined set: %d" % len(pdbbind_v2019_refined_files))

pdbbind_v2019_general_files = get_pdbbind_molecular_complex_files(subset="general", version="v2019", interactions="protein-ligand", load_binding_pocket=False)
print("Number of files in PDBBind v2019 general set: %d" % len(pdbbind_v2019_general_files))
Loading