Takes a PDB string and constructs a Protein object. WARNING: All non-standard residue types will be converted into UNK. All non-standard atoms will be ignored. Args: pdb_str: The contents of the pdb file chain_id: If chain_id is specified (e.g. A), then only that chain is par
(pdb_str: str, chain_id: Optional[str] = None)
| 70 | |
| 71 | |
| 72 | def from_pdb_string(pdb_str: str, chain_id: Optional[str] = None) -> Protein: |
| 73 | """Takes a PDB string and constructs a Protein object. |
| 74 | |
| 75 | WARNING: All non-standard residue types will be converted into UNK. All |
| 76 | non-standard atoms will be ignored. |
| 77 | |
| 78 | Args: |
| 79 | pdb_str: The contents of the pdb file |
| 80 | chain_id: If chain_id is specified (e.g. A), then only that chain |
| 81 | is parsed. Otherwise all chains are parsed. |
| 82 | |
| 83 | Returns: |
| 84 | A new `Protein` parsed from the pdb contents. |
| 85 | """ |
| 86 | pdb_fh = io.StringIO(pdb_str) |
| 87 | parser = PDBParser(QUIET=True) |
| 88 | structure = parser.get_structure('none', pdb_fh) |
| 89 | models = list(structure.get_models()) |
| 90 | if len(models) != 1: |
| 91 | raise ValueError( |
| 92 | f'Only single model PDBs are supported. Found {len(models)} models.') |
| 93 | model = models[0] |
| 94 | |
| 95 | atom_positions = [] |
| 96 | aatype = [] |
| 97 | atom_mask = [] |
| 98 | residue_index = [] |
| 99 | chain_ids = [] |
| 100 | b_factors = [] |
| 101 | |
| 102 | for chain in model: |
| 103 | if chain_id is not None and chain.id != chain_id: |
| 104 | continue |
| 105 | for res in chain: |
| 106 | if res.id[2] != ' ': |
| 107 | raise ValueError( |
| 108 | f'PDB contains an insertion code at chain {chain.id} and residue ' |
| 109 | f'index {res.id[1]}. These are not supported.') |
| 110 | res_shortname = residue_constants.restype_3to1.get(res.resname, 'X') |
| 111 | restype_idx = residue_constants.restype_order.get( |
| 112 | res_shortname, residue_constants.restype_num) |
| 113 | pos = np.zeros((residue_constants.atom_type_num, 3)) |
| 114 | mask = np.zeros((residue_constants.atom_type_num,)) |
| 115 | res_b_factors = np.zeros((residue_constants.atom_type_num,)) |
| 116 | for atom in res: |
| 117 | if atom.name not in residue_constants.atom_types: |
| 118 | continue |
| 119 | pos[residue_constants.atom_order[atom.name]] = atom.coord |
| 120 | mask[residue_constants.atom_order[atom.name]] = 1. |
| 121 | res_b_factors[residue_constants.atom_order[atom.name]] = atom.bfactor |
| 122 | if np.sum(mask) < 0.5: |
| 123 | # If no known atom positions are reported for the residue then skip it. |
| 124 | continue |
| 125 | aatype.append(restype_idx) |
| 126 | atom_positions.append(pos) |
| 127 | atom_mask.append(mask) |
| 128 | residue_index.append(res.id[1]) |
| 129 | chain_ids.append(chain.id) |