Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
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
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
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.
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/dirty/rbfe-5-many-ligands-workflow.ipynb)
for an end-to-end example on dev.
Comment thread
sg-s marked this conversation as resolved.
Outdated

To preview a network interactively in Jupyter before submitting, use
`LigandSet.map_network().show_network()` — see
[constructing a network](../how-to/ligands.md#constructing-a-network-using-konnektor).
28 changes: 27 additions & 1 deletion docs/dev/mock-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,33 @@ To run the mock server standalone for local development:
python tests/run_mock_server.py [PORT]
```

Where `PORT` is the port number to run the server on (default: 8000).
Where `PORT` is the port number to run the server on (default: 4931 via `make mock-server`).

Optional flags:

```bash
uv run python -m tests.run_mock_server --port 4931 --abfe-duration 30 --rbfe-duration 5
```

## RBFE notebook (local)

The [RBFE single-pair notebook](../notebooks/dirty/rbfe-1-single-pair.ipynb) runs against the mock when `DO_ENV=local` and the server is up:

Comment thread
sg-s marked this conversation as resolved.
Outdated
```bash
make mock-server # port 4931
```

Set `DO_ENV=local` in `.env`, then open the notebook. Fixtures are under:

| Path | Purpose |
|------|---------|
| `tests/fixtures/executions/a5484958-059f-4b1b-ba2c-664adf23e8e8.json` | Preloaded succeeded RBFE execution (`RBFE.from_id`) |
| `tests/fixtures/result-explorer-rbfe-a5484958.json` | Result-explorer rows for that job |
| `tests/fixtures/deeporigin.rbfe/quotation-result.json` | Quote response for `deeporigin.rbfe` |
| `tests/fixtures/tool-runs/deeporigin.rbfe/result-template.json` | Injected ΔΔG row after confirm/watch |
| `tests/fixtures/tool-runs/deeporigin.system-prep/run-rbfe.json` | RBFE-mode system-prep (`ligand1` + `ligand2`) |

Integration coverage: `tests/test_rbfe_local.py` (`uv run pytest tests/test_rbfe_local.py --env local`).

## How Tool Executions Work

Expand Down
2 changes: 1 addition & 1 deletion docs/notebook_watch_mixin.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Notebook watch (ABFE and other async executions)

`NotebookWatchMixin` adds `watch()`, `stop_watching()`, and `show()` for live HTML updates in Jupyter while polling the platform. Executions rehydrated with `from_id` / `from_dto` get the same watch-related instance state as objects constructed with `__init__`. The HTML view is built with [`ExecutionDisplay`](platform/ref/execution_display.md) (Bootstrap card: progress bar from `progressReport.complete`, execution id, name, status). It does **not** use `nest_asyncio`.
`NotebookWatchMixin` adds `watch()`, `stop_watching()`, and `show()` for live HTML updates in Jupyter while polling the platform. Executions rehydrated with `from_id` / `from_dto` get the same watch-related instance state as objects constructed with `__init__`. The HTML view is built with [`ExecutionDisplay`](platform/ref/execution_display.md) (Bootstrap card with execution id, name, status, and progress). When the tools API returns a v2 `progressReport` tree, the card body shows an indented HTML/SVG step tree with per-node status colors and optional completion rings; legacy flat `complete` shapes still use the Bootstrap progress bar. It does **not** use `nest_asyncio`.

- **Non-blocking cell (default):** `task = await abfe.watch()` — the cell returns immediately; the widget keeps updating while you run other cells.
- **Block until the job finishes (live widget):** `await abfe.watch(blocking=True)` or set `JOB_WATCH_BLOCK=1` (also `true`, `yes`, `on`; case-insensitive). Used by doc notebook CI (`scripts/build_docs.sh`) and `nbconvert --execute`.
Expand Down
Loading
Loading