Skip to content

Commit ce87d13

Browse files
authored
Merge branch 'dev' into dev
2 parents e49551a + e7f6a89 commit ce87d13

68 files changed

Lines changed: 2097 additions & 505 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.pre-commit-config.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@ repos:
44
hooks:
55
- id: prettier
66
additional_dependencies:
7-
- prettier@3.2.5
7+
- prettier@3.5.3
8+
9+
- repo: https://github.com/pre-commit/pre-commit-hooks
10+
rev: v5.0.0
11+
hooks:
12+
- id: trailing-whitespace
13+
- id: end-of-file-fixer
14+
- id: check-added-large-files
815

916
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
10-
rev: "3.1.2"
17+
rev: "3.2.1"
1118
hooks:
1219
- id: editorconfig-checker
1320
alias: ec

CHANGELOG.md

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
- [[#235](https://github.com/nf-core/proteinfold/issues/235)] - Update samplesheet to new version (switch from `sequence` column to `id`).
2121
- [[#239](https://github.com/nf-core/proteinfold/issues/239)] - Update alphafold2 standard mode Dockerfile.
2222
- [[#240](https://github.com/nf-core/proteinfold/issues/240)] - Separate download and input of pdb `mmcif` files and `obsolete` database.
23+
- [[#229](https://github.com/nf-core/proteinfold/issues/229)] - Add Boltz pipeline [PR #227](https://github.com/nf-core/proteinfold/pull/227).
2324
- [[PR #249](https://github.com/nf-core/proteinfold/pull/249)] - Update pipeline template to [nf-core/tools 3.2.0](https://github.com/nf-core/tools/releases/tag/3.2.0).
2425
- [[PR #271](https://github.com/nf-core/proteinfold/pull/271)] - Update RFAA and HF3 dockerfiles for quicker building and reduction in image size.
2526
- [[PR #274](https://github.com/nf-core/proteinfold/pull/274)] - Simplify run_helixfold3 module and move arguments to `modules.config`.
@@ -35,13 +36,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3536
- [[#273](https://github.com/nf-core/proteinfold/issues/273)] - Fixes comparison report to correctly label msa coverage plots with corresponding method label.
3637
- [[#290](https://github.com/nf-core/proteinfold/issues/290)] - Update Alphafold2 split images to make them compatible Hopper gpus.
3738
- [[PR #302](https://github.com/nf-core/proteinfold/pull/302)] - Fix HF3 dbs and max_template_date.
38-
- [[#305](https://github.com/nf-core/proteinfold/pull/305)] - Stop RFAA and HF3 symlinking scripts into workdir.
39+
- [[PR #305](https://github.com/nf-core/proteinfold/pull/305)] - Stop RFAA and HF3 symlinking scripts into workdir.
40+
- [[PR #306](https://github.com/nf-core/proteinfold/pull/306)] - extract_output.py -> extract_metrics.py so pLDDT, MSA, PAE emitted as raw data .tsv files
41+
- [[PR #307](https://github.com/nf-core/proteinfold/pull/307)] - Update Boltz-1 boilerplate and formatting.
42+
- [[PR #314](https://github.com/nf-core/proteinfold/pull/314)] - Fix extract metrics for broken modules.
43+
- [[PR #315](https://github.com/nf-core/proteinfold/pull/315)] - Add global db flag.
44+
- [[#263](https://github.com/nf-core/proteinfold/issues/263)] - Removed broken colabfold options (`auto` and `alphafold2`)
45+
- [[PR #316](https://github.com/nf-core/proteinfold/pull/316)] - Add process_gpu label to modules which use GPU.
3946

4047
### Parameters
4148

42-
| Old parameter | New parameter |
43-
| ------------- | --------------------- |
44-
| | `--pdb_obsolete_path` |
49+
| Old parameter | New parameter |
50+
| ---------------------------- | ------------------------------ |
51+
| | `--pdb_obsolete_path` |
52+
| `--small_bfd_link` | `--alphafold2_small_bfd_link` |
53+
| `--mgnify_link` | `--alphafold2_mgnify_link` |
54+
| `--pdb_mmcif_link` | `--alphafold2_pdb_mmcif_link` |
55+
| `--uniref30_alphafold2_link` | `--alphafold2_uniref30_link` |
56+
| `--uniref90_link` | `--alphafold2_uniref90_link` |
57+
| `--pdb_seqres_link` | `--alphafold2_pdb_seqres_link` |
58+
| `--small_bfd_path` | `--alphafold2_small_bfd_path` |
59+
| `--mgnify_path_alphafold2` | `--alphafold2_mgnify_path` |
60+
| `--pdb_mmcif_path` | `--alphafold2_pdb_mmcif_path` |
61+
| `--uniref30_alphafold2_path` | `--alphafold2_uniref30_path` |
62+
| `--uniref90_path` | `--alphafold2_uniref90_path` |
63+
| `--pdb_seqres_path` | `--alphafold2_pdb_seqres_path` |
64+
| `--uniprot_path` | `--alphafold2_uniprot_path` |
65+
| | `--alphafold3_small_bfd_link` |
66+
| | `--alphafold3_mgnify_link` |
67+
| | `--alphafold3_uniref90_link` |
68+
| | `--alphafold3_pdb_seqres_link` |
69+
| | `--uniprot_link` |
70+
| | `--alphafold3_small_bfd_path` |
71+
| | `--alphafold3_params_path` |
72+
| | `--alphafold3_mgnify_path` |
73+
| | `--alphafold3_pdb_mmcif_path` |
74+
| | `--alphafold3_uniref90_path` |
75+
| | `--alphafold3_pdb_seqres_path` |
76+
| | `--alphafold3_uniprot_path` |
4577

4678
> **NB:** Parameter has been **updated** if both old and new parameter information is present.
4779
> **NB:** Parameter has been **added** if just the new parameter information is present.

README.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,19 @@ On release, automated continuous integration tests run the pipeline on a full-si
3535

3636
ii. [AlphaFold2 split](https://github.com/luisas/alphafold_split) - AlphaFold2 MSA computation and model inference in separate processes
3737

38-
iii. [ColabFold](https://github.com/sokrypton/ColabFold) - MMseqs2 API server followed by ColabFold
38+
iii. [AlphaFold3](https://github.com/deepmind/alphafold) - Regular AlphaFold3 (MSA computation and model inference in the same process)
3939

40-
iv. [ColabFold](https://github.com/sokrypton/ColabFold) - MMseqs2 local search followed by ColabFold
40+
iv. [ColabFold](https://github.com/sokrypton/ColabFold) - MMseqs2 API server followed by ColabFold
4141

42-
v. [ESMFold](https://github.com/facebookresearch/esm) - Regular ESM
42+
v. [ColabFold](https://github.com/sokrypton/ColabFold) - MMseqs2 local search followed by ColabFold
4343

44-
vi. [RoseTTAFold-All-Atom](https://github.com/baker-laboratory/RoseTTAFold-All-Atom/) - Regular RFAA
44+
vi. [ESMFold](https://github.com/facebookresearch/esm) - Regular ESM
4545

46-
vii. [HelixFold3](https://github.com/PaddlePaddle/PaddleHelix/tree/dev/apps/protein_folding/helixfold3) - Regular HF3
46+
vii. [RoseTTAFold-All-Atom](https://github.com/baker-laboratory/RoseTTAFold-All-Atom/) - Regular RFAA
4747

48-
viii. [Boltz](https://github.com/jwohlwend/boltz/) - Regular Boltz-1
48+
viii. [HelixFold3](https://github.com/PaddlePaddle/PaddleHelix/tree/dev/apps/protein_folding/helixfold3) - Regular HF3
49+
50+
ix. [Boltz](https://github.com/jwohlwend/boltz/) - Regular Boltz-1
4951

5052
## Usage
5153

@@ -92,6 +94,21 @@ The pipeline takes care of downloading the databases and parameters required by
9294
-profile <docker/singularity/podman/shifter/charliecloud/conda/institute>
9395
```
9496

97+
- The AlphaFold3 mode can be run using the command below:
98+
99+
```console
100+
nextflow run nf-core/proteinfold \
101+
--input samplesheet.csv \
102+
--outdir <OUTDIR> \
103+
--mode alphafold3 \
104+
--alphafold3_db <null (default) | DB_PATH> \
105+
--use_gpu <true/false> \
106+
-profile <docker/singularity/podman/shifter/charliecloud/conda/institute>
107+
```
108+
109+
> [!WARNING]
110+
> The AlphaFold3 weights are not provided by this pipeline. Users must obtain the weights directly from DeepMind according to their [terms of use](https://github.com/deepmind/alphafold/blob/main/WEIGHTS_TERMS_OF_USE.md) and [prohibited use policy](https://github.com/deepmind/alphafold/blob/main/WEIGHTS_PROHIBITED_USE_POLICY.md). Please ensure you comply with all terms and conditions before using AlphaFold3. For more information about AlphaFold3 usage and requirements, please refer to the [official AlphaFold3 repository](https://github.com/deepmind/alphafold).
111+
95112
- Below, the command to run colabfold_local mode:
96113

97114
```console

bin/extract_metrics.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env python
2+
import pickle
3+
import os
4+
import argparse
5+
import json
6+
#import torch moved to a conditional import since too bulky import if not used
7+
import numpy as np
8+
import csv
9+
from utils import plddt_from_struct_b_factor
10+
11+
# TODO: add extraction of other values, iPTM, etc
12+
# TODO: look into have a --prog argument that could set filenames etc, logically seperate it?
13+
# {id}_{prog}_{metric}.tsv might be easier for MultiQC to parse a complex workdir, than without the .prog
14+
15+
# Mapping of characters to integers for MSA parsing.
16+
# 20 is for unknown characters, and 21 is for gaps.
17+
AA_to_int = {
18+
"A": 0, "C": 1, "D": 2, "E": 3, "F": 4, "G": 5, "H": 6, "I": 7, "K": 8, "L": 9,
19+
"M": 10, "N": 11, "P": 12, "Q": 13, "R": 14, "S": 15, "T": 16, "V": 17, "W": 18, "Y": 19,
20+
".": 20, "-": 21
21+
}
22+
23+
def a3m_to_int(a3m_file):
24+
"""
25+
Convert an A3M MSA representation into an integer representation (0-21).
26+
"""
27+
with open(a3m_file, "r") as f:
28+
msa = f.read()
29+
30+
# Convert each sequence in the MSA
31+
int_sequences = []
32+
for idx, line in enumerate(msa.splitlines()):
33+
if idx == 0 and not line.startswith(">"): # If there's an additional header (non-FASTA) skip it. E.g ColabFold
34+
continue
35+
36+
if not line.startswith(">"): # Ignore header lines
37+
filtered_line = ''.join(char for char in line if not char.islower()) # Remove inserts (lower-case chars) in a3m
38+
int_sequence = [AA_to_int.get(char.upper(), 20) for char in filtered_line]
39+
int_sequences.append(int_sequence)
40+
41+
int_sequences_array = np.array(int_sequences, dtype=object)
42+
return int_sequences_array
43+
44+
def format_msa_rows(msa_data):
45+
return [[str(x) for x in val] for val in msa_data]
46+
47+
def format_pae_rows(pae_data):
48+
return [[f"{num:.4f}" for num in row] for row in pae_data]
49+
50+
def write_tsv(file_path, rows):
51+
with open(file_path, 'w') as out_f:
52+
writer = csv.writer(out_f, delimiter='\t')
53+
writer.writerows(rows)
54+
55+
def extract_structs_plddt_to_tsv(id, structures):
56+
"""
57+
Write out a tsv file contain pLDDTs for reading by MultiQC in nf-core/proteinfold
58+
Uses utils function with BioPython PDB package to extract residue pLDDT values from the b-factor column.
59+
"""
60+
plddt_cols = [plddt_from_struct_b_factor(structure) for structure in structures]
61+
res_counts = [len(plddt_col) for plddt_col in plddt_cols]
62+
63+
if len(set(res_counts)) != 1:
64+
raise ValueError("Not all structures have the same number of residues!")
65+
66+
rank_names = [f"rank_{i}" for i in range(len(structures))]
67+
# Create header as the first row
68+
plddt_rows = [["Positions"] + rank_names]
69+
res_id_col = list(range(len(plddt_cols[0])))
70+
plddt_rows.extend(zip(res_id_col, *plddt_cols)) # Combine lists column-wise to make rows
71+
write_tsv(f"{id}_plddt.tsv", plddt_rows)
72+
73+
def read_pkl(id, pkl_files):
74+
"""
75+
Adapted from the Galaxy AlphaFold tool (https://github.com/usegalaxy-au/tools-au/blob/de94df520c8dc7b8652aedb92e90f6ebb312f95f/tools/alphafold/scripts/outputs.py), originally authored by @neoformit and @graceahall and funded by Australian Biocommons and QCIF Australia.
76+
"""
77+
for pkl_file in pkl_files:
78+
print(f"Processing {pkl_file}")
79+
data = pickle.load(open(pkl_file, "rb"))
80+
81+
# Process MSA data
82+
if pkl_file.endswith("final_features.pkl"): # HelixFold3 - This one must be first
83+
write_tsv(f"{id}_msa.tsv", format_msa_rows(data["feat"]["msa"]))
84+
elif pkl_file.endswith("features.pkl"): # AlphaFold2.3
85+
# TODO: AlphaFold2.3 fills end rows with 0s in AlpahFold muliter for an alanine nf-core/proteinfold Issue #300
86+
write_tsv(f"{id}_msa.tsv", format_msa_rows(data["msa"]))
87+
# AlphaFold2.3 non-summary, for each pkl. TODO: Need to either read in ranking_debug.json to get the ranking order, or do it later in the workflow.
88+
else:
89+
model_id = os.path.basename(pkl_file).replace("result_model_", "").replace(".pkl", "")
90+
write_tsv(f"{id}_{model_id}_lddt.tsv", format_msa_rows(data["plddt"]))
91+
92+
if 'predicted_aligned_error' not in data.keys():
93+
print(f"No PAE output in {pkl_file}, it was likely a monomer calculation")
94+
write_tsv(f"{id}_{model_id}_pae.tsv", None)
95+
else:
96+
write_tsv(f"{id}_{model_id}_pae.tsv", format_pae_rows(data["predicted_aligned_error"]))
97+
98+
def read_a3m(id, a3m_files):
99+
# ColabFold, RosettaFold-All-Atom, Boltz-1
100+
for a3m_file in a3m_files:
101+
int_seqs = a3m_to_int(a3m_file)
102+
write_tsv(f"{id}_msa.tsv", format_msa_rows(int_seqs))
103+
104+
def read_npz(id, npz_files):
105+
for idx, npz_file in enumerate(npz_files):
106+
data = np.load(npz_file)
107+
#Boltz PAE files if --write_full_pae is used
108+
if npz_file.split('/')[-1].startswith('pae') and npz_file.endswith('.npz'):
109+
write_tsv(f"{id}_{idx}_pae.tsv", format_pae_rows(data["pae"]))
110+
111+
def read_json(id, json_files):
112+
for idx, json_file in enumerate(json_files):
113+
with open(json_file, 'r') as f:
114+
data = json.load(f)
115+
if json_file.endswith("_data.json"): #AF3 output with MSA info
116+
# Can't just used format_msa_rows since there's FASTA headers in the json content
117+
unpaired_MSAs = data['sequences'][0]['protein']['unpairedMsa']
118+
msa_lines = [''.join(c for c in line if not c.islower()) for line in unpaired_MSAs.split("\n") if line.strip() and not line.startswith(">")]
119+
msa_rows = [[str(AA_to_int.get(residue, 20)) for residue in line] for line in msa_lines]
120+
write_tsv(f"{id}_msa.tsv", msa_rows)
121+
#AF3 output with PAE info, or HF3 PAE data. TODO: Need to make sure the workflow points to [protein]/[protein]_rank1/all_results.json
122+
elif "pae" in data:
123+
write_tsv(f"{id}_{idx}_pae.tsv", format_pae_rows(data["pae"]))
124+
125+
def read_pt(id, pt_files):
126+
import torch # moved to a conditional import since too bulky import if not used
127+
for pt_file in pt_files:
128+
with open(pt_file, 'rb') as f: # TODO: point to [protein]_aux.pt
129+
data = torch.load(f, map_location="cpu")
130+
if 'pae' in data:
131+
# The pt file contains a tensor that needs to be cast as an array
132+
# Squeeze leading dimension (batch?)
133+
write_tsv(f"{id}_pae.tsv", format_pae_rows(np.squeeze(data["pae"].numpy())))
134+
135+
def main():
136+
parser = argparse.ArgumentParser()
137+
parser.add_argument("--pkls", dest="pkls", required=False, nargs="+") # For reading both HelixFold3 and AlphaFold2 MSA formats
138+
parser.add_argument("--npzs", dest="npzs", required=False, nargs="+") # For reading the Boltz-1 PAE formats. TODO: Boltz-1 MSA not implemented (go straight to .a3m file), implement
139+
parser.add_argument("--a3ms", dest="a3ms", required=False, nargs="+") # For reading the RosettaFold-All-Atom, ColabFold, and Boltz-1 MSA formats
140+
parser.add_argument("--jsons", dest="jsons", required=False, nargs="+") # For reading the AF3 MSA & PAE, HF3 PAE
141+
parser.add_argument("--pts", dest="pts", required=False, nargs="+") # For read RFAA pytorch model to get PAE data
142+
parser.add_argument("--structs", dest="structs", required=False, nargs="+")
143+
parser.add_argument("--name", default="untitled", dest="name") # might need a --name $meta.id
144+
parser.add_argument("--output_dir", default=".", dest="output_dir")
145+
args = parser.parse_args()
146+
147+
if args.pkls:
148+
read_pkl(args.name, args.pkls)
149+
if args.a3ms:
150+
read_a3m(args.name, args.a3ms)
151+
if args.npzs:
152+
read_npz(args.name, args.npzs)
153+
if args.jsons:
154+
read_json(args.name, args.jsons)
155+
if args.pts:
156+
read_pt(args.name, args.pts)
157+
if args.structs:
158+
extract_structs_plddt_to_tsv(args.name, args.structs)
159+
160+
if __name__ == "__main__":
161+
main()

bin/extract_output.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)