Spaces:
Runtime error
Runtime error
import os | |
import shutil | |
import tempfile | |
import subprocess | |
import dataclasses as dc | |
from typing import List, Optional | |
from Bio import PDB | |
from Bio.PDB import Model as PDBModel | |
from diffab.tools.renumber import renumber as renumber_chothia | |
from .base import DockingEngine | |
def fix_docked_pdb(pdb_path): | |
fixed = [] | |
with open(pdb_path, 'r') as f: | |
for ln in f.readlines(): | |
if (ln.startswith('ATOM') or ln.startswith('HETATM')) and len(ln) == 56: | |
fixed.append( ln[:-1] + ' 1.00 0.00 \n' ) | |
else: | |
fixed.append(ln) | |
with open(pdb_path, 'w') as f: | |
f.write(''.join(fixed)) | |
class HDock(DockingEngine): | |
def __init__( | |
self, | |
hdock_bin='./bin/hdock', | |
createpl_bin='./bin/createpl', | |
): | |
super().__init__() | |
self.hdock_bin = os.path.realpath(hdock_bin) | |
self.createpl_bin = os.path.realpath(createpl_bin) | |
self.tmpdir = tempfile.TemporaryDirectory() | |
self._has_receptor = False | |
self._has_ligand = False | |
self._receptor_chains = [] | |
self._ligand_chains = [] | |
def __enter__(self): | |
return self | |
def __exit__(self, typ, value, traceback): | |
self.tmpdir.cleanup() | |
def set_receptor(self, pdb_path): | |
shutil.copyfile(pdb_path, os.path.join(self.tmpdir.name, 'receptor.pdb')) | |
self._has_receptor = True | |
def set_ligand(self, pdb_path): | |
shutil.copyfile(pdb_path, os.path.join(self.tmpdir.name, 'ligand.pdb')) | |
self._has_ligand = True | |
def _dump_complex_pdb(self): | |
parser = PDB.PDBParser(QUIET=True) | |
model_receptor = parser.get_structure(None, os.path.join(self.tmpdir.name, 'receptor.pdb'))[0] | |
docked_pdb_path = os.path.join(self.tmpdir.name, 'ligand_docked.pdb') | |
fix_docked_pdb(docked_pdb_path) | |
structure_ligdocked = parser.get_structure(None, docked_pdb_path) | |
pdb_io = PDB.PDBIO() | |
paths = [] | |
for i, model_ligdocked in enumerate(structure_ligdocked): | |
model_complex = PDBModel.Model(0) | |
for chain in model_receptor: | |
model_complex.add(chain.copy()) | |
for chain in model_ligdocked: | |
model_complex.add(chain.copy()) | |
pdb_io.set_structure(model_complex) | |
save_path = os.path.join(self.tmpdir.name, f"complex_{i}.pdb") | |
pdb_io.save(save_path) | |
paths.append(save_path) | |
return paths | |
def dock(self): | |
if not (self._has_receptor and self._has_ligand): | |
raise ValueError('Missing receptor or ligand.') | |
subprocess.run( | |
[self.hdock_bin, "receptor.pdb", "ligand.pdb"], | |
cwd=self.tmpdir.name, check=True | |
) | |
subprocess.run( | |
[self.createpl_bin, "Hdock.out", "ligand_docked.pdb"], | |
cwd=self.tmpdir.name, check=True | |
) | |
return self._dump_complex_pdb() | |
class DockSite: | |
chain: str | |
resseq: int | |
class HDockAntibody(HDock): | |
def __init__(self, *args, **kwargs): | |
super().__init__(*args, **kwargs) | |
self._heavy_chain_id = None | |
self._epitope_sites: Optional[List[DockSite]] = None | |
def set_ligand(self, pdb_path): | |
raise NotImplementedError('Please use set_antibody') | |
def set_receptor(self, pdb_path): | |
raise NotImplementedError('Please use set_antigen') | |
def set_antigen(self, pdb_path, epitope_sites: Optional[List[DockSite]]=None): | |
super().set_receptor(pdb_path) | |
self._epitope_sites = epitope_sites | |
def set_antibody(self, pdb_path): | |
heavy_chains, _ = renumber_chothia(pdb_path, os.path.join(self.tmpdir.name, 'ligand.pdb')) | |
self._has_ligand = True | |
self._heavy_chain_id = heavy_chains[0] | |
def _prepare_lsite(self): | |
lsite_content = f"95-102:{self._heavy_chain_id}\n" # Chothia CDR H3 | |
with open(os.path.join(self.tmpdir.name, 'lsite.txt'), 'w') as f: | |
f.write(lsite_content) | |
print(f"[INFO] lsite content: {lsite_content}") | |
def _prepare_rsite(self): | |
rsite_content = "" | |
for site in self._epitope_sites: | |
rsite_content += f"{site.resseq}:{site.chain}\n" | |
with open(os.path.join(self.tmpdir.name, 'rsite.txt'), 'w') as f: | |
f.write(rsite_content) | |
print(f"[INFO] rsite content: {rsite_content}") | |
def dock(self): | |
if not (self._has_receptor and self._has_ligand): | |
raise ValueError('Missing receptor or ligand.') | |
self._prepare_lsite() | |
cmd_hdock = [self.hdock_bin, "receptor.pdb", "ligand.pdb", "-lsite", "lsite.txt"] | |
if self._epitope_sites is not None: | |
self._prepare_rsite() | |
cmd_hdock += ["-rsite", "rsite.txt"] | |
subprocess.run( | |
cmd_hdock, | |
cwd=self.tmpdir.name, check=True | |
) | |
cmd_pl = [self.createpl_bin, "Hdock.out", "ligand_docked.pdb", "-lsite", "lsite.txt"] | |
if self._epitope_sites is not None: | |
self._prepare_rsite() | |
cmd_pl += ["-rsite", "rsite.txt"] | |
subprocess.run( | |
cmd_pl, | |
cwd=self.tmpdir.name, check=True | |
) | |
return self._dump_complex_pdb() | |
if __name__ == '__main__': | |
with HDockAntibody('hdock', 'createpl') as dock: | |
dock.set_antigen('./data/dock/receptor.pdb', [DockSite('A', 991)]) | |
dock.set_antibody('./data/example_dock/3qhf_fv.pdb') | |
print(dock.dock()) | |