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
30 changes: 19 additions & 11 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, Chai-1 and Protenix with MMseqs2 Multiple sequence alignments (MSAs) and custom templates.
Scripts to run AlphaFold3, Boltz, Chai-1, OpenFold3 and Protenix with MMseqs2 Multiple sequence alignments (MSAs) and custom templates.

## Table of Contents
- [Installation](#installation)
Expand All @@ -26,7 +26,7 @@ micromamba activate abcfold
> **Environment note**
>
> - Your main Python environment can be Conda, micromamba, or virtualenv.
> - `abcfold` will automatically create **internal micromamba environments** to run Boltz, Chai-1 and Protenix safely, therefore a micromamba installation is required.
> - `abcfold` will automatically create **internal micromamba environments** to run Boltz, Chai-1, OpenFold3 and Protenix safely, therefore a micromamba installation is required.
> - This prevents package conflicts with your main environment and ensures reproducible results.


Expand Down Expand Up @@ -57,7 +57,7 @@ python -m pre_commit install

### Running ABCfold

ABCFold will run Alphafold3, Boltz, Chai-1 and Protenix 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, Chai-1, OpenFold3 and Protenix 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,11 +76,11 @@ ABCFold will run Alphafold3, Boltz, Chai-1 and Protenix consecutively. The progr
}
```

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.
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, Chai-1, OpenFold3 and Protenix are installed upon runtime.

For the majority of jobs, ABCFold can be run as follows:
```bash
abcfold <input_json> <output_dir> -abcp --mmseqs2 --model_params <path_to_af3_model_params>
abcfold <input_json> <output_dir> -abcop --mmseqs2 --model_params <path_to_af3_model_params>
```
> [!NOTE]
> `--model_params` is stored after the first run, therefore subsequent ABCFold jobs don't require this flag.
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`, `-p` (`--alphafold3`, `--boltz`,`--chai1`,`--protenix`): Flags to run Alphafold3, Boltz, Chai-1 and Protenix respectively. If none of these flags are provided, Alphafold3 will be run by default.
- `-a`, `-b`, `-c`, `-o`, `-p` (`--alphafold3`, `--boltz`,`--chai1`, `--openfold3`, `--protenix`): Flags to run Alphafold3, Boltz, Chai-1, OpenFold3 and Protenix 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 All @@ -114,6 +114,9 @@ However, there you may wish to use the following flags to add run time options s
- `--af3_sif_path`: [optional] Path to sif file if using an AlphaFold3 singularity instead of Docker
- `--use_af3_template_search`[optional] If providing your own custom MSA or you've ran `--mmseqs2`, allow Alphafold3 to search for templates

#### OpenFold3 arguments
- `--inference_ckpt_path` [optional] Path for model checkpoint to be used for inference. If not specified, will attempt to find or download parameters in ~/.openfold3/

#### Template arguments

- `--templates`: Flag to enable a template search
Expand All @@ -132,19 +135,19 @@ However, there you may wish to use the following flags to add run time options s
If you wanted to provide a custom template, `custom_a.pdb` for your protein sequence with the ID `A` and you have your template has two chains: chain `A` and chain `B` and chain `B` is what you want the template to be, you could run:

```bash
abcfold <input_json> <output_dir> -abcp --mmseqs2 --custom_template custom_a.pdb --custom_template_chain B --target_id A
abcfold <input_json> <output_dir> -abcop --mmseqs2 --custom_template custom_a.pdb --custom_template_chain B --target_id A

```

If you had multiple IDs in your input sequence, multiple template files and you wanted to provide 3 custom templates, chain `A` from `custom_a.pdb`, chain `B` from `custom_b.pdb`, and chain B from `custom_c.pdb`, where `custom_a.pdb` and `custom_b.pdb` correspond to the ID `A` and `custom_c.pdb` corresponds to the ID `B`, you could run:

```bash
abcfold <input_json> <output_dir> -abcp --mmseqs2 --custom_template custom_a.pdb custom_b.pdb custom_c.pdb --custom_template_chain A B B --target_id A A B
abcfold <input_json> <output_dir> -abcop --mmseqs2 --custom_template custom_a.pdb custom_b.pdb custom_c.pdb --custom_template_chain A B B --target_id A A B

```
### Output

