Skip to content
Snippets Groups Projects
window.py 1.79 KiB
Newer Older
from rdkit import Chem
from Bio.PDB import PDBParser
import numpy as np

def compute_box(
    receptor_path:str, 
    ligand_path:str, 
    cutoff:float=5.0, 
    padding:float=5.0) -> "dict[str, tuple[float, float, float]]":
    
    """
    calculates the dimensions and center of the docking box
    @param receptor_path: path to the receptor file (.pdb)
    @param ligand_path: path to the ligand file (.sdf)
    @param cutoff: capture distance for neighbour atoms (angstrom)
    @param padding: padding around the box to ensure the ligand is inside (angstrom)
    @return: center coordinates (x, y, z) and sizes (x, y, z) of the box
    """
    
    ligand = Chem.SDMolSupplier(ligand_path)[0]
    ligand_coords = np.array([list(ligand.GetConformer().GetAtomPosition(i)) 
        for i in range(ligand.GetNumAtoms())])
    structure = PDBParser(QUIET=True).get_structure('receptor', receptor_path)
    atoms = list(structure.get_atoms()) # get all atoms in receptor

    # compute the geometric center of the ligand (center of mass)
    ligand_center = np.mean(ligand_coords, axis=0).astype(float)
    
    # collect atoms close to the ligand
    site_atoms = np.array([atom.coord 
        for atom in atoms 
        if np.linalg.norm(atom.coord - ligand_center) <= cutoff]).astype(float)
    if site_atoms.size == 0:
        site_atoms = ligand_coords

    # compute min/max coordinates for the docking box
    x_min, y_min, z_min = np.min(site_atoms, axis=0)
    x_max, y_max, z_max = np.max(site_atoms, axis=0)
    
    return {
        "center": (
            (x_min + x_max) / 2, 
            (y_min + y_max) / 2, 
            (z_min + z_max) / 2
        ),
        "size": (
            (x_max - x_min) + 2 * padding, 
            (y_max - y_min) + 2 * padding, 
            (z_max - z_min) + 2 * padding
        )
    }