Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .cursor/rules/python.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ alwaysApply: true

# Code Style

- Use beartype for runtime type validation
- Use type hints for all function arguments and return types
- Use f-strings for string formatting
- Prefer string literals over Enums
Expand Down
33 changes: 33 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Deep Origin CLI — Drug Discovery

Python SDK for Deep Origin drug-discovery workflows: proteins, ligands, docking,
system preparation, and free-energy calculations.

## Language

**ABFE Workflow**:
Platform tool `deeporigin.abfe-end-to-end` that runs ordered `steps` of
`system-prep` and/or `abfe`. The CLI uses the same public key as platform-ui and
platform infra; v5 workflow versions (e.g. `1.0.x`) replace the legacy v3 job
implementation under that key.
_Avoid_: `deeporigin.abfe-e2e-workflow`, `mode` discriminator (superseded legacy)

**Combined workflow**:
A single `ABFE(protein, ligand)` execution with `steps=["system-prep", "abfe"]`.
_Avoid_: conflating the workflow *steps* with the platform tool key

**FEP parameters**:
Shared simulation settings (`ABFEParams`) for binding and solvation legs, used by both ABFE and RBFE.
_Avoid_: Duplicating binding/solvation blocks per tool class

**Prepared system**:
Simulation-ready binding and solvation XML files (and metadata) produced by system prep.
_Avoid_: "system" alone when meaning the prepared molecular system artifact

**Workflow step**:
A named stage in a combined workflow execution (`system-prep`, `abfe`, `rbfe`, `konnektor`).
_Avoid_: `mode` for v5 workflow tools

**KonnektorResult**:
CLI return type from `Konnektor.run()` — resolved ligand pairs, connectivity flag, and inline viz HTML.
_Avoid_: conflating with platform ingest entity `LigandNetwork` or legacy `LigandSet.network` dict
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ mock-server:
@echo "Starting mock server..."
uv run python -m tests.run_mock_server \
$(if $(PORT),--port $(PORT),) \
$(if $(ABFE_DURATION),--abfe-duration $(ABFE_DURATION),)
$(if $(ABFE_DURATION),--abfe-duration $(ABFE_DURATION),) \
$(if $(RBFE_DURATION),--rbfe-duration $(RBFE_DURATION),)


# Build image from current directory and start an interactive shell
Expand Down
15 changes: 8 additions & 7 deletions docs/dd/how-to/ligands.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,17 +396,18 @@ You can generate 3D coordinates for a single ligand or all ligands in a LigandSe

### Constructing a network using Konnektor

To run RBFE, it is helpful to map out a network within the ligand set, so that we can run RBFE on those pairs of ligands. To do so, use:
To run RBFE, it is helpful to map out a network within the ligand set, so that we can run RBFE on those pairs of ligands. Use the Konnektor platform tool:

```{.python notest}
# assuming ligands is a LigandSet
ligands.map_network().show_network()
```
from deeporigin.drug_discovery import Konnektor

This maps the network and creates a visualization similar to:
# assuming ligands is a LigandSet with at least two ligands
result = Konnektor(ligands=ligands).run()
result.show_network()
pairs = result.pairs
```

!!! note "Mutation Behavior"
The `map_network()` method mutates the LigandSet by storing the network in `self.network` and returns `self` for method chaining.
`result.pairs` is a list of `(ligand1, ligand2)` tuples suitable for RBFE. The visualization is similar to:

<iframe
src="../../images/network.html"
Expand Down
6 changes: 6 additions & 0 deletions docs/dd/ref/abfe.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# `deeporigin.drug_discovery.abfe`

`ABFE` drives platform tool `deeporigin.abfe-end-to-end`. Constructor inputs infer workflow
`steps` the same way as [`RBFE`](rbfe.md): `protein` + `ligand` runs
`["system-prep", "abfe"]`; `prepared_system` runs `["abfe"]` only. FEP
simulation settings are shared with RBFE via [`ABFEParams`](fep_common.md)
(also exported as `RBFEParams` from `rbfe`).

::: src.drug_discovery.abfe
options:
docstring_style: google
Expand Down
6 changes: 5 additions & 1 deletion docs/dd/ref/execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ path you will use after :meth:`Execution.confirm`:
``confirm()`` only sends ``executionId`` to the platform; it cannot change inputs
or switch sync/async. The SDK applies the confirm response with
:meth:`Execution.update_from_dto` (``status``, :attr:`~deeporigin.drug_discovery.execution.Execution.cost`,
:attr:`~deeporigin.drug_discovery.execution.Execution.dto`). The SDK stores ``_quoted_mode`` so ``start()`` rejects a
:attr:`~deeporigin.drug_discovery.execution.Execution.dto`, :attr:`~deeporigin.drug_discovery.execution.Execution.estimate`).
Pricing is derived from ``quotationResult.successfulQuotations`` via
:meth:`Execution._quotation_total` (summed across all billable items).
User log rows from :meth:`Execution.get_user_logs` are formatted via
:meth:`Execution._user_logs_dataframe`. The SDK stores ``_quoted_mode`` so ``start()`` rejects a
sync-mode quote and ``run()`` can reject an async-mode quote (see each tool).

::: src.drug_discovery.execution
Expand Down
19 changes: 19 additions & 0 deletions docs/dd/ref/fep_common.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# `deeporigin.drug_discovery.fep_common`

Shared FEP parameter types and serialization helpers used by `ABFE` and `RBFE`.

::: src.drug_discovery.fep_common
options:
docstring_style: google
show_root_heading: false
show_category_heading: true
show_object_full_path: false
show_root_toc_entry: false
inherited_members: true
members_order: alphabetical
filters:
- "!^_"
show_signature: true
show_signature_annotations: true
show_if_no_docstring: true
group_by_category: true
11 changes: 2 additions & 9 deletions docs/dd/ref/execution-helpers.md → docs/dd/ref/konnektor.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
# `deeporigin.drug_discovery.execution_helpers`
# `deeporigin.drug_discovery.konnektor`

Helpers shared by tool execution classes (for example `Docking`, `PocketFinder`,
`SystemPrep`):

- `price_total_from_execution_dto(dto)` — reads `priceTotal` from the first
successful row in `dto["quotationResult"]["successfulQuotations"]`, or
returns `None`.

::: src.drug_discovery.execution_helpers
::: src.drug_discovery.konnektor
options:
docstring_style: google
show_root_heading: false
Expand Down
37 changes: 34 additions & 3 deletions docs/dd/ref/rbfe.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,38 @@

Relative binding free energy (RBFE) in the drug discovery SDK is supported through:

- `SystemPrep` in RBFE mode — pass `ligand1` and `ligand2` instead of a single `ligand`. See the [RBFE tutorial](../tutorial/rbfe.md).
- Platform tool `deeporigin.rbfe-end-to-end` for end-to-end pairwise RBFE runs. Start executions via the [Platform executions API](../../platform/ref/executions.md) using prepared system outputs from `SystemPrep.run()`.
- **`RBFE`** — batch workflow on platform tool `deeporigin.rbfe` (`steps`: `["konnektor", "system-prep", "rbfe"]`, `["system-prep", "rbfe"]`, or `["rbfe"]`). Up to 20 ligand pairs per execution. See the [RBFE tutorial](../tutorial/rbfe.md).
- **`SystemPrep`** in RBFE mode — single-pair sync prep via `deeporigin.system-prep` (pass `ligand1` and `ligand2`). Useful for one-off prep or when you want fine-grained control before submitting `RBFE(prepared_systems=[...])`.

There is no `deeporigin.drug_discovery.rbfe` module in the SDK.
## Steps

Exactly one of `ligands`, `pairs`, or `prepared_systems` must be provided.

| Steps | Input | Output |
|------|-------|--------|
| `["konnektor", "system-prep", "rbfe"]` | Shared `protein` + `ligands[]` + `network_type` + FEP params | Konnektor edges, then `system` and `result` records |
| `["system-prep", "rbfe"]` | Shared `protein` + `pairs[]` + FEP params | `system` then `result` records |
| `["rbfe"]` | `prepared_systems[]` + FEP params | `result` records |

For Konnektor mode, each ligand must be synced and registered (platform `id` and
`file_path` required). Use `SystemPrep` for single-pair prep without FEP.

Start executions via `RBFE.start()` or the [Platform executions API](../../platform/ref/executions.md).

Rehydrate a submitted run with `RBFE.from_id(execution_id)`, `RBFE.from_last_run()`, or `RBFE.from_dto(dto)` to refresh status, watch progress in notebooks, or inspect stored inputs.

After an RBFE leg completes, `RBFE.get_results()` returns a summary DataFrame with `protein_id`, `ligand1_id`, `ligand2_id`, and `ddG` (free-energy difference from `total` with `unit`, e.g. `-3875.483 kcal/mol`).

## Prepared systems

`RBFE.get_prepared_system(ligand1_id=..., ligand2_id=...)` loads a `PreparedSystem` from system-prep result rows scoped to this execution (via `PreparedSystem.from_result`). Optional ligand IDs filter to a specific pair; when omitted or when multiple rows match, the first result is returned. No execution status check is required — if system-prep rows are not available yet, a `DeepOriginException` is raised.

Visualize the returned object in a notebook:

```{.python notest}
ps = rbfe.get_prepared_system(ligand1_id=ligand1.id, ligand2_id=ligand2.id)
ps.show()
ps.show(solute=True) # solute-only PDB when available
```

This is separate from `RBFE.get_results()`, which reads `deeporigin.rbfe` ΔΔG summary rows rather than prepared-system outputs.
7 changes: 7 additions & 0 deletions docs/dd/tools/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ the platform. This is useful when you want to inspect a previous run, reconnect
to an in-progress execution, or fetch results in a later session.

```{.python notest}
# By execution id:
tool = SomeTool.from_id("<executionId>")

# Or resume the most recently created run of this tool type:
tool = SomeTool.from_last_run()

tool.sync()
result = tool.get_results()
```
Expand All @@ -72,6 +77,8 @@ The commonly available methods are:
- `cancel()` cancels an asynchronous execution, when supported.
- `get_results()` retrieves outputs after completion.
- `from_id()` reconstructs a tool object from an execution ID.
- `from_last_run()` reconstructs a tool object from the most recently created
execution of that tool type.

Not every method is available on every tool. The tool-specific pages document
the supported execution modes, inputs, outputs, and examples.
65 changes: 38 additions & 27 deletions docs/dd/tutorial/abfe.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# ABFE

This document describes how to run a [ABFE :octicons-link-external-16:](https://en.wikipedia.org/wiki/Free-energy_perturbation) simulation using Deep Origin tools.
This document describes how to run an [ABFE :octicons-link-external-16:](https://en.wikipedia.org/wiki/Free-energy_perturbation) simulation using Deep Origin tools.

The `ABFE` class drives platform tool `deeporigin.abfe-end-to-end` with ordered workflow
`steps`:

- `["system-prep", "abfe"]` — protein + ligand through system prep, then FEP (default)
- `["abfe"]` — FEP only on an existing `PreparedSystem`

## Prerequisites

We assume that you have prepared a protein, docked a ligand to it, and obtained a pose that you want to proceed with.
We assume that you have prepared a protein, docked a ligand to it, and obtained a pose that you want to proceed with.

In this tutorial we will use a protein and ligand from the example dataset.
In this tutorial we will use a protein and ligand from the example dataset.

```{.python notest}
from deeporigin.drug_discovery import (
ABFE,
SystemPrep,
PreparedSystem,
ABFEParams,
BRD_DATA_DIR,
Protein,
Expand All @@ -28,39 +32,45 @@ ligand.sync()

For more details on how to get started, see [:material-page-previous: Getting Started ](./getting-started.md).

## Combined workflow (recommended)

## System Preparation
Pass `protein` and `ligand` to run system preparation and ABFE in one execution:

Before ABFE, you must turn your protein and docked ligand into a simulation-ready
systems. This step is called *system preparation*.

For a single ligand (i.e., ABFE), system prep builds two solvated models:
```{.python notest}
abfe = ABFE(protein=protein, ligand=ligand)
abfe.start(quote=True)
abfe.estimate
```

1. **Binding system** — protein and ligand assembled in an explicit water box with
ions. This is the complex used for the binding leg of ABFE.
2. **Ligand solvation system** — the same ligand alone in solvent, used for the
solvation leg.
After quoting, confirm and watch progress as shown below. When the system-prep
step completes, you can load the prepared system from the same execution:

Along the way, Deep Origin System Prep typically:
```{.python notest}
prepared = abfe.get_prepared_system()
prepared.show()
```

- Cleans and standardizes the protein structure, optionally protonates it at
physiological pH, and assigns a protein force field (default Amber ff14SB).
- Parameterizes the ligand (hydrogens, charges, GAFF2 or OpenFF), then merges it
with the protein into a complex.
- Solvates each system (water box padding, salt, optional retention of crystal
waters).
## Two-step alternative (SystemPrep)

You can still prepare the system separately with `SystemPrep`, then submit FEP-only
`steps=["abfe"]`:

```{.python notest}
sysprep = SystemPrep(
protein=protein,
ligand=ligand,
)
from deeporigin.drug_discovery import SystemPrep, PreparedSystem

sysprep = SystemPrep(protein=protein, ligand=ligand)
system = sysprep.run()
system.show()

abfe = ABFE(prepared_system=system)
abfe.start(quote=True)
abfe.estimate
```

System prep builds two solvated models:

1. **Binding system** — protein and ligand in explicit solvent (binding leg).
2. **Ligand solvation system** — ligand alone in solvent (solvation leg).

You will see something like:

Expand All @@ -74,10 +84,11 @@ You will see something like:

## Estimating costs

Before starting a ABFE run, you can estimate costs using:
Before starting an ABFE run, you can estimate costs using `start(quote=True)` on
either workflow entry point (combined or two-step):

```{.python notest}
abfe = ABFE(prepared_system=system)
abfe = ABFE(protein=protein, ligand=ligand)
abfe.start(quote=True)
abfe.estimate
```
Expand Down
51 changes: 38 additions & 13 deletions docs/dd/tutorial/rbfe.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,50 @@ prepared.show()
```

The returned `PreparedSystem` includes paths to binding and solvation XML files
and a system PDB. Use these artifacts with the platform RBFE end-to-end tool
(`deeporigin.rbfe-end-to-end`); see
[:material-page-previous: Platform executions](../../platform/ref/executions.md).
and a system PDB. Submit batch RBFE with the `RBFE` class and platform tool
`deeporigin.rbfe`:

## Constructing a network
```{.python notest}
from deeporigin.drug_discovery import RBFE, RBFEParams

# End-to-end: prep + FEP for one pair (add more pairs to the list for networks)
rbfe = RBFE(
protein=protein,
pairs=[(ligand1, ligand2)],
params=RBFEParams(test_run=1),
)
rbfe.start()
```

!!! tip "Constructing a network"
View the documentation for `LigandSet` to learn how to
[construct a network](../how-to/ligands.md#constructing-a-network-using-konnektor).
For FEP on existing prepared systems, pass `prepared_systems=[prepared, ...]`
(`steps` is inferred as `["rbfe"]`). For single-pair prep without FEP, use
`SystemPrep` instead of `RBFE`.
See [:material-page-previous: Platform executions](../../platform/ref/executions.md).

For a congeneric series, map edges between ligands before scheduling pairwise
RBFE calculations:
## Constructing a network

For a congeneric series, submit the full ligand set and let the workflow run
Konnektor to plan pairwise edges, then system-prep and RBFE for each edge:

```{.python notest}
from deeporigin.drug_discovery import LigandSet

ligands = LigandSet.from_dir(BRD_DATA_DIR)
ligands.map_network().show_network()
ligand_set = LigandSet.from_dir(BRD_DATA_DIR)
for ligand in ligand_set:
ligand.sync()

rbfe = RBFE(
protein=protein,
ligands=ligand_set,
network_type="mst",
params=RBFEParams(test_run=1),
)
rbfe.start()
```

This stores the network on the ligand set and renders an interactive graph in
Jupyter.
See the [RBFE many-ligands workflow notebook](../../notebooks/clean/rbfe-5-many-ligands-workflow.ipynb)
for an end-to-end example on dev.

To preview a network interactively in Jupyter before submitting, use
`Konnektor(ligands=...).run()` and call `.show_network()` on the result — see
[constructing a network](../how-to/ligands.md#constructing-a-network-using-konnektor).
Loading
Loading