Download scripts/libs/utils_pdb.py from OneScience-Group/CombFold: direct link, hf CLI and curl.
- Browser
- Download file 6.59 kB
-
https://huggingface.co/OneScience-Group/CombFold/resolve/main/scripts/libs/utils_pdb.py
- Command line
-
hf download hf://OneScience-Group/CombFold/scripts/libs/utils_pdb.py
-
curl -L -o utils_pdb.py https://huggingface.co/OneScience-Group/CombFold/resolve/main/scripts/libs/utils_pdb.py
6.59 kB
| 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 | |
| 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)) | |