ABCFold will output the AlphaFold, Boltz and/or Chai models in the `<output_dir>`, it will also produce an output page containing a results table and informative [PAE viewer](https://gitlab.gwdg.de/general-microbiology/pae-viewer). This is opened automatically in your default browser unless the `--no_server` or `--no_visuals` flags are used.
ABCFold will output the AlphaFold, Boltz, Chai, OpenFold3 and Protenix models in the `<output_dir>`, it will also produce an output page containing a results table and informative [PAE viewer](https://gitlab.gwdg.de/general-microbiology/pae-viewer). This is opened automatically in your default browser unless the `--no_server` or `--no_visuals` flags are used.

Unless the `--no_visuals` flag is used, you can then open the output pages by running:

Expand All @@ -168,7 +171,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, Chai-1 and Protenix.
> These scripts will only modify the input JSON files, I.E. they will NOT run AlphaFold3, Boltz, Chai-1, OpenFold3 and Protenix.

### Adding MMseqs2 MSAs and templates

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

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

#### OpenFold3 limitations

Currently OpenFold3 is unable to create bonded-pairs or alter the number of recycles. Therefore these options will be ignored if provided.


## Contributing

Expand Down
64 changes: 61 additions & 3 deletions abcfold/abcfold.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
boltz_argparse_util, chai_argparse_util,
custom_template_argpase_util,
main_argpase_util, mmseqs2_argparse_util,
openfold_argparse_util,
prediction_argparse_util,
protenix_argparse_util,
raise_argument_errors,
Expand All @@ -27,6 +28,7 @@
from abcfold.output.boltz import BoltzOutput
from abcfold.output.chai import ChaiOutput
from abcfold.output.file_handlers import superpose_models
from abcfold.output.openfold3 import OpenfoldOutput
from abcfold.output.protenix import ProtenixOutput
from abcfold.output.utils import (get_gap_indicies, insert_none_by_minus_one,
make_dummy_m8_file)
Expand Down Expand Up @@ -192,7 +194,7 @@ def run(args, config, defaults, config_file):

template_hits_path = None
if args.templates and args.mmseqs2:
template_hits_path = temp_dir.joinpath("all_chain.m8")
template_hits_path = temp_dir.joinpath("all_chains.m8")
elif args.templates:
template_hits_path = make_dummy_m8_file(run_json, temp_dir)

Expand Down Expand Up @@ -230,6 +232,30 @@ def run(args, config, defaults, config_file):
outputs.append(po)
successful_runs.append(protenix_success)

if args.openfold3:
from abcfold.openfold3.run_openfold3 import run_openfold

template_hits_path = None
if args.templates and args.mmseqs2:
template_hits_path = temp_dir.joinpath("all_chains.m8")

openfold_success = run_openfold(
input_json=run_json,
output_dir=args.output_dir,
save_input=args.save_input,
number_of_models=args.number_of_models,
template_hits_path=template_hits_path,
input_ckpt=args.inference_ckpt_path
)

if openfold_success:
openfold_output_dirs = list(args.output_dir.glob("openfold_results*"))
oo = OpenfoldOutput(
openfold_output_dirs, input_params, name, args.save_input
)
outputs.append(oo)
successful_runs.append(openfold_success)

if args.no_visuals:
logger.info("Visuals disabled")
return
Expand Down Expand Up @@ -333,6 +359,34 @@ def run(args, config, defaults, config_file):
)
chai_models["models"].append(model_data)

openfold_models = {"models": []}
if args.openfold3:
if openfold_success:
programs_run.append("OpenFold3")
for seed in oo.output.keys():
for idx in oo.output[seed].keys():
if idx >= 0:
model = oo.output[seed][idx]["cif"]
model.check_clashes()
score_file = oo.output[seed][idx]["scores"]
plddt = model.residue_plddts
pae = oo.output[seed][idx]["af3_pae"]
if len(indicies) > 0:
plddt = insert_none_by_minus_one(
indicies[index_counter], plddt
)
index_counter += 1
model_data = get_model_data(
model,
plot_dict,
"OpenFold3",
plddt,
pae,
score_file,
args.output_dir,
)
openfold_models["models"].append(model_data)

protenix_models = {"models": []}
if args.protenix:
if protenix_success:
Expand Down Expand Up @@ -365,6 +419,7 @@ def run(args, config, defaults, config_file):
alphafold_models["models"] +
boltz_models["models"] +
chai_models["models"] +
openfold_models["models"] +
protenix_models["models"]
)

