File size: 6,588 Bytes
8efb4bd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | from functools import lru_cache
from typing import Tuple, List
import Bio.PDB
import numpy as np
import scipy.spatial
from libs.utils_classes import INTERFACE_MIN_ATOM_DIST, SubunitPdbInfo
@lru_cache(5)
def get_pdb_model_readonly(pdb_path: str):
pdb_parser = Bio.PDB.PDBParser(QUIET=True)
pdb_struct = pdb_parser.get_structure("original_pdb", pdb_path)
assert len(list(pdb_struct)) == 1, f"Too many models! {pdb_path}"
return next(iter(pdb_struct))
def get_pdb_model_no_cache(pdb_path: str):
pdb_parser = Bio.PDB.PDBParser(QUIET=True)
pdb_struct = pdb_parser.get_structure("original_pdb", pdb_path)
assert len(list(pdb_struct)) == 1, f"Too many models! {pdb_path}"
return next(iter(pdb_struct))
def extract_chains(pdb_path: str, output_path: str, chains_to_save: List[str]):
pdb_parser = Bio.PDB.PDBParser(QUIET=True)
pdb_struct = pdb_parser.get_structure("original_pdb", pdb_path)
assert len(list(pdb_struct)) == 1, "can't extract if more than one model"
model = next(iter(pdb_struct))
chains = list(model.get_chains())
for chain_id in chains_to_save:
assert len([c for c in chains if c.id == chain_id]) == 1, f"Missing chain {chain_id} from {pdb_path}"
for chain in chains:
if chain.id not in chains_to_save:
model.detach_child(chain.id)
io = Bio.PDB.PDBIO()
io.set_structure(pdb_struct)
io.save(output_path)
def extract_pdb_info(pdb_path: str, pdb_info: SubunitPdbInfo, output_path: str):
pdb_parser = Bio.PDB.PDBParser(QUIET=True)
pdb_struct = pdb_parser.get_structure("original_pdb", pdb_path)
assert len(list(pdb_struct)) == 1, "can't extract if more than one model"
model = next(iter(pdb_struct))
chains = list(model.get_chains())
assert len([c for c in chains if c.id == pdb_info.chain_id]) == 1, f"Missing chain {pdb_info.chain_id}"
for chain in chains:
if chain.id != pdb_info.chain_id:
model.detach_child(chain.id)
res_to_remove = []
for res in model.get_residues():
if not (pdb_info.chain_residue_id <= res.id[1] < pdb_info.chain_residue_id + pdb_info.length):
res_to_remove.append(res)
for res in res_to_remove:
res.parent.detach_child(res.id)
io = Bio.PDB.PDBIO()
io.set_structure(pdb_struct)
io.save(output_path)
def copy_pdb_rename_chain(original_pdb_path: str, new_chain_name: str, output_path: str):
pdb_parser = Bio.PDB.PDBParser(QUIET=True)
pdb_struct = pdb_parser.get_structure("original_pdb", original_pdb_path)
model = next(iter(pdb_struct))
chains = list(model.get_chains())
assert len(chains) == 1
assert len(new_chain_name) == 1, f"Bad chain name provided {new_chain_name}"
chains[0].id = new_chain_name
io = Bio.PDB.PDBIO()
io.set_structure(pdb_struct)
io.save(output_path)
def copy_pdb_add_offset(original_pdb_path: str, offset: int, output_path: str):
pdb_parser = Bio.PDB.PDBParser(QUIET=True)
pdb_struct = pdb_parser.get_structure("original_pdb", original_pdb_path)
model = next(iter(pdb_struct))
chains = list(model.get_chains())
assert len(chains) == 1
# prevent "already used for a sibling of this entity" error
for res in chains[0].get_residues():
res.id = (res.id[0], res.id[1] + 10**4, res.id[2])
for res in chains[0].get_residues():
res.id = (res.id[0], res.id[1] - 10**4 + offset, res.id[2])
io = Bio.PDB.PDBIO()
io.set_structure(pdb_struct)
io.save(output_path)
def copy_pdb_set_start_offset(original_pdb_path: str, offset: int, output_path: str):
pdb_parser = Bio.PDB.PDBParser(QUIET=True)
pdb_struct = pdb_parser.get_structure("original_pdb", original_pdb_path)
model = next(iter(pdb_struct))
current_offset = min([res.id[1] for res in model.get_residues()])
copy_pdb_add_offset(original_pdb_path, offset - current_offset, output_path)
def is_chains_coords_close(chain1_ca: np.ndarray, chain2_ca: np.ndarray):
if len(chain1_ca) == 0 or len(chain2_ca) == 0:
return False
return np.min(scipy.spatial.distance.cdist(chain1_ca, chain2_ca)) < INTERFACE_MIN_ATOM_DIST
def are_subunits_close_in_pdb(pdb_path: str, subunit1: SubunitPdbInfo, subunit2: SubunitPdbInfo):
model = get_pdb_model_readonly(pdb_path)
chains = list(model.get_chains())
chain1 = [i for i in chains if i.get_id() == subunit1.chain_id][0]
chain2 = [i for i in chains if i.get_id() == subunit2.chain_id][0]
chain1_ca = np.array([res['CA'].coord for res in chain1.get_residues() if 'CA' in res
and subunit1.chain_residue_id <= res.get_id()[1]
<= subunit1.chain_residue_id + subunit1.length])
chain2_ca = np.array([res['CA'].coord for res in chain2.get_residues() if 'CA' in res
and subunit2.chain_residue_id <= res.get_id()[1]
<= subunit2.chain_residue_id + subunit2.length])
assert len(chain1_ca) > 0 and len(chain2_ca) > 0, f"No CA atoms found {subunit1} {subunit2} {pdb_path}"
return is_chains_coords_close(chain1_ca, chain2_ca)
def get_interface_res_ids(pdb_path: str, subunit1: SubunitPdbInfo, subunit2: SubunitPdbInfo) \
-> Tuple[List[int], List[int]]:
model = get_pdb_model_readonly(pdb_path)
chains = list(model.get_chains())
chain1 = [i for i in chains if i.get_id() == subunit1.chain_id][0]
chain2 = [i for i in chains if i.get_id() == subunit2.chain_id][0]
chain1_res = [res for res in chain1.get_residues() if 'CA' in res and subunit1.chain_residue_id <= res.get_id()[1]
<= subunit1.chain_residue_id + subunit1.length]
chain2_res = [res for res in chain2.get_residues() if 'CA' in res and subunit2.chain_residue_id <= res.get_id()[1]
<= subunit2.chain_residue_id + subunit2.length]
chain1_ca = np.array([res['CA'].coord for res in chain1_res])
chain2_ca = np.array([res['CA'].coord for res in chain2_res])
close_residues = np.argwhere(scipy.spatial.distance.cdist(chain1_ca, chain2_ca) < INTERFACE_MIN_ATOM_DIST)
chain1_interface, chain2_interface = set(), set()
for i, j in close_residues:
chain1_interface.add(chain1_res[i].id[1] - subunit1.chain_residue_id)
chain2_interface.add(chain2_res[j].id[1] - subunit2.chain_residue_id)
return sorted(list(chain1_interface)), sorted(list(chain2_interface))
|