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
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
![Coverage](https://raw.githubusercontent.com/rigdenlab/ABCFold/refs/heads/main/.blob/coverage.svg)


Scripts to run AlphaFold3, Boltz-1 and Chai-1 with MMseqs2 Multiple sequence alignments (MSAs) and custom templates.
Scripts to run AlphaFold3, Boltz and Chai-1 with MMseqs2 Multiple sequence alignments (MSAs) and custom templates.

## Table of Contents
- [Installation](#installation)
Expand Down Expand Up @@ -57,7 +57,7 @@ python -m pre_commit install

### Running ABCfold

ABCFold will run Alphafold3, Boltz-1 and Chai-1 consecutively. The program takes an input of a JSON in the Alphafold3 format (For full instruction on how to format this, click [here](https://github.com/google-deepmind/alphafold3/blob/main/docs/input.md)). An example JSON is shown below:
ABCFold will run Alphafold3, Boltz and Chai-1 consecutively. The program takes an input of a JSON in the Alphafold3 format (For full instruction on how to format this, click [here](https://github.com/google-deepmind/alphafold3/blob/main/docs/input.md)). An example JSON is shown below:

```json
{
Expand All @@ -76,7 +76,7 @@ ABCFold will run Alphafold3, Boltz-1 and Chai-1 consecutively. The program takes
}
```

Please make sure you have AlphaFold3 installed on your system (Instructions [here](https://github.com/google-deepmind/alphafold3/blob/main/docs/installation.md)) and have procured the model parameters. Boltz-1 and Chai-1 are installed upon runtime.
Please make sure you have AlphaFold3 installed on your system (Instructions [here](https://github.com/google-deepmind/alphafold3/blob/main/docs/installation.md)) and have procured the model parameters. Boltz and Chai-1 are installed upon runtime.

For the majority of jobs, ABCFold can be run as follows:
```bash
Expand All @@ -100,7 +100,7 @@ However, there you may wish to use the following flags to add run time options s
#### Main arguments
- `<input_json>`: Path to the input AlphaFold3 JSON file.
- `<output_dir>`: Path to the output directory.
- `-a`, `-b`, `-c` (`--alphafold3`, `--boltz1`,`--chai1`): Flags to run Alphafold3, Boltz-1 and Chai-1 respectively. If none of these flags are provided, Alphafold3 will be run by default.
- `-a`, `-b`, `-c` (`--alphafold3`, `--boltz`,`--chai1`): Flags to run Alphafold3, Boltz and Chai-1 respectively. If none of these flags are provided, Alphafold3 will be run by default.
- `--mmseqs2`: [optional] Flag to use MMseqs2 MSAs and templates (if specified).
- `--mmseqs_database`: [optional] The path to the database used by a local copy of MMSeqs2, provided mmseqs is installed, the inclusion of this flag allows MMseqs2 to be run locally.
- `--override`: [optional] Flag to override the existing output directory.
Expand Down Expand Up @@ -168,7 +168,7 @@ you will find `open_output.py` in your `<output_dir>`. This needs to be run from
Below are scripts for adding MMseqs2 MSAs and custom templates to AlphaFold3 input JSON files.

> [!WARNING]
> These scripts will only modify the input JSON files, I.E. they will NOT run AlphaFold3, Boltz-1 and Chai-1.
> These scripts will only modify the input JSON files, I.E. they will NOT run AlphaFold3, Boltz and Chai-1.

### Adding MMseqs2 MSAs and templates

Expand Down Expand Up @@ -275,9 +275,9 @@ Below is an example of a hetero-3-mer. When modelling a homo-oligomer, id is giv

If you want to add a custom template to the first sequence, you can use `--target_id A`. If you wish to add a custom template to the second sequence, use `--target_id B` or `--target_id C`.

#### Boltz-1 limitations
#### Boltz limitations

If modelling multiple copies of the same sequence in Boltz-1, the input JSON must be set up as follows:
If modelling multiple copies of the same sequence in Boltz, the input JSON must be set up as follows:

```json
{
Expand Down Expand Up @@ -320,7 +320,7 @@ If the identical sequences are given as seperate entities (as shown below) you w
}
```

Additionally, Boltz-1 currently lacks the ability to create linked-ligands and therefore covalent bonds between the chain/ligand will be missing.
Additionally, Boltz currently lacks the ability to create linked-ligands and therefore covalent bonds between the chain/ligand will be missing.

## Contributing

Expand Down
57 changes: 30 additions & 27 deletions abcfold/abcfold.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ def run(args, config, defaults, config_file):

check_af3_install(interactive=False, sif_path=args.sif_path)

if args.boltz1:
from abcfold.boltz1.check_install import check_boltz1
if args.boltz:
from abcfold.boltz.check_install import check_boltz

check_boltz1()
check_boltz()

if args.chai1:
from abcfold.chai1.check_install import check_chai1
Expand Down Expand Up @@ -141,7 +141,8 @@ def run(args, config, defaults, config_file):
seq.get("protein", {}).get("unpairedMsa")
or seq.get("protein", {}).get("unpairedMsaPath")
for seq in input_params["sequences"]
)):
)
):
af3_database = make_dummy_af3_db(temp_dir)

af3_success = run_alphafold3(
Expand All @@ -167,8 +168,8 @@ def run(args, config, defaults, config_file):
run_json = ao.input_json
successful_runs.append(af3_success)

if args.boltz1:
from abcfold.boltz1.run_boltz import run_boltz
if args.boltz:
from abcfold.boltz.run_boltz import run_boltz

boltz_success = run_boltz(
input_json=run_json,
Expand Down Expand Up @@ -241,34 +242,33 @@ def run(args, config, defaults, config_file):
plddt = model.residue_plddts
if len(indicies) > 0:
plddt = insert_none_by_minus_one(
indicies[index_counter],
plddt
)
indicies[index_counter], plddt
)
index_counter += 1
model_data = get_model_data(
model, plot_dict, "AlphaFold3",
plddt, score_file, args.output_dir
model,
plot_dict,
"AlphaFold3",
plddt,
score_file,
args.output_dir,
)
alphafold_models["models"].append(model_data)

boltz_models = {"models": []}
if args.boltz1:
if args.boltz:
if boltz_success:
programs_run.append("Boltz-1")
programs_run.append("Boltz")
for idx in bo.output.keys():
model = bo.output[idx]["cif"]
model.check_clashes()
score_file = bo.output[idx]["json"]
plddt = model.residue_plddts
if len(indicies) > 0:
plddt = insert_none_by_minus_one(
indicies[index_counter],
plddt
)
plddt = insert_none_by_minus_one(indicies[index_counter], plddt)
index_counter += 1
model_data = get_model_data(
model, plot_dict, "Boltz-1",
plddt, score_file, args.output_dir
model, plot_dict, "Boltz", plddt, score_file, args.output_dir
)
boltz_models["models"].append(model_data)

Expand All @@ -284,13 +284,16 @@ def run(args, config, defaults, config_file):
plddt = model.residue_plddts
if len(indicies) > 0:
plddt = insert_none_by_minus_one(
indicies[index_counter],
plddt
)
indicies[index_counter], plddt
)
index_counter += 1
model_data = get_model_data(
model, plot_dict, "Chai-1",
plddt, score_file, args.output_dir
model,
plot_dict,
"Chai-1",
plddt,
score_file,
args.output_dir,
)
chai_models["models"].append(model_data)

Expand All @@ -305,7 +308,7 @@ def run(args, config, defaults, config_file):
cif_file = args.output_dir.joinpath(model["model_path"])
if model["model_source"] == "AlphaFold3":
output_name = "af3_model_" + model["model_id"][-1] + ".cif"
elif model["model_source"] == "Boltz-1":
elif model["model_source"] == "Boltz":
output_name = "boltz_model_" + model["model_id"][-1] + ".cif"
elif model["model_source"] == "Chai-1":
output_name = "chai_model_" + model["model_id"][-1] + ".cif"
Expand Down Expand Up @@ -399,11 +402,11 @@ def run(args, config, defaults, config_file):

def main():
"""
Run AlphaFold3 / Boltz1 / Chai-1
Run AlphaFold3 / Boltz / Chai-1
"""
import argparse

parser = argparse.ArgumentParser(description="Run AlphaFold3 / Boltz1 / Chai-1")
parser = argparse.ArgumentParser(description="Run AlphaFold3 / Boltz / Chai-1")

defaults = {}
config_file = Path(__file__).parent.joinpath("data", "config.ini")
Expand Down
25 changes: 9 additions & 16 deletions abcfold/argparse_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@ def main_argpase_util(parser):
parser.add_argument(
"input_json",
type=validate_json_file,
help="Path to the input JSON in AlphaFold3 format"
)
parser.add_argument(
"output_dir",
help="Path to the output directory"
help="Path to the input JSON in AlphaFold3 format",
)
parser.add_argument("output_dir", help="Path to the output directory")
parser.add_argument(
"--override",
help="[optional] Override the existing output directory, if it exists",
Expand All @@ -53,12 +50,10 @@ def mmseqs2_argparse_util(parser):
parser.add_argument(
"--mmseqs_database",
help="[optional] The database directory for the generation of the MSA. This \
is only required if using a local installation of MMseqs2"
is only required if using a local installation of MMseqs2",
)
parser.add_argument(
"--templates",
action="store_true",
help="[optional] Enable template search"
"--templates", action="store_true", help="[optional] Enable template search"
)
parser.add_argument(
"--num_templates",
Expand Down Expand Up @@ -118,9 +113,9 @@ def prediction_argparse_util(parser):
def boltz_argparse_util(parser):
parser.add_argument(
"-b",
"--boltz1",
"--boltz",
action="store_true",
help="Run Boltz1",
help="Run Boltz",
)
if "--save_input" not in parser._option_string_actions:
parser.add_argument(
Expand Down Expand Up @@ -200,9 +195,9 @@ def visuals_argparse_util(parser):


def raise_argument_errors(args):
if not args.alphafold3 and not args.boltz1 and not args.chai1:
if not args.alphafold3 and not args.boltz and not args.chai1:
logger.info(
"Neither AlphaFold3, Boltz-1, or Chai-1 selected. Running AlphaFold3 \
"Neither AlphaFold3, Boltz, or Chai-1 selected. Running AlphaFold3 \
by default"
)
args.alphafold3 = True
Expand All @@ -216,9 +211,7 @@ def raise_argument_errors(args):
sys.exit(1)

if args.templates and not args.mmseqs2 and not args.alphafold3:
logger.error(
"Cannot use --templates flag without using MMseqs2 or Alphafold3"
)
logger.error("Cannot use --templates flag without using MMseqs2 or Alphafold3")
sys.exit(1)

if (
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

logger = logging.getLogger("logger")

BOLTZ_VERSION = "1.0.0"
BOLTZ_VERSION = "2.1.1"


def check_boltz1():
def check_boltz():
try:
import boltz as _ # noqa F401

Expand Down Expand Up @@ -55,3 +55,5 @@ def check_boltz1():
if proc.stderr:
logger.error(proc.stderr.read().decode())
raise subprocess.CalledProcessError(proc.returncode, proc.args)

logger.info(f"Running Boltz version: {BOLTZ_VERSION}")
32 changes: 16 additions & 16 deletions abcfold/boltz1/run_boltz.py → abcfold/boltz/run_boltz.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from pathlib import Path
from typing import Union

from abcfold.boltz1.af3_to_boltz1 import BoltzYaml
from abcfold.boltz1.check_install import check_boltz1
from abcfold.boltz.af3_to_boltz import BoltzYaml
from abcfold.boltz.check_install import check_boltz

logger = logging.getLogger("logger")

Expand All @@ -20,7 +20,7 @@ def run_boltz(
num_recycles: int = 10,
) -> bool:
"""
Run Boltz1 using the input JSON file
Run Boltz using the input JSON file

Args:
input_json (Union[str, Path]): Path to the input JSON file
Expand All @@ -31,18 +31,18 @@ def run_boltz(
number_of_models (int): Number of models to generate

Returns:
Bool: True if the Boltz1 run was successful, False otherwise
Bool: True if the Boltz run was successful, False otherwise

Raises:
subprocess.CalledProcessError: If the Boltz1 command returns an error
subprocess.CalledProcessError: If the Boltz command returns an error


"""
input_json = Path(input_json)
output_dir = Path(output_dir)

logger.debug("Checking if boltz1 is installed")
check_boltz1()
logger.debug("Checking if boltz is installed")
check_boltz()

with tempfile.TemporaryDirectory() as temp_dir:
working_dir = Path(temp_dir)
Expand All @@ -55,7 +55,7 @@ def run_boltz(
out_file = working_dir.joinpath(f"{input_json.stem}.yaml")

boltz_yaml.write_yaml(out_file)
logger.info("Running Boltz1")
logger.info("Running Boltz")
cmd = (
generate_boltz_command(out_file, output_dir, number_of_models, num_recycles)
if not test
Expand All @@ -81,16 +81,16 @@ def run_boltz(
with open(output_err_file, "w") as f:
f.write(stderr.decode())
logger.error(
"Boltz1 run failed. Error log is in %s", output_err_file
"Boltz run failed. Error log is in %s", output_err_file
)
else:
logger.error("Boltz1 run failed")
logger.error("Boltz run failed")
return False
elif "WARNING: ran out of memory" in stdout:
logger.error("Boltz1 ran out of memory")
logger.error("Boltz ran out of memory")
return False

logger.info("Boltz1 run complete")
logger.info("Boltz run complete")
logger.info("Output files are in %s", output_dir)
return True

Expand All @@ -102,15 +102,15 @@ def generate_boltz_command(
num_recycles: int = 10,
) -> list:
"""
Generate the Boltz1 command
Generate the Boltz command

Args:
input_yaml (Union[str, Path]): Path to the input YAML file
output_dir (Union[str, Path]): Path to the output directory
number_of_models (int): Number of models to generate

Returns:
list: The Boltz1 command
list: The Boltz command
"""
return [
"boltz",
Expand All @@ -130,13 +130,13 @@ def generate_boltz_command(

def generate_boltz_test_command() -> list:
"""
Generate the test command for Boltz1
Generate the test command for Boltz

Args:
None

Returns:
list: The Boltz1 test command
list: The Boltz test command
"""

return [
Expand Down
Loading
Loading