Expand All @@ -379,6 +434,8 @@ def run(args, config, defaults, config_file):
output_name = "boltz_model_" + model["model_id"][-1] + ".cif"
elif model["model_source"] == "Chai-1":
output_name = "chai_model_" + model["model_id"][-1] + ".cif"
elif model["model_source"] == "OpenFold3":
output_name = "openfold_model_" + model["model_id"][-1] + ".cif"
elif model["model_source"] == "Protenix":
output_name = "protenix_model_" + model["model_id"][-1] + ".cif"
shutil.copy(
Expand Down Expand Up @@ -471,12 +528,12 @@ def run(args, config, defaults, config_file):

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

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

defaults = {}
Expand All @@ -492,6 +549,7 @@ def main():
parser = alphafold_argparse_util(parser)
parser = boltz_argparse_util(parser)
parser = chai_argparse_util(parser)
parser = openfold_argparse_util(parser)
parser = protenix_argparse_util(parser)
parser = mmseqs2_argparse_util(parser)
parser = custom_template_argpase_util(parser)
Expand Down
4 changes: 2 additions & 2 deletions abcfold/alphafold3/check_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def generate_test_command(interactive: bool = True,
Returns:
str: The Alphafold3 help command
"""
if sif_path:
if sif_path is not None and sif_path != "None":
return f"""
singularity exec \
{sif_path} \
Expand All @@ -83,7 +83,7 @@ def generate_version_command(sif_path: Union[str, Path, None] = None) -> str:
"""
Generate the Alphafold3 version command
"""
if sif_path:
if sif_path is not None and sif_path != "None":
return f"""
singularity exec \
{sif_path} \
Expand Down
2 changes: 1 addition & 1 deletion abcfold/alphafold3/run_alphafold3.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def generate_af3_cmd(
input_json = Path(input_json)
output_dir = Path(output_dir)

if sif_path is not None:
if sif_path is not None and sif_path != "None":
return f"""
singularity exec \
--nv \
Expand Down
26 changes: 24 additions & 2 deletions abcfold/argparse_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,22 @@ def protenix_argparse_util(parser):
return parser


def openfold_argparse_util(parser):
parser.add_argument(
"-o",
"--openfold3",
action="store_true",
help="Run OpenFold 3",
)
parser.add_argument(
"--inference_ckpt_path",
help=dedent("Path for model checkpoint to be used for inference. \
If not specified, will attempt to find or download parameters to \
~/.openfold3/")
)
return parser


def alphafold_argparse_util(parser):
parser.add_argument(
"--database",
Expand Down Expand Up @@ -213,9 +229,15 @@ def visuals_argparse_util(parser):


def raise_argument_errors(args):
if not args.alphafold3 and not args.boltz and not args.chai1 and not args.protenix:
if (
not args.alphafold3
and not args.boltz
and not args.chai1
and not args.protenix
and not args.openfold3
):
logger.info(
dedent("Neither AlphaFold3, Boltz, Chai-1, or Protenix selected. \
dedent("None of AlphaFold3, Boltz, Chai-1, Protenix or OpenFold3 selected. \
Running AlphaFold3 by default")
)
args.alphafold3 = True
Expand Down
24 changes: 23 additions & 1 deletion abcfold/backend_envs.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,31 @@ def pip_install(self, packages: list[str]):
self._run([
"run",
"-n", self.env_name,
"pip", "install", *packages,
"python", "-m", "pip", "install",
"--break-system-packages",
*packages,
])

def conda_install(
self,
packages: list[str],
*,
channels: Optional[list[str]] = None,
):
cmd = [
"install",
"-y",
"-n", self.env_name,
]

if channels:
for ch in channels:
cmd.extend(["-c", ch])

cmd.extend(packages)

self._run(cmd)

def run(self,
command: list[str],
capture_output: bool = False,
Expand Down
2 changes: 1 addition & 1 deletion abcfold/boltz/check_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def ensure_boltz_env():
# 1. Ensure env exists
env.create(python_version="3.11")

# 2. Check installed chai version
# 2. Check installed boltz version
installed = env.get_installed_version("boltz")

if installed != BOLTZ_VERSION:
Expand Down
2 changes: 2 additions & 0 deletions abcfold/html/abcfold_vue.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Vue.component('abc-table', {
return 'btn-source3';
case 'Protenix':
return 'btn-source4';
case 'OpenFold3':
return 'btn-source5';
default:
return 'btn-default';
}
Expand Down
6 changes: 6 additions & 0 deletions abcfold/html/html_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from abcfold.output.boltz import BoltzOutput
from abcfold.output.chai import ChaiOutput
from abcfold.output.file_handlers import ConfidenceJsonFile, NpzFile
from abcfold.output.openfold3 import OpenfoldOutput
from abcfold.output.protenix import ProtenixOutput
from abcfold.plots.pae_plot import create_pae_plots
from abcfold.plots.plddt_plot import plot_plddt
Expand Down Expand Up @@ -278,6 +279,11 @@ def get_all_cif_files(outputs) -> Dict[str, list]:
if "Chai-1" not in method_cif_objs:
method_cif_objs["Chai-1"] = []
method_cif_objs["Chai-1"].extend(output.cif_files[seed])
elif isinstance(output, OpenfoldOutput):
for seed in output.seeds:
if "Openfold3" not in method_cif_objs:
method_cif_objs["Openfold3"] = []
method_cif_objs["Openfold3"].extend(output.cif_files[seed])
elif isinstance(output, ProtenixOutput):
for seed in output.seeds:
if "Protenix" not in method_cif_objs:
Expand Down
10 changes: 10 additions & 0 deletions abcfold/html/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,16 @@ rect{
transition: background-color 0.3s ease;
}

.btn-source5 {
background-color: #E89EB8;
color: #3b3b3d;
border: none;
border-radius: 12px;
padding: 7px 15px;
cursor: pointer;
transition: background-color 0.3s ease;
}

.btn-default {
background-color: rgb(199, 195, 195);
color: white;
Expand Down
Loading
Loading