Docking Integration
This notebook demonstrates preparing Auto3D-generated conformers for molecular docking:
AutoDock Vina - PDBQT format preparation
Open Babel - format conversion
Docking workflow - from SMILES to docked poses
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:
3D conformer generation with Auto3D (optimized geometries)
Format conversion to PDBQT (Vina) and MOL2 (GOLD)
Docking configuration for AutoDock Vina
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)