Docking Integration

This notebook demonstrates preparing Auto3D-generated conformers for molecular docking:

  1. AutoDock Vina - PDBQT format preparation

  2. Open Babel - format conversion

  3. Docking workflow - from SMILES to docked poses

  4. Post-processing - analyzing docking results

Workflow Overview

SMILES → Auto3D (3D conformers) → Format conversion → Docking → Analysis
[ ]:
import os
import tempfile
import subprocess
from pathlib import Path

import Auto3D
from Auto3D import Auto3DOptions, main
from rdkit import Chem
from rdkit.Chem import AllChem

print(f"Auto3D version: {Auto3D.__version__}")

1. Prepare Ligands with Auto3D

Generate optimized 3D conformers for docking.

[ ]:
# Example ligands for docking
ligands = {
    "aspirin": "CC(=O)OC1=CC=CC=C1C(=O)O",
    "ibuprofen": "CC(C)CC1=CC=C(C=C1)C(C)C(=O)O",
    "naproxen": "COC1=CC2=CC(C(C)C(=O)O)=CC=C2C=C1",
}

with tempfile.NamedTemporaryFile(mode='w', suffix='.smi', delete=False) as f:
    for name, smi in ligands.items():
        f.write(f"{smi} {name}\n")
    input_file = f.name

print(f"Ligands: {list(ligands.keys())}")

CLI Alternative

You can generate docking-ready conformers from the command line:

# Generate multiple conformers for docking
auto3d run ligands.smi --k=3 --window=3.0 --gpu

# For fast screening
auto3d run ligands.smi --k=5 --engine=ANI2xt --gpu

# With configuration file
auto3d run ligands.smi -c docking.yaml

Example docking.yaml:

k: 3
window: 3.0
optimizing_engine: AIMNET
threshold: 0.5
use_gpu: true

2. Convert to PDBQT (AutoDock Vina)

AutoDock Vina requires PDBQT format with Gasteiger charges.

[ ]:
def sdf_to_pdbqt_obabel(sdf_path, output_dir=None):
    """
    Convert SDF to PDBQT using Open Babel.

    Requires: openbabel installed (`conda install -c conda-forge openbabel`)
    """
    if output_dir is None:
        output_dir = Path(sdf_path).parent
    else:
        output_dir = Path(output_dir)
        output_dir.mkdir(exist_ok=True)

    # Read molecules
    mols = list(Chem.SDMolSupplier(sdf_path, removeHs=False))
    pdbqt_files = []

    for i, mol in enumerate(mols):
        if mol is None:
            continue

        name = mol.GetProp("_Name").replace(" ", "_")

        # Write individual SDF
        temp_sdf = output_dir / f"{name}.sdf"
        with Chem.SDWriter(str(temp_sdf)) as w:
            w.write(mol)

        # Convert with Open Babel
        pdbqt_file = output_dir / f"{name}.pdbqt"

        cmd = f"obabel {temp_sdf} -O {pdbqt_file} --partialcharge gasteiger"

        try:
            result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
            if pdbqt_file.exists():
                pdbqt_files.append(str(pdbqt_file))
                print(f"  Created: {pdbqt_file.name}")
        except Exception as e:
            print(f"  Error converting {name}: {e}")

        # Cleanup temp SDF
        if temp_sdf.exists():
            temp_sdf.unlink()

    return pdbqt_files


# Check if Open Babel is available
try:
    result = subprocess.run("obabel -V", shell=True, capture_output=True)
    print("Open Babel is available")
    obabel_available = True
except:
    print("Open Babel not found. Install with: conda install -c conda-forge openbabel")
    obabel_available = False
[ ]:
# Convert to PDBQT
if 'sdf_output' in dir() and obabel_available:
    pdbqt_dir = Path(sdf_output).parent / "pdbqt"
    pdbqt_files = sdf_to_pdbqt_obabel(sdf_output, pdbqt_dir)
    print(f"\nCreated {len(pdbqt_files)} PDBQT files")

3. Vina Docking Configuration

Example configuration for AutoDock Vina.

[ ]:
def create_vina_config(receptor_pdbqt, ligand_pdbqt, output_pdbqt,
                       center, size, exhaustiveness=32):
    """
    Create AutoDock Vina configuration file.

    Args:
        receptor_pdbqt: Path to receptor PDBQT
        ligand_pdbqt: Path to ligand PDBQT
        output_pdbqt: Path for output
        center: (x, y, z) center of search box
        size: (x, y, z) size of search box
        exhaustiveness: Search thoroughness (8-32)
    """
    config = f"""
receptor = {receptor_pdbqt}
ligand = {ligand_pdbqt}
out = {output_pdbqt}

center_x = {center[0]}
center_y = {center[1]}
center_z = {center[2]}

size_x = {size[0]}
size_y = {size[1]}
size_z = {size[2]}

exhaustiveness = {exhaustiveness}
num_modes = 9
energy_range = 3
"""
    return config.strip()


# Example configuration
print("Example Vina configuration:")
print("-" * 40)
example_config = create_vina_config(
    receptor_pdbqt="receptor.pdbqt",
    ligand_pdbqt="ligand.pdbqt",
    output_pdbqt="docked.pdbqt",
    center=(10.0, 20.0, 30.0),
    size=(25, 25, 25),
    exhaustiveness=32
)
print(example_config)
[ ]:
def run_vina_docking(config_file):
    """
    Run AutoDock Vina with configuration file.

    Requires: AutoDock Vina installed
    """
    cmd = f"vina --config {config_file}"

    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
        return result.stdout
    except Exception as e:
        return f"Error: {e}"


print("\nTo run docking:")
print("  1. Prepare receptor PDBQT (from PDB using prepare_receptor4.py or Open Babel)")
print("  2. Define binding site (center and size)")
print("  3. Run: vina --config config.txt")
print("  4. Analyze output poses")

4. Alternative: MOL2 for GOLD

GOLD docking requires MOL2 format.

[ ]:
def sdf_to_mol2_obabel(sdf_path, output_dir=None):
    """
    Convert SDF to MOL2 using Open Babel.
    """
    if output_dir is None:
        output_dir = Path(sdf_path).parent
    else:
        output_dir = Path(output_dir)

    mol2_file = output_dir / (Path(sdf_path).stem + ".mol2")

    cmd = f"obabel {sdf_path} -O {mol2_file}"

    try:
        subprocess.run(cmd, shell=True, capture_output=True)
        if mol2_file.exists():
            return str(mol2_file)
    except:
        pass

    return None


if 'sdf_output' in dir() and obabel_available:
    mol2_file = sdf_to_mol2_obabel(sdf_output)
    if mol2_file:
        print(f"Created MOL2: {mol2_file}")

5. Post-Docking Analysis

Analyze docking results.

[ ]:
def parse_vina_output(pdbqt_path):
    """
    Parse Vina output PDBQT to extract poses and scores.
    """
    poses = []
    current_pose = None

    with open(pdbqt_path) as f:
        for line in f:
            if line.startswith("MODEL"):
                current_pose = {"model": int(line.split()[1]), "lines": []}
            elif line.startswith("REMARK VINA RESULT:"):
                parts = line.split()
                if current_pose:
                    current_pose["affinity"] = float(parts[3])
                    current_pose["rmsd_lb"] = float(parts[4])
                    current_pose["rmsd_ub"] = float(parts[5])
            elif line.startswith("ENDMDL"):
                if current_pose:
                    poses.append(current_pose)
                current_pose = None
            elif current_pose:
                current_pose["lines"].append(line)

    return poses


print("Docking result analysis functions available.")
print("\nTypical Vina scores:")
print("  Excellent: < -10 kcal/mol")
print("  Good: -8 to -10 kcal/mol")
print("  Moderate: -6 to -8 kcal/mol")
print("  Weak: > -6 kcal/mol")

6. Complete Workflow Example

End-to-end workflow from SMILES to docking.

[ ]:
def smiles_to_docking_ready(smiles_dict, output_dir, k=3, window=3.0):
    """
    Complete workflow: SMILES → Auto3D → docking-ready files.

    Returns paths to SDF and PDBQT files.
    """
    output_dir = Path(output_dir)
    output_dir.mkdir(exist_ok=True)

    # Step 1: Write SMILES
    smi_file = output_dir / "input.smi"
    with open(smi_file, 'w') as f:
        for name, smi in smiles_dict.items():
            f.write(f"{smi} {name}\n")

    # Step 2: Run Auto3D
    config = Auto3DOptions(
        path=str(smi_file),
        k=k,
        window=window,
        optimizing_engine="AIMNET",
        use_gpu=True,
    )

    sdf_output = main(config)

    # Step 3: Convert to PDBQT (if Open Babel available)
    pdbqt_files = []
    try:
        pdbqt_dir = output_dir / "pdbqt"
        pdbqt_files = sdf_to_pdbqt_obabel(sdf_output, pdbqt_dir)
    except:
        pass

    return {
        "sdf": sdf_output,
        "pdbqt_files": pdbqt_files
    }


print("Complete workflow function defined.")
print("Usage: smiles_to_docking_ready({'drug': 'SMILES'}, 'output/')")

Summary

This tutorial covered:

  1. 3D conformer generation with Auto3D (optimized geometries)

  2. Format conversion to PDBQT (Vina) and MOL2 (GOLD)

  3. Docking configuration for AutoDock Vina

  4. Post-processing of docking results

Key points:

  • Auto3D provides better starting geometries than force field methods

  • Multiple conformers improve binding mode sampling

  • Use Gasteiger charges for AutoDock Vina

[ ]:
# Cleanup
if 'input_file' in dir() and os.path.exists(input_file):
    os.unlink(input_file)