{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Docking Integration\n", "\n", "This notebook demonstrates preparing Auto3D-generated conformers for molecular docking:\n", "\n", "1. **AutoDock Vina** - PDBQT format preparation\n", "2. **Open Babel** - format conversion\n", "3. **Docking workflow** - from SMILES to docked poses\n", "4. **Post-processing** - analyzing docking results\n", "\n", "## Workflow Overview\n", "\n", "```\n", "SMILES → Auto3D (3D conformers) → Format conversion → Docking → Analysis\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "import tempfile\n", "import subprocess\n", "from pathlib import Path\n", "\n", "import Auto3D\n", "from Auto3D import Auto3DOptions, main\n", "from rdkit import Chem\n", "from rdkit.Chem import AllChem\n", "\n", "print(f\"Auto3D version: {Auto3D.__version__}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Prepare Ligands with Auto3D\n", "\n", "Generate optimized 3D conformers for docking." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Example ligands for docking\n", "ligands = {\n", " \"aspirin\": \"CC(=O)OC1=CC=CC=C1C(=O)O\",\n", " \"ibuprofen\": \"CC(C)CC1=CC=C(C=C1)C(C)C(=O)O\",\n", " \"naproxen\": \"COC1=CC2=CC(C(C)C(=O)O)=CC=C2C=C1\",\n", "}\n", "\n", "with tempfile.NamedTemporaryFile(mode='w', suffix='.smi', delete=False) as f:\n", " for name, smi in ligands.items():\n", " f.write(f\"{smi} {name}\\n\")\n", " input_file = f.name\n", "\n", "print(f\"Ligands: {list(ligands.keys())}\")" ] }, { "cell_type": "markdown", "execution_count": null, "metadata": {}, "outputs": [], "source": "### CLI Alternative\n\nYou can generate docking-ready conformers from the command line:\n\n```bash\n# Generate multiple conformers for docking\nauto3d run ligands.smi --k=3 --window=3.0 --gpu\n\n# For fast screening\nauto3d run ligands.smi --k=5 --engine=ANI2xt --gpu\n\n# With configuration file\nauto3d run ligands.smi -c docking.yaml\n```\n\nExample `docking.yaml`:\n\n```yaml\nk: 3\nwindow: 3.0\noptimizing_engine: AIMNET\nthreshold: 0.5\nuse_gpu: true\n```" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Convert to PDBQT (AutoDock Vina)\n", "\n", "AutoDock Vina requires PDBQT format with Gasteiger charges." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def sdf_to_pdbqt_obabel(sdf_path, output_dir=None):\n", " \"\"\"\n", " Convert SDF to PDBQT using Open Babel.\n", " \n", " Requires: openbabel installed (`conda install -c conda-forge openbabel`)\n", " \"\"\"\n", " if output_dir is None:\n", " output_dir = Path(sdf_path).parent\n", " else:\n", " output_dir = Path(output_dir)\n", " output_dir.mkdir(exist_ok=True)\n", " \n", " # Read molecules\n", " mols = list(Chem.SDMolSupplier(sdf_path, removeHs=False))\n", " pdbqt_files = []\n", " \n", " for i, mol in enumerate(mols):\n", " if mol is None:\n", " continue\n", " \n", " name = mol.GetProp(\"_Name\").replace(\" \", \"_\")\n", " \n", " # Write individual SDF\n", " temp_sdf = output_dir / f\"{name}.sdf\"\n", " with Chem.SDWriter(str(temp_sdf)) as w:\n", " w.write(mol)\n", " \n", " # Convert with Open Babel\n", " pdbqt_file = output_dir / f\"{name}.pdbqt\"\n", " \n", " cmd = f\"obabel {temp_sdf} -O {pdbqt_file} --partialcharge gasteiger\"\n", " \n", " try:\n", " result = subprocess.run(cmd, shell=True, capture_output=True, text=True)\n", " if pdbqt_file.exists():\n", " pdbqt_files.append(str(pdbqt_file))\n", " print(f\" Created: {pdbqt_file.name}\")\n", " except Exception as e:\n", " print(f\" Error converting {name}: {e}\")\n", " \n", " # Cleanup temp SDF\n", " if temp_sdf.exists():\n", " temp_sdf.unlink()\n", " \n", " return pdbqt_files\n", "\n", "\n", "# Check if Open Babel is available\n", "try:\n", " result = subprocess.run(\"obabel -V\", shell=True, capture_output=True)\n", " print(\"Open Babel is available\")\n", " obabel_available = True\n", "except:\n", " print(\"Open Babel not found. Install with: conda install -c conda-forge openbabel\")\n", " obabel_available = False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Convert to PDBQT\n", "if 'sdf_output' in dir() and obabel_available:\n", " pdbqt_dir = Path(sdf_output).parent / \"pdbqt\"\n", " pdbqt_files = sdf_to_pdbqt_obabel(sdf_output, pdbqt_dir)\n", " print(f\"\\nCreated {len(pdbqt_files)} PDBQT files\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Vina Docking Configuration\n", "\n", "Example configuration for AutoDock Vina." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def create_vina_config(receptor_pdbqt, ligand_pdbqt, output_pdbqt,\n", " center, size, exhaustiveness=32):\n", " \"\"\"\n", " Create AutoDock Vina configuration file.\n", " \n", " Args:\n", " receptor_pdbqt: Path to receptor PDBQT\n", " ligand_pdbqt: Path to ligand PDBQT\n", " output_pdbqt: Path for output\n", " center: (x, y, z) center of search box\n", " size: (x, y, z) size of search box\n", " exhaustiveness: Search thoroughness (8-32)\n", " \"\"\"\n", " config = f\"\"\"\n", "receptor = {receptor_pdbqt}\n", "ligand = {ligand_pdbqt}\n", "out = {output_pdbqt}\n", "\n", "center_x = {center[0]}\n", "center_y = {center[1]}\n", "center_z = {center[2]}\n", "\n", "size_x = {size[0]}\n", "size_y = {size[1]}\n", "size_z = {size[2]}\n", "\n", "exhaustiveness = {exhaustiveness}\n", "num_modes = 9\n", "energy_range = 3\n", "\"\"\"\n", " return config.strip()\n", "\n", "\n", "# Example configuration\n", "print(\"Example Vina configuration:\")\n", "print(\"-\" * 40)\n", "example_config = create_vina_config(\n", " receptor_pdbqt=\"receptor.pdbqt\",\n", " ligand_pdbqt=\"ligand.pdbqt\",\n", " output_pdbqt=\"docked.pdbqt\",\n", " center=(10.0, 20.0, 30.0),\n", " size=(25, 25, 25),\n", " exhaustiveness=32\n", ")\n", "print(example_config)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def run_vina_docking(config_file):\n", " \"\"\"\n", " Run AutoDock Vina with configuration file.\n", " \n", " Requires: AutoDock Vina installed\n", " \"\"\"\n", " cmd = f\"vina --config {config_file}\"\n", " \n", " try:\n", " result = subprocess.run(cmd, shell=True, capture_output=True, text=True)\n", " return result.stdout\n", " except Exception as e:\n", " return f\"Error: {e}\"\n", "\n", "\n", "print(\"\\nTo run docking:\")\n", "print(\" 1. Prepare receptor PDBQT (from PDB using prepare_receptor4.py or Open Babel)\")\n", "print(\" 2. Define binding site (center and size)\")\n", "print(\" 3. Run: vina --config config.txt\")\n", "print(\" 4. Analyze output poses\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. Alternative: MOL2 for GOLD\n", "\n", "GOLD docking requires MOL2 format." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def sdf_to_mol2_obabel(sdf_path, output_dir=None):\n", " \"\"\"\n", " Convert SDF to MOL2 using Open Babel.\n", " \"\"\"\n", " if output_dir is None:\n", " output_dir = Path(sdf_path).parent\n", " else:\n", " output_dir = Path(output_dir)\n", " \n", " mol2_file = output_dir / (Path(sdf_path).stem + \".mol2\")\n", " \n", " cmd = f\"obabel {sdf_path} -O {mol2_file}\"\n", " \n", " try:\n", " subprocess.run(cmd, shell=True, capture_output=True)\n", " if mol2_file.exists():\n", " return str(mol2_file)\n", " except:\n", " pass\n", " \n", " return None\n", "\n", "\n", "if 'sdf_output' in dir() and obabel_available:\n", " mol2_file = sdf_to_mol2_obabel(sdf_output)\n", " if mol2_file:\n", " print(f\"Created MOL2: {mol2_file}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5. Post-Docking Analysis\n", "\n", "Analyze docking results." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def parse_vina_output(pdbqt_path):\n", " \"\"\"\n", " Parse Vina output PDBQT to extract poses and scores.\n", " \"\"\"\n", " poses = []\n", " current_pose = None\n", " \n", " with open(pdbqt_path) as f:\n", " for line in f:\n", " if line.startswith(\"MODEL\"):\n", " current_pose = {\"model\": int(line.split()[1]), \"lines\": []}\n", " elif line.startswith(\"REMARK VINA RESULT:\"):\n", " parts = line.split()\n", " if current_pose:\n", " current_pose[\"affinity\"] = float(parts[3])\n", " current_pose[\"rmsd_lb\"] = float(parts[4])\n", " current_pose[\"rmsd_ub\"] = float(parts[5])\n", " elif line.startswith(\"ENDMDL\"):\n", " if current_pose:\n", " poses.append(current_pose)\n", " current_pose = None\n", " elif current_pose:\n", " current_pose[\"lines\"].append(line)\n", " \n", " return poses\n", "\n", "\n", "print(\"Docking result analysis functions available.\")\n", "print(\"\\nTypical Vina scores:\")\n", "print(\" Excellent: < -10 kcal/mol\")\n", "print(\" Good: -8 to -10 kcal/mol\")\n", "print(\" Moderate: -6 to -8 kcal/mol\")\n", "print(\" Weak: > -6 kcal/mol\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6. Complete Workflow Example\n", "\n", "End-to-end workflow from SMILES to docking." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def smiles_to_docking_ready(smiles_dict, output_dir, k=3, window=3.0):\n", " \"\"\"\n", " Complete workflow: SMILES → Auto3D → docking-ready files.\n", " \n", " Returns paths to SDF and PDBQT files.\n", " \"\"\"\n", " output_dir = Path(output_dir)\n", " output_dir.mkdir(exist_ok=True)\n", " \n", " # Step 1: Write SMILES\n", " smi_file = output_dir / \"input.smi\"\n", " with open(smi_file, 'w') as f:\n", " for name, smi in smiles_dict.items():\n", " f.write(f\"{smi} {name}\\n\")\n", " \n", " # Step 2: Run Auto3D\n", " config = Auto3DOptions(\n", " path=str(smi_file),\n", " k=k,\n", " window=window,\n", " optimizing_engine=\"AIMNET\",\n", " use_gpu=True,\n", " )\n", " \n", " sdf_output = main(config)\n", " \n", " # Step 3: Convert to PDBQT (if Open Babel available)\n", " pdbqt_files = []\n", " try:\n", " pdbqt_dir = output_dir / \"pdbqt\"\n", " pdbqt_files = sdf_to_pdbqt_obabel(sdf_output, pdbqt_dir)\n", " except:\n", " pass\n", " \n", " return {\n", " \"sdf\": sdf_output,\n", " \"pdbqt_files\": pdbqt_files\n", " }\n", "\n", "\n", "print(\"Complete workflow function defined.\")\n", "print(\"Usage: smiles_to_docking_ready({'drug': 'SMILES'}, 'output/')\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", "This tutorial covered:\n", "\n", "1. **3D conformer generation** with Auto3D (optimized geometries)\n", "2. **Format conversion** to PDBQT (Vina) and MOL2 (GOLD)\n", "3. **Docking configuration** for AutoDock Vina\n", "4. **Post-processing** of docking results\n", "\n", "Key points:\n", "- Auto3D provides **better starting geometries** than force field methods\n", "- Multiple conformers improve **binding mode sampling**\n", "- Use **Gasteiger charges** for AutoDock Vina" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Cleanup\n", "if 'input_file' in dir() and os.path.exists(input_file):\n", " os.unlink(input_file)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.10.0" } }, "nbformat": 4, "nbformat_minor": 4 }