diff --git a/README.md b/README.md index 4f07fe1..9d1b8b2 100644 --- a/README.md +++ b/README.md @@ -204,26 +204,30 @@ Below are scripts for adding MMseqs2 MSAs and custom templates to AlphaFold3 inp ABCFold also includes a Boltz2 utility for scoring existing complex coordinates or fixed-receptor ligand poses without running Boltz diffusion sampling. See -[Boltz Existing-Structure Scoring](docs/boltz_existing_scoring.md) for +[Boltz Affinity Scoring](docs/boltz_affinity.md) for confidence scoring, affinity scoring, and `--reuse_trunk` examples. -After installation, use `boltz-score-existing` directly: +This is the fast Boltz path for already-built poses: it loads Boltz2 and runs +the confidence and optional affinity heads on supplied coordinates, but skips +the expensive diffusion structure-generation loop. + +After installation, use `boltz-affinity` directly: ```bash -boltz-score-existing poses.sdf --receptor receptor.pdb --affinity +boltz-affinity poses.sdf --receptor receptor.pdb --affinity ``` For a checkout managed with `uv`, either run through `uv`: ```bash -uv run boltz-score-existing poses.sdf --receptor receptor.pdb --affinity +uv run boltz-affinity poses.sdf --receptor receptor.pdb --affinity ``` or activate the project environment first: ```bash source .venv/bin/activate -boltz-score-existing poses.sdf --receptor receptor.pdb --affinity +boltz-affinity poses.sdf --receptor receptor.pdb --affinity ``` The module form @@ -235,26 +239,31 @@ checkouts. ABCFold also includes a Boltz-native docking wrapper for the case where a crystal receptor and pocket are known, but the ligand pose should be generated from SMILES by Boltz. See -[Boltz Crystal-Pocket Docking](docs/boltz_crystal_docking.md) for crystal +[Boltz Dock](docs/boltz_dock.md) for crystal template, pocket constraint, reference-ligand, and affinity examples. -After installation, use `boltz-dock-crystal` directly: +This mode is named `boltz-dock` because it generates a new ligand pose. It is +not as fast as `boltz-affinity`: Boltz diffusion still runs, but the receptor is +kept close to the provided crystal template and the ligand is steered into the +known pocket. + +After installation, use `boltz-dock` directly: ```bash -boltz-dock-crystal receptor.pdb "CCO" --pocket_residue A:145 --affinity +boltz-dock receptor.pdb "CCO" --pocket_residue A:145 --affinity ``` For a checkout managed with `uv`, either run through `uv`: ```bash -uv run boltz-dock-crystal receptor.pdb "CCO" --pocket_residue A:145 --affinity +uv run boltz-dock receptor.pdb "CCO" --pocket_residue A:145 --affinity ``` or activate the project environment first: ```bash source .venv/bin/activate -boltz-dock-crystal receptor.pdb "CCO" --pocket_residue A:145 --affinity +boltz-dock receptor.pdb "CCO" --pocket_residue A:145 --affinity ``` The module form diff --git a/abcfold/boltz/dock_crystal.py b/abcfold/boltz/dock_crystal.py index af2a70f..0163e7f 100644 --- a/abcfold/boltz/dock_crystal.py +++ b/abcfold/boltz/dock_crystal.py @@ -42,7 +42,7 @@ class DockingInput: def _parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser = argparse.ArgumentParser( - prog="boltz-dock-crystal", + prog="boltz-dock", description=( "Dock a ligand SMILES with Boltz while constraining the protein to " "a crystal receptor template and the ligand to a pocket." @@ -53,7 +53,7 @@ def _parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser.add_argument( "--out_dir", type=Path, - default=Path("boltz_crystal_docking"), + default=Path("boltz_dock"), help="Directory for the generated YAML and Boltz outputs.", ) parser.add_argument( @@ -530,7 +530,7 @@ def prepare_crystal_docking_input(args: argparse.Namespace) -> DockingInput: "--reference_ligand_chain." ) - yaml_path = out_dir / "boltz_crystal_dock.yaml" + yaml_path = out_dir / "boltz_dock.yaml" yaml_text = _render_yaml( receptor, protein_chains, @@ -542,7 +542,7 @@ def prepare_crystal_docking_input(args: argparse.Namespace) -> DockingInput: yaml_path.write_text(yaml_text) command = generate_boltz_crystal_dock_command(yaml_path, out_dir, args) - (out_dir / "boltz_crystal_dock_command.json").write_text( + (out_dir / "boltz_dock_command.json").write_text( json.dumps(command, indent=2) + "\n" ) return DockingInput(yaml_path=yaml_path, command=command, contacts=contacts) diff --git a/abcfold/boltz/score_existing.py b/abcfold/boltz/score_existing.py index 5ff949a..a94ee89 100644 --- a/abcfold/boltz/score_existing.py +++ b/abcfold/boltz/score_existing.py @@ -52,8 +52,11 @@ def _safe_id(path: Path) -> str: def _parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser = argparse.ArgumentParser( - prog="boltz-score-existing", - description="Score existing PDB/mmCIF complexes with Boltz2 confidence.", + prog="boltz-affinity", + description=( + "Score existing PDB/mmCIF complexes or fixed ligand poses with " + "Boltz2 confidence and optional affinity heads." + ), ) parser.add_argument( "structures", @@ -80,7 +83,7 @@ def _parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser.add_argument( "--out_dir", type=Path, - default=Path("boltz_existing_scores"), + default=Path("boltz_affinity_scores"), help="Directory for confidence JSON/NPZ outputs.", ) parser.add_argument( diff --git a/docs/boltz_existing_scoring.md b/docs/boltz_affinity.md similarity index 80% rename from docs/boltz_existing_scoring.md rename to docs/boltz_affinity.md index 3a9a69e..8331e2e 100644 --- a/docs/boltz_existing_scoring.md +++ b/docs/boltz_affinity.md @@ -1,9 +1,9 @@ -# Boltz Existing-Structure Scoring +# Boltz Affinity Scoring -`abcfold.boltz.score_existing` scores already-built complexes with Boltz2 -without running Boltz diffusion sampling. Use it when protein or complex -coordinates already exist and you want Boltz2 confidence and, optionally, -Boltz2 affinity estimates for those coordinates. +`boltz-affinity` scores already-built complexes with Boltz2 without running +Boltz diffusion sampling. Use it when protein or complex coordinates already +exist and you want Boltz2 confidence and, optionally, Boltz2 affinity estimates +for those coordinates. This is a scoring utility, not a structure-generation or local-minimization tool. It does not move the protein or ligand. @@ -13,20 +13,20 @@ tool. It does not move the protein or ligand. Installed ABCFold environments expose this as: ```bash -boltz-score-existing --help +boltz-affinity --help ``` For a local checkout managed with `uv`, use either: ```bash -uv run boltz-score-existing --help +uv run boltz-affinity --help ``` or activate the environment before using the command directly: ```bash source .venv/bin/activate -boltz-score-existing --help +boltz-affinity --help ``` The development-module equivalent is: @@ -68,9 +68,9 @@ Use this mode when each input file already contains the protein and ligand chains in one `.pdb`, `.cif`, or `.mmcif` file. ```bash -boltz-score-existing \ +boltz-affinity \ complex_1.cif complex_2.cif \ - --out_dir boltz_existing_scores \ + --out_dir boltz_affinity_scores \ --cache ~/.boltz \ --device cuda \ --no_download @@ -79,9 +79,9 @@ boltz-score-existing \ For affinity estimates on the same coordinates: ```bash -boltz-score-existing \ +boltz-affinity \ complex_1.cif complex_2.cif \ - --out_dir boltz_existing_scores_affinity \ + --out_dir boltz_affinity_scores \ --cache ~/.boltz \ --device cuda \ --no_download \ @@ -98,7 +98,7 @@ poses are stored as SDF files. This is the format used by DEKOIS2/Matcha-style and HEDGEHOG-style pose scoring. ```bash -boltz-score-existing \ +boltz-affinity \ poses.sdf \ --receptor receptor.pdb \ --out_dir boltz_pose_scores \ @@ -110,7 +110,7 @@ boltz-score-existing \ For confidence plus affinity: ```bash -boltz-score-existing \ +boltz-affinity \ poses.sdf \ --receptor receptor.pdb \ --out_dir boltz_pose_scores_affinity \ @@ -132,7 +132,7 @@ topology, for example multiple poses of the same ligand against the same protein. ```bash -boltz-score-existing \ +boltz-affinity \ same_ligand_poses.sdf \ --receptor receptor.pdb \ --out_dir boltz_pose_scores_reuse \ @@ -161,10 +161,15 @@ The output directory contains: ## Runtime Notes -The command avoids the expensive Boltz diffusion sampling path, so it is faster -than full Boltz structure prediction. It still loads the Boltz2 checkpoint and -runs the trunk, so the first score is not instantaneous. On GPU, scoring -additional poses in the same process is much cheaper than the cold start. +The command avoids the expensive Boltz diffusion sampling path, so it is much +faster than full Boltz structure prediction. It still loads the Boltz2 +checkpoint and runs the trunk, so the first score is not instantaneous. On GPU, +scoring additional poses in the same process is much cheaper than the cold +start, especially with `--reuse_trunk` for same-topology pose batches. + +In practice, this mode should be treated as Boltz scoring rather than Boltz +prediction: it can rank or annotate already generated poses, but it will not +repair geometry or move the ligand. The utility currently sets protein MSAs to `empty`, so proteins are scored in single-sequence mode. That is useful for fast pose screening, but confidence and diff --git a/docs/boltz_crystal_docking.md b/docs/boltz_dock.md similarity index 73% rename from docs/boltz_crystal_docking.md rename to docs/boltz_dock.md index aa43f7a..253047e 100644 --- a/docs/boltz_crystal_docking.md +++ b/docs/boltz_dock.md @@ -1,9 +1,9 @@ -# Boltz Crystal-Pocket Docking +# Boltz Dock -`abcfold.boltz.dock_crystal` runs Boltz structure generation with a fixed -crystal receptor as a template, a ligand SMILES, and pocket constraints. Use it -when you know the receptor structure and pocket, but want Boltz to generate the -ligand pose instead of only scoring an existing pose. +`boltz-dock` runs Boltz structure generation with a fixed crystal receptor as a +template, a ligand SMILES, and pocket constraints. Use it when you know the +receptor structure and pocket, but want Boltz to generate the ligand pose +instead of only scoring an existing pose. This is a Boltz-native docking/co-folding mode. It is not a classical force field minimizer: Boltz still runs diffusion sampling, but the protein is guided @@ -14,20 +14,20 @@ toward the crystal template and the ligand is guided into the pocket. Installed ABCFold environments expose this as: ```bash -boltz-dock-crystal --help +boltz-dock --help ``` For a local checkout managed with `uv`, use either: ```bash -uv run boltz-dock-crystal --help +uv run boltz-dock --help ``` or activate the environment before using the command directly: ```bash source .venv/bin/activate -boltz-dock-crystal --help +boltz-dock --help ``` The development-module equivalent is: @@ -39,14 +39,14 @@ python -m abcfold.boltz.dock_crystal --help ## Explicit Pocket Residues ```bash -boltz-dock-crystal \ +boltz-dock \ crystal_receptor.pdb \ "CCOc1ccc(...)" \ --protein_chain A \ --pocket_residue A:145 \ --pocket_residue A:146 \ --pocket_residue A:189 \ - --out_dir boltz_crystal_dock \ + --out_dir boltz_dock \ --affinity ``` @@ -61,13 +61,13 @@ If the receptor PDB still contains a reference ligand chain, the wrapper can infer pocket residues by distance: ```bash -boltz-dock-crystal \ +boltz-dock \ crystal_complex.pdb \ "CCOc1ccc(...)" \ --protein_chain A \ --reference_ligand_chain L \ --pocket_cutoff 6.0 \ - --out_dir boltz_crystal_dock \ + --out_dir boltz_dock \ --affinity ``` @@ -88,7 +88,7 @@ These settings keep the protein close to the crystal receptor and steer the ligand into the pocket. They can be relaxed: ```bash -boltz-dock-crystal \ +boltz-dock \ crystal_receptor.pdb \ "CCOc1ccc(...)" \ --pocket_residue A:145 \ @@ -102,8 +102,12 @@ less constrained. ## Accuracy and Runtime This mode runs Boltz diffusion, so it is much slower than -`abcfold.boltz.score_existing`, which only scores supplied coordinates. The -default docking settings use: +`boltz-affinity`, which only scores supplied coordinates. Compared with a fully +unconstrained Boltz run, `boltz-dock` saves setup work by reusing the provided +crystal receptor, writing `msa: empty` unless `--use_msa_server` is requested, +and constraining the search to the known pocket. It is still a generative Boltz +run, so runtime is controlled mainly by diffusion samples, recycling steps, and +sampling steps. The default docking settings use: - `--diffusion_samples 25` - `--recycling_steps 10` @@ -113,7 +117,7 @@ default docking settings use: For a quick dry run that only writes the Boltz YAML and command: ```bash -boltz-dock-crystal \ +boltz-dock \ crystal_receptor.pdb \ "CCOc1ccc(...)" \ --pocket_residue A:145 \ @@ -122,8 +126,8 @@ boltz-dock-crystal \ The output directory contains: -- `boltz_crystal_dock.yaml` -- `boltz_crystal_dock_command.json` +- `boltz_dock.yaml` +- `boltz_dock_command.json` - Boltz prediction outputs when `--dry_run` is not used Use `--use_msa_server` to let Boltz fetch MSAs. Without it, the wrapper writes diff --git a/pyproject.toml b/pyproject.toml index 1f20e46..c249c9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,8 +91,8 @@ abcfold = ["data/config.ini"] [project.scripts] abcfold = "abcfold.abcfold:main" -boltz-score-existing = "abcfold.boltz.score_existing:main" -boltz-dock-crystal = "abcfold.boltz.dock_crystal:main" +boltz-affinity = "abcfold.boltz.score_existing:main" +boltz-dock = "abcfold.boltz.dock_crystal:main" mmseqs2msa = "abcfold.scripts.add_mmseqs_msa:main" custom_templates = "abcfold.scripts.add_custom_template:main" ipsae = "abcfold.scripts.ipsae:main" diff --git a/tests/test_boltz_entrypoints.py b/tests/test_boltz_entrypoints.py index 9e620e9..98e95c2 100644 --- a/tests/test_boltz_entrypoints.py +++ b/tests/test_boltz_entrypoints.py @@ -7,5 +7,5 @@ def test_boltz_console_entrypoints_are_registered(): for entry_point in entry_points(group="console_scripts") } - assert scripts["boltz-score-existing"] == "abcfold.boltz.score_existing:main" - assert scripts["boltz-dock-crystal"] == "abcfold.boltz.dock_crystal:main" + assert scripts["boltz-affinity"] == "abcfold.boltz.score_existing:main" + assert scripts["boltz-dock"] == "abcfold.boltz.dock_crystal:main"