Docking¶
Dock ligands to a Protein with the Deep Origin docking tool.
Prerequisites¶
- You have a prepared Protein
- You have a Ligand or LigandSet
- You have protonated your ligands
- You have found pockets in your protein using PocketFinder
Docking a single Ligand¶
Use Docking with your protein, pocket, and ligand. Here pocket is a Pocket from PocketFinder . Both Docking.run() and Docking.start() use client.executions.create: run() sets sync=True for one ligand (one blocking request until completion), and start() sets sync=False for a single persisted async job with two or more ligands. Docking.run() returns a LigandSet of poses.
from deeporigin.drug_discovery import Docking
docking = Docking(protein=protein, pocket=pocket, ligand=ligand)
poses = docking.run()
Estimating cost¶
To get a cost estimate without running the docking, call quote() on the Docking instance:
docking = Docking(protein=protein, pocket=pocket, ligand=ligand)
docking.quote() # populates docking.estimate
docking.estimate # estimated cost in dollars
docking.cost # None until a billable run completes
After a completed run, the actual cost is on the same object:
docking = Docking(protein=protein, pocket=pocket, ligand=ligand)
poses = docking.run()
docking.cost # actual cost in dollars
Viewing docked poses¶
Docked poses for that ligand can be viewed using:
protein.show(poses=poses)
You will see something similar to the following. Use the arrows to inspect individual poses.
Viewing pose scores and binding energy¶
Every pose is assigned a pose score and a binding energy. These can be viewed using:
poses
A widget similar to the following will be shown:
LigandSet with 15 poses
SMILES: Cc1[nH]c2cc(Cl)cc(Cl)c2c1CCN
Properties: Binding Energy, POSE SCORE, SMILES, initial_smiles
Use .to_dataframe() to convert to a dataframe, .show_df() to view dataframewith structures, or .show() for 3D visualization
To work with a dataframe containing this data, use:
df = poses.to_dataframe()
Exporting poses to SDF¶
Poses can be saved to a SDF file using:
poses.to_sdf()
Docking many ligands¶
Using batch jobs¶
Tutorial
Follow the tutorial on how to dock ligands using batch jobs. This is best suited for large jobs with 100+ ligands.
Using functions¶
Several ligands in a LigandSet can be docked by passing ligands to Docking, then Docking.start() (async). Poll with sync() or Jupyter helpers until the job completes, then call get_results() to retrieve a LigandSet of poses.
docking = Docking(protein=protein, pocket=pocket, ligands=ligands)
docking.start()
# … wait for completion (docking.sync() in a loop, or watch() in notebooks) …
poses = docking.get_results()
poses is a LigandSet containing the docked poses. To work with a DataFrame:
df = poses.to_dataframe()
To filter poses to keep only top poses, use:
top_poses = poses.filter_top_poses()
These poses can be visualized as before:
protein.show(poses=poses)
If you need SDF files for the poses (e.g. for export), use get_poses() instead, which downloads the SDF files from the platform:
poses = docking.get_poses()
poses.to_sdf("my_poses.sdf")
To estimate the cost of docking a full LigandSet without running it:
docking = Docking(protein=protein, pocket=pocket, ligands=ligands)
docking.quote()
docking.estimate # total estimated cost across all ligands
Working with existing runs¶
Reconnect to an asynchronous docking run started earlier, in this or a previous session, instead of re-submitting it:
# By execution id:
docking = Docking.from_id("<executionId>")
# Or the most recently created Docking run:
docking = Docking.from_last_run()
docking.sync() # refresh status from the platform
poses = docking.get_results()
from_last_run() returns the newest execution of that tool type, so call it on
the class you submitted with — ConstrainedDocking.from_last_run() for a
constrained run.
Constrained docking¶
Use ConstrainedDocking to dock test ligands while
preserving a reference binding mode. The platform derives harmonic constraints
server-side from MCS alignment between each test ligand and a supplied
reference pose. Callers provide reference_ligand (scaffold identity) and
reference_pose (required 3D SDF coordinates); they do not pass constraint
atom lists.
Dock-then-constrain pipeline¶
Dock a reference ligand, upload the best pose SDF, then constrained-dock analogs:
from deeporigin.drug_discovery import ConstrainedDocking, Docking
ref_poses = Docking(protein=protein, pocket=pocket, ligand=reference_ligand).run()
reference_pose = ref_poses.ligands[0]
reference_pose.sync(remote_path="testing/reference-pose.sdf")
cd = ConstrainedDocking(
protein=protein,
pocket=pocket,
reference_ligand=reference_ligand,
reference_pose=reference_pose,
ligand=query_ligand,
)
poses = cd.run()
Each test ligand must have SMILES or a structure file on the platform (load from
SDF/MOL2 and call ligand.sync(), or use Ligand.from_smiles and call
ligand.sync()). The reference pose must have 3D coordinates.
SMILES-only test ligands¶
When a test ligand has no structure file, provide SMILES and sync the entity:
from deeporigin.drug_discovery import ConstrainedDocking, Ligand
test_ligand = Ligand.from_smiles("CC(C)O")
test_ligand.sync()
cd = ConstrainedDocking(
protein=protein,
pocket=pocket,
reference_ligand=reference_ligand,
reference_pose=reference_pose,
ligand=test_ligand,
)
poses = cd.run()
The platform embeds the SMILES to an ephemeral 3D structure for MCS alignment. Reference ligand and reference pose still require structure files on the platform.
To view new poses together with the reference pose:
protein.show(poses=reference_pose + poses)
Inspect whether harmonic constraints were applied via the constrained property
on each pose in poses.to_dataframe(). When MCS cannot match a test ligand,
the tool free-docks that ligand and sets constrained=False.
Retrieve the reference pose echoed by the tool:
reported_reference = cd.get_reference_pose()
Multiple test ligands (async)¶
Pass ligands= and use start() / watch() for batch constrained docking:
cd = ConstrainedDocking(
protein=protein,
pocket=pocket,
reference_ligand=reference_ligand,
reference_pose=reference_pose,
ligands=analogs,
)
cd.start()
# … wait for completion …
poses = cd.get_results()
MCS override¶
Force a common scaffold with mcs_smarts or mcs_smiles (mutually exclusive):
cd = ConstrainedDocking(
protein=protein,
pocket=pocket,
reference_ligand=reference_ligand,
reference_pose=reference_pose,
ligand=query_ligand,
mcs_smarts="C(=O)",
)
poses = cd.run()
Estimating cost¶
cd = ConstrainedDocking(
protein=protein,
pocket=pocket,
reference_ligand=reference_ligand,
reference_pose=reference_pose,
ligand=query_ligand,
)
cd.run(quote=True)
cd.estimate
Filtering docking outputs¶
Filter docking results by score and related properties.
Deprecated: Complex
The examples below use the deprecated Complex type. New workflows should use Docking (and related APIs) instead of Complex.docking.
Here we assume that you have constructed a Complex object and successfully run Docking.
Following convention, we assume that the Complex object is called sim.
Fetch docked poses¶
First, we get the results of Docking in a pandas DataFrame using:
poses = sim.docking.get_poses()
poses object shows us:
LigandSet with 2246 ligands
157 unique SMILES
Properties: Binding Energy, POSE SCORE, SCORE, SMILES, initial_smiles
Use .to_dataframe() to convert to a dataframe, .show_df() to view dataframewith structures, or .show() for 3D visualization
Plot docking results¶
The metrics of all docked poses can be plotted in a scatter plot using:
poses.plot()
Pick top results¶
We can pick the top pose for each SMILES string using:
poses.filter_top_poses()