Metadata-Version: 2.5
Name: caddforge-docking
Version: 0.7.0
Summary: Molecular docking workflows for the CADDForge toolbox.
Author-email: Manuel Sellner <manuel.sellner@idorsia.com>, Christoph Sager <christoph.sager@idorsia.com>
License: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: caddforge-core>=0.21.0
Requires-Dist: caddforge-unidock-tools==1.1.3
Requires-Dist: pdb4amber>=1.4.1
Requires-Dist: plumed>=2.10.0
Requires-Dist: pyocl-idor>=0.8.3
Requires-Dist: rdkit>=2022.9.5
Provides-Extra: gui
Requires-Dist: caddforge-gui>=0.2.0; extra == 'gui'
Requires-Dist: fastapi>=0.110; extra == 'gui'
Requires-Dist: python-multipart>=0.0.21; extra == 'gui'
Description-Content-Type: text/markdown

# CADDForge Docking Plugin

Install this plugin with `python -m pip install caddforge-docking`. It depends directly
on `caddforge-core>=0.21.0`; Python imports and CLI commands still use `caddforge`.
For the complete public toolbox, including user-facing extras, install
`python -m pip install caddforge`. When migrating an existing environment, uninstall
the former `caddforge` core distribution before installing renamed core and updated plugins.

`caddforge-docking` provides docking workflows as plugins for the CADDForge framework.

## Optional GUI dependencies
The core docking workflows can be installed without GUI dependencies.

If you want to use the Docking GUI extension, install the optional GUI extra:
```bash
pip install "caddforge-docking[gui]"
```

GUI tip for large shared inputs:
- In file inputs, choose `Use server path` when the backend host can access the same filesystem path directly (for example shared `/mnt/...` data or Slurm env packs). This skips upload/copy and avoids long submit times for large files.

## Implemented Tools
- [`unidock`](#tool-unidock)
- [`idockya`](#tool-idockya)
- [`gnina`](#tool-gnina)

## Tool: `unidock`

### What it does
The `unidock` tool runs GPU-accelerated molecular docking with Uni-Dock through the standard CADDForge workflow/job interface. It supports:
- receptor input as `.pdbqt`, or `.pdb` with automatic receptor preparation
- docking one ligand, an index of ligands, or SDF input
- iterative batch processing for multi-structure SDF input (`batch_size`)
- automatic pocket center detection from a reference ligand (`.pdb`, `.pdbqt`, `.sdf`)
- standardized CADDForge outputs (`results.json`, `best_scores.csv`, `result_record.json`)

### External dependencies
These tools are required and are not installed automatically by this Python package:
- `unidock` (Uni-Dock CLI): <https://github.com/dptech-corp/Uni-Dock>

Notes:
- If receptor input is `.pdb`, the workflow also calls `unidocktools proteinprep` to create `.pdbqt`.

### CLI usage
```bash
caddforge run docking unidock --config unidock.yaml
```

### Python API usage
```python
from caddforge.core.execution import load_result_for_job, submit_workflow
from caddforge.plugins import get_tool

spec = get_tool("docking", "unidock")
cfg = spec.config_cls(
    receptor_path="protein.pdbqt",
    ligand_index_path="ligands.index",
    center_x=-19.18838,
    center_y=1.76425,
    center_z=9.23822,
    size_x=20.0,
    size_y=20.0,
    size_z=20.0,
    search_mode="balance",
    backend="local",  # or "slurm"
)

workflow = spec.workflow_cls(cfg)
job = submit_workflow(workflow, cfg, backend_name=cfg.backend)
result = load_result_for_job(job)
if result is not None:
    print(result.status.value, result.metrics)
```

### Example config
```yaml
receptor_path: protein.pdbqt
ligand_index_path: ligands.index
center_x: -19.18838
center_y: 1.76425
center_z: 9.23822
size_x: 20
size_y: 20
size_z: 20
search_mode: fast
```

### Tool-specific config options
Only one ligand source must be set: `ligand_path` or `ligand_index_path` or `ligand_multisdf_path`.

#### Required / primary inputs
- `receptor_path` (`Path`): Receptor file (`.pdb` or `.pdbqt`).
- `ligand_path` (`Path | None`): Single ligand input (`.pdbqt` or `.sdf`).
- `ligand_index_path` (`Path | None`): Path to ligand index file (text file with one absolute or relative ligand file path per line; supported ligand files are `.pdbqt` or single-structure `.sdf`).
- `ligand_multisdf_path` (`Path | None`): Multi-structure SDF ligand input (recommended for batch processing).

Ligand index file example (`ligands.index`):
```text
/data/ligands/ligand_0001.sdf
/data/ligands/ligand_0002.sdf
/data/ligands/ligand_0003.sdf
```

#### Optional receptor / pocket inputs
- `flex_path` (`Path | None`): Optional flexible sidechain file (`.pdb` or `.pdbqt`).
- `reference_ligand_path` (`Path | None`): Optional ligand to infer docking center from center of geometry (`.pdb`, `.pdbqt`, `.sdf`).
- `center_x` (`float | None`): Box center X.
- `center_y` (`float | None`): Box center Y.
- `center_z` (`float | None`): Box center Z.
- `size_x` (`float`, default `20.0`): Box size X.
- `size_y` (`float`, default `20.0`): Box size Y.
- `size_z` (`float`, default `20.0`): Box size Z.

Notes:
- If `center_x/y/z` are not all provided, `reference_ligand_path` is required.
- `proteinprep_center_x/y/z` and `proteinprep_size_x/y/z` exist in the current config model for compatibility, but are not used with the current minimal `unidocktools proteinprep -r ... -o ...` interface.
- Ligand input intent:
  - Use `ligand_path` for a single ligand file (`.pdbqt` or `.sdf`).
  - Use `ligand_multisdf_path` for multi-structure SDF files.
  - Use `ligand_index_path` when you already have ligands split into one-file-per-ligand and want explicit file-level control.

#### Batch handling options
- `batch_size` (`int | None`): When set with `ligand_multisdf_path`, process multi-structure SDF in iterative batches.
- `run_ligandprep` (`bool`, default `false`): If enabled, run `unidocktools ligandprep` before docking and use prepared ligands as UniDock input.
- `ligandprep_batch_size` (`int`, default `10000`): Batch size passed to `unidocktools ligandprep -bs` when ligand preparation is enabled.
- `ligandprep_timeout_seconds` (`int`, default `3600`): Maximum allowed runtime for one `unidocktools ligandprep` call; timed-out prep is terminated and the job fails fast.
- `max_pending_postprocess_batches` (`int`, default `2`): Upper bound of completed batches waiting for async post-processing; controls overlap vs temporary disk usage.

Batch behavior:
1. Split each batch into single-structure SDF files.
2. Create an index for that batch only.
3. Run UniDock for that batch.
4. Remove temporary files for that batch (unless `keep_temporary_files: true`).

Ligand preparation behavior (`run_ligandprep: true`):
- CADDForge runs `unidocktools ligandprep` automatically and docks prepared SDF outputs.
- If the installed `unidocktools` version does not support `ligandprep`, the job fails fast with a clear error.
- If one `ligandprep` call exceeds `ligandprep_timeout_seconds`, CADDForge terminates it and fails fast (prevents indefinite hangs).

#### UniDock runtime/scoring options
- `scoring` (`"ad4" | "vina" | "vinardo"`, default `"vina"`): Scoring function.
- `search_mode` (`"fast" | "balance" | "detail"`, default `"balance"`): UniDock search mode.
- `cpu` (`int`, default `0`): CPU count passed to UniDock.
- `seed` (`int`, default `0`): Random seed.
- `exhaustiveness` (`int`, default `384`): Search exhaustiveness.
- `max_evals` (`int`, default `0`): Max evaluations.
- `num_modes` (`int`, default `9`): Max number of output modes.
- `min_rmsd` (`float`, default `1.0`): Minimum RMSD between output poses.
- `energy_range` (`float`, default `3.0`): Maximum energy range from best mode.
- `spacing` (`float`, default `0.375`): Grid spacing.
- `verbosity` (`int`, default `1`): UniDock verbosity (0/1/2).
- `max_step` (`int`, default `0`): Max steps per MC run.
- `refine_step` (`int`, default `3`): Refinement steps.
- `max_gpu_memory` (`int`, default `0`): GPU memory limit (0 = auto/all available).

#### Output / execution extras
- `output_dir_name` (`str`, default `"docked_out"`): Pose output directory name under `results/`.
- `prepared_receptor_filename` (`str`, default `"protein_prepared.pdbqt"`): Filename for generated prepared receptor.
- `keep_temporary_files` (`bool`, default `false`): Keep temporary split/index files.
- `extra_unidock_args` (`list[str]`, default `[]`): Extra raw CLI args appended to `unidock` (for non-core options only; core options like `--max_gpu_memory`, `--search_mode`, etc. should be set via dedicated config fields).

### Outputs
For each run, artifacts are written under `runs/<date>/<job-id>/`:
- `results/<output_dir_name>/`: UniDock pose files (`<ligand>_out.sdf`, etc.)
- `results/results.json`: summary payload with per-ligand best score
- `results/best_scores.csv`: per-ligand best score table
- `results/result_record.json`: standardized CADDForge `Result`
- `stdout.log` / `stderr.log`: command logs

## Tool: `idockya`

### What it does
The `idockya` tool runs docking with OpenChemLib iDockYa through `pyocl`, supplied
by `pyocl-idor>=0.8.3`. Java 21 or newer is required; set `JAVA_HOME` to that runtime.
It supports:
- receptor and native ligand input from standard structure files
- ligand input as one file (`ligand_path`) or many files (`ligand_paths`)
- multi-structure SDF processing from `ligand_path` (record-by-record streaming)
- optional parallel ligand docking with per-worker `DockingEngine` reuse
- standardized CADDForge outputs (`results.json`, `best_scores.csv`, `result_record.json`)

Supported input formats:
- `.sdf`, `.mol`, `.mol2`, `.pdb`, `.pdbqt`, `.smi`, `.smiles`

Notes:
- For receptor/native ligand SDF input, the first SDF record is used.
- For ligand SDF input (`ligand_path`), all records are docked.

### CLI usage
```bash
caddforge run docking idockya --config idockya.yaml
```

### Python API usage
```python
from caddforge.core.execution import load_result_for_job, submit_workflow
from caddforge.plugins import get_tool

spec = get_tool("docking", "idockya")
cfg = spec.config_cls(
    receptor_path="receptor.sdf",
    native_ligand_path="native_ligand.sdf",
    ligand_path="ligands.sdf",  # can be multi-structure SDF
    output_format="sdf",
    num_workers=0,  # auto (uses SLURM_CPUS_PER_TASK if set)
    backend="local",  # or "slurm"
)

workflow = spec.workflow_cls(cfg)
job = submit_workflow(workflow, cfg, backend_name=cfg.backend)
result = load_result_for_job(job)
if result is not None:
    print(result.status.value, result.metrics)
```

### Example config
```yaml
receptor_path: receptor.sdf
native_ligand_path: native_ligand.sdf
ligand_path: ligands.sdf
output_format: sdf
output_dir_name: docked_out
num_workers: 0
max_inflight_tasks: 0
```

### Tool-specific config options

#### Required / primary inputs
- `receptor_path` (`Path`): Receptor structure input.
- `native_ligand_path` (`Path`): Native/reference ligand structure input.
- `ligand_path` (`Path | None`): Single ligand file path (can be multi-record SDF).
- `ligand_paths` (`list[Path]`): Multiple ligand file paths.

Only one ligand source must be set:
- `ligand_path` or `ligand_paths`

#### Output / execution options
- `output_dir_name` (`str`, default `docked_out`): Pose output directory under `results/`.
- `output_format` (`"sdf" | "pdb" | "mol2"`, default `sdf`): Primary pose output format.
- `grid_dimension` (`float | None`): Optional iDockYa grid dimension override.

#### Parallelism options
- `num_workers` (`int`, default `0`): Worker processes for ligand docking.
  `0` => auto-detect (`SLURM_CPUS_PER_TASK` if available, else local CPU count).
- `max_inflight_tasks` (`int`, default `0`): Max queued/running ligand tasks not yet collected.
  `0` => `4 * num_workers`.

Performance behavior:
- In parallel mode, each worker initializes one `DockingEngine` and reuses it.
- Ligand input is streamed; no full multi-structure SDF is loaded into RAM.
- Scores are written incrementally to CSV to keep memory usage bounded.

### Outputs
For each run, artifacts are written under `runs/<date>/<job-id>/`:
- `results/<output_dir_name>/`: per-ligand docked poses (primary `pose_file` uses `output_format`; SDF is also produced internally for compatibility)
- `results/results.json`: summary payload (`ligands_total`, `best_score_overall`, `best_scores_csv`, and `ligands_preview`)
- `results/best_scores.csv`: per-ligand score table
- `results/result_record.json`: standardized CADDForge `Result`
- `stdout.log` / `stderr.log`: run logs

## Tool: `gnina`

### What it does
The `gnina` tool runs docking with the `gnina` executable through the standard CADDForge workflow/job interface. It supports:
- receptor input as `.pdbqt` or `.pdb`
- ligand input as one file or a list of files
- SDF input with automatic per-record staging so each ligand gets a dedicated output pose file
- manual docking boxes or gnina autoboxing
- flexible docking through `--flex`, `--flexres`, or `--flexdist`
- standardized CADDForge outputs (`results.json`, `best_scores.csv`, `result_record.json`)

### External dependencies
These tools are required and are not installed automatically by this Python package:
- `gnina` executable: <https://github.com/gnina/gnina>

### CLI usage
```bash
caddforge run docking gnina --config gnina.yaml
```

### Python API usage
```python
from caddforge.core.execution import load_result_for_job, submit_workflow
from caddforge.plugins import get_tool

spec = get_tool("docking", "gnina")
cfg = spec.config_cls(
    receptor_path="protein.pdb",
    ligand_path="ligands.sdf",
    autobox_ligand_path="reference_ligand.sdf",
    flexres=["A:194", "A:244", "A:252"],
    no_gpu=True,
    backend="local",  # or "slurm"
)

workflow = spec.workflow_cls(cfg)
job = submit_workflow(workflow, cfg, backend_name=cfg.backend)
result = load_result_for_job(job)
if result is not None:
    print(result.status.value, result.metrics)
```

### Example config
```yaml
receptor_path: protein.pdb
ligand_path: ligands.sdf
autobox_ligand_path: reference_ligand.sdf
flexres:
  - A:194
  - A:244
  - A:252
scoring: dkoes_fast
cnn_scoring: rescore
no_gpu: true
```

### Tool-specific config options

#### Required / primary inputs
- `receptor_path` (`Path`): Rigid receptor input (`.pdbqt` or `.pdb`). Flexible complex generation requires `.pdb` so receptor hydrogen/protonation states can be preserved from the input.
- `ligand_path` (`Path | None`): One ligand file. `.sdf` inputs may contain multiple records.
- `ligand_paths` (`list[Path]`): Alternative to `ligand_path` for docking multiple ligand files.

Only one ligand source must be set:
- `ligand_path` or `ligand_paths`

Supported ligand/autobox formats:
- `.sdf`, `.mol2`, `.pdbqt`, `.pdb`

#### Search space options
Choose exactly one search-space mode:

Manual box:
- `center_x`, `center_y`, `center_z`
- `size_x`, `size_y`, `size_z`

Autobox:
- `autobox_ligand_path`
- `autobox_add` (`float | None`)
- `autobox_extend` (`int | None`)

#### Flexible docking options
- `flex_path` (`Path | None`): Prebuilt flexible side-chain PDBQT passed via `--flex`.
- `flexres` (`list[str]`): Flexible residues, rendered as comma-separated `chain:resid`.
- `flexdist_ligand_path` (`Path | None`) and `flexdist` (`float | None`): Define flexible residues by distance from a ligand.
- `flex_limit` (`int | None`): Hard limit for flexible residues.
- `flex_max` (`int | None`): Keep at most the closest `flex_max` flexible residues.

Notes:
- `flex_path` and `flexres` are mutually exclusive.
- If flexibility is enabled and `write_flex_receptor_output: true`, the workflow writes per-ligand flexible receptor outputs under `results/flex_receptor_out/`.
- If flexibility, `write_flex_receptor_output`, and `write_flexible_complexes` are enabled, the workflow also writes one full protein-ligand complex PDB, one protein-only PDB, and one ligand-only SDF per generated pose. Protein and ligand hydrogen presence is copied from the input receptor and ligand records; missing input hydrogens are not invented. Ligand bond orders and formal charges are copied from the input ligand; PDB complexes emit ligand bond orders as `CONECT` records, whose interpretation depends on the downstream PDB reader.

#### Common gnina runtime/scoring options
- `scoring` (`dkoes_fast`, `ad4_scoring`, `dkoes_scoring`, `dkoes_scoring_old`, `vina`, `vinardo`): if omitted, CADDForge does not pass `--scoring` and gnina uses its own default.
- `cnn_scoring` (`none`, `rescore`, `refinement`, `metrorescore`, `metrorefine`, `all`): if omitted, CADDForge does not pass `--cnn_scoring` and gnina uses its own default.
- `cnn` (`str | None`): Built-in CNN model name.
- `cnn_model` (`Path | None`): External Torch model file.
- `score_only`, `local_only`, `minimize`, `randomize_only` (`bool`)
- `exhaustiveness` (`int | None`): if omitted, CADDForge does not pass `--exhaustiveness`.
- `num_modes` (`int | None`): if omitted, CADDForge does not pass `--num_modes`.
- `min_rmsd_filter` (`float | None`): if omitted, CADDForge does not pass `--min_rmsd_filter`.
- `cpu` (`int | None`): Explicit CPU count. If omitted, gnina auto-detects.
- `seed` (`int | None`)
- `add_hydrogens` (`on | off | None`): if omitted, CADDForge does not pass `--addH`.
- `device` (`int | None`)
- `no_gpu` (`bool | None`): if true, CADDForge passes `--no_gpu`; if omitted, the flag is not passed.
- `pose_sort_order` (`CNNscore | CNNaffinity | Energy | None`)

#### Output / execution extras
- `gnina_executable` (`str`, default `gnina`): Executable name or full path.
- `output_dir_name` (`str`, default `docked_out`)
- `flex_output_dir_name` (`str`, default `flex_receptor_out`)
- `flexible_complex_output_dir_name` (`str`, default `flexible_complexes`)
- `flexible_complex_ligand_resname` (`str`, default `LIG`)
- `gnina_log_dir_name` (`str`, default `gnina_logs`)
- `output_format` (`sdf | pdbqt`, default `sdf`)
- `write_flex_receptor_output` (`bool`, default `true`)
- `write_flexible_complexes` (`bool`, default `true`): Requires flexible docking, `write_flex_receptor_output: true`, `output_format: sdf`, and a PDB receptor. Set to `false` to keep only gnina's raw pose and flex output files.
- `keep_temporary_files` (`bool`, default `false`): On Slurm, temporary staged ligand files are created in `$SLURM_TMPDIR`; if this is `true`, they are copied back to `run_dir/staged_inputs` before cleanup.
- `log_sync_interval_seconds` (`int`, default `30`): Interval for resiliently copying live stdout, stderr, and the active per-ligand gnina log from Slurm scratch to the job directory.
- `result_sync_interval_seconds` (`int`, default `5`): Retry interval for asynchronously copying completed ligand artifacts from Slurm scratch to the job directory.
- `extra_gnina_args` (`list[str]`, default `[]`): Additional raw gnina CLI args for less-common options not modeled directly.

On Slurm, gnina runs inside `$SLURM_TMPDIR/caddforge_gnina_<job-id>`. Static inputs are staged once, completed ligand artifacts are copied back asynchronously, and transient copy failures remain queued while docking continues. After the last ligand, pending files receive one final copy attempt; the job fails rather than publishing an incomplete completed result if files still cannot be persisted.

### Outputs
For each run, artifacts are written under `runs/<date>/<job-id>/`:
- `results/<output_dir_name>/`: Per-ligand docked poses
- `results/<flex_output_dir_name>/`: Flexible receptor outputs when enabled
- `results/<flexible_complex_output_dir_name>/`: Per-pose complex PDBs, protein-only PDBs, and ligand-only SDFs when flexible complex generation is enabled
- `results/flexible_complexes_manifest.csv`: Flexible complex artifact provenance and hydrogen counts
- `results/<gnina_log_dir_name>/`: Per-ligand gnina log files
- `results/results.json`: Summary payload with ligand counts and best score
- `results/best_scores.csv`: Per-ligand best score table
- `results/result_record.json`: Standardized CADDForge `Result`
- `stdout.log` / `stderr.log`: Workflow command logs

Pipeline output aliases:
- `scores`: `best_scores.csv`
- `poses`: docked pose output directory
- `flexible_complexes_manifest`: flexible artifact manifest CSV, when generated
- `flexible_complexes`: per-pose complex PDB path collection, when generated
- `flexible_proteins`: per-pose protein-only PDB path collection, when generated
- `flexible_ligand_poses`: per-pose ligand-only SDF path collection, when generated

## Compressed inputs

Declared receptor, ligand, and reference inputs may use a trailing `.gz`, for example
`ligands.sdf.gz`; CADDForge supplies the docking tool with a plain file in runtime scratch. UniDock
ligand indexes may also reference `.sdf.gz` entries.

## Continuous integration and releases

`.github/workflows/release.yml` builds a wheel and source archive, validates
metadata, and tests the installed wheel on Linux with Python 3.10 and 3.12.
The lightweight test selection is recorded in `scripts/ci_tests.json`;
external scientific engines are validated separately. CI installs the same
wheel with its `[gui]` extra so GUI regression tests use the declared GUI
dependencies, including `caddforge-gui`.

Pushing a matching `v*` release tag publishes the tested artifacts to PyPI.
Branch pushes, pull requests and manual runs never publish. Configure a
PyPI Trusted Publisher for the `idorsia` repository, `release.yml` workflow
and `pypi` environment before pushing release tags. Runtime CADDForge
dependencies must already be available publicly; publish core and GUI before
FEP/docking, and publish docking/descriptors before MD.
