Skip to content

small_molecule_binding: replace AF2 with Boltz-2 co-folding, port to Delta - #62

Open
drawadiagram wants to merge 1 commit into
update/core-manager-0926from
update/smallmol-boltz-0926
Open

small_molecule_binding: replace AF2 with Boltz-2 co-folding, port to Delta#62
drawadiagram wants to merge 1 commit into
update/core-manager-0926from
update/smallmol-boltz-0926

Conversation

@drawadiagram

Copy link
Copy Markdown
Contributor

Splits the small-molecule workflow out of #59. Third of four.

Based on #60 (needs find_gpus and IMPRESS_SESSION_DIR); GitHub retargets this to main when #60 merges. #63 stacks on this one — the guided-RFD3 fix series is split out separately so this PR stays reviewable.

The cut point is the merge commit where the Boltz-2 migration and the Delta portability work met, before the guided-RFD3 fixes began. Everything here is that first half.

Fold prediction: AlphaFold2 → Boltz-2 co-folding

STEP_AF2 keeps its name for compatibility, but the step now co-folds the protein together with the ligand (supplied as SMILES) and reports ligand_iptm — a protein-ligand interface confidence AF2 could never provide, since it never folded the ligand at all. AF2 here ran in single-sequence mode with zero ligand awareness, so this is a real capability upgrade rather than a swap.

The new fold_min_ligand_iptm gate defaults to None in PROD so the switch doesn't silently tighten production thresholds. scripts/af2.shscripts/boltz.sh, which holds the CCD cache lock across a completeness check so concurrent tasks can't read a half-extracted mols/ (the same race later ported to the protein workflow in #61).

Ligand SMILES

A Rosetta .params file contains no SMILES, so scripts/derive_ligand_smiles.py derives one offline via RDKit bond-order perception from the params connectivity plus a reference structure's 3D coordinates. Output committed as p{1..8}_in/ALR.smiles.

RFD3

Drops the scaffoldguided.* CLI argument: RFD3 has no such namespace (unlike older RFDiffusion versions) and guidance lives entirely inside the InputSpecification JSON, so the argument was silently inert. Also sets PYTHONNOUSERSITE and clears PYTHONPATH/PYTHONUSERBASE so the host's ~/.local can't shadow packages inside the container.

⚠️ Worth a close look

filter_shape.py changes the RosettaScripts ScoreTermValueBased score_fxn from sfxn to sfxn_clean. That is a scoring change sitting inside what otherwise reads as a sys.argvargparse refactor. Calling it out so it doesn't slip through as cleanup.

Configuration and retries

The loose module-level threshold constants become a RunConfig dataclass with PROD and TEST instances selected by IMPRESS_TEST_MODE; backend chosen by IMPRESS_BACKEND (dragon|local); GPUs assigned round-robin from find_gpus().

_stage_metrics_improving() gives the fastrelax and interface stages a metric-agnostic "is this retry actually helping" check, so an attempt whose every still-failing metric stayed flat or regressed short-circuits instead of burning the task budget.

Portability and hygiene

Every scripts/*.sh re-activates $VIRTUAL_ENV instead of a hardcoded /anvil path; mpnn_run.py restores the numpy aliases NumPy 1.24 removed but LigandMPNN's bundled openfold still uses; packmin.py/fastrelax.py use pyrosetta.rosetta.* imports and mute Rosetta's tracer.

Adds delta_env_setup.sh, delta_gpu_run.sh, pull_foundry.sh, and scripts/validate_run.py (post-run output-tree validator).

@AymenFJA — the --mail-user address you flagged on the protein-binding script was still present in this workflow's delta_gpu_run.sh; it's a <your e-mail> placeholder here now. One more remains in examples/discontinuous_scaffolds/rfd3_benchmark/run_islands.slurm:10, pre-existing on main and untouched by any of these four PRs — worth a separate cleanup.

Replaces part of #59.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Lo8DwSbyvdWZRkkkka6gA2

…Delta

Small-molecule workflow changes extracted from the impress_fixes branch,
up to the point where the guided-RFD3 fix series begins. Depends on the
ImpressManager/find_gpus changes in the core commit.

Fold prediction: AlphaFold2 is replaced by Boltz-2. The STEP_AF2 constant
keeps its name for compatibility, but the step now co-folds the protein
together with the ligand (supplied as SMILES) and reports ligand_iptm, a
protein-ligand interface confidence AF2 could not provide since it never
folded the ligand at all. The new fold_min_ligand_iptm gate defaults to
None in PROD so the switch does not silently tighten production
thresholds. scripts/af2.sh is replaced by scripts/boltz.sh, which holds
the CCD cache lock across a completeness check so concurrent tasks cannot
read a half-extracted mols/ directory.

Ligand SMILES: a Rosetta .params file contains no SMILES, so
scripts/derive_ligand_smiles.py derives one offline via RDKit bond-order
perception from the params connectivity plus a reference structure's 3D
coordinates. Its output is committed as p{1..8}_in/ALR.smiles.

RFD3: drop the scaffoldguided.* CLI argument. RFD3 has no such namespace
(unlike older RFDiffusion versions) and guidance is expressed entirely
inside the InputSpecification JSON, so the argument was silently inert.
Also set PYTHONNOUSERSITE and clear PYTHONPATH/PYTHONUSERBASE so the
host's ~/.local cannot shadow packages inside the container.

Configuration: the loose module-level threshold constants become a
RunConfig dataclass with PROD and TEST instances, selected by
IMPRESS_TEST_MODE, and the backend is chosen by IMPRESS_BACKEND
(dragon|local). GPUs are assigned round-robin from find_gpus().

Retry logic: _stage_metrics_improving() gives the fastrelax and interface
stages a metric-agnostic "is this retry actually helping" check, so an
attempt whose every still-failing metric stayed flat or regressed
short-circuits instead of burning the task budget.

Portability and hygiene: every scripts/*.sh re-activates $VIRTUAL_ENV
instead of sourcing a hardcoded /anvil path; mpnn_run.py restores the
numpy aliases NumPy 1.24 removed but LigandMPNN's bundled openfold still
uses; filter_shape.py moves to argparse; packmin.py and fastrelax.py use
pyrosetta.rosetta.* imports and mute Rosetta's tracer output.

Note for review: filter_shape.py also changes the RosettaScripts
ScoreTermValueBased score_fxn from "sfxn" to "sfxn_clean". That is a
scoring change, not part of the argparse refactor.

Adds delta_env_setup.sh, delta_gpu_run.sh, pull_foundry.sh, and
scripts/validate_run.py (post-run output-tree validator).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lo8DwSbyvdWZRkkkka6gA2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant