diff --git a/CONTEXT.md b/CONTEXT.md
index 9e300788..e525de5a 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -13,22 +13,24 @@
- **Fold preparation**: building the object to model for one prediction job and its
output directory, including AlphaPulldown-style naming and feature-metadata copying.
Shared by the single-fold command and the resident batch so the two cannot diverge.
-- **Feature request**: one named sequence, of a stated molecule type, requiring an AlphaFold 3 feature artifact.
+- **Feature request**: one named sequence, of a stated molecule type, requiring a feature artifact.
- **Molecule type**: whether a feature request is a protein or an RNA chain. It decides
which databases are searched, whether a paired MSA exists at all, and which AlphaFold 3
- chain the finalized artifact carries. DNA has no MSA and is not handled by this path.
+ chain the finalized artifact carries. RNA is AlphaFold 3 only, and DNA has no MSA and
+ is not handled by this path.
- **Feature batch**: an ordered collection of feature requests handled as one operation.
- **MSA batch**: the GPU stage that searches MMseqs2 and durably publishes one reusable MSA bundle per feature request.
-- **Feature finalization**: the CPU stage that reads an MSA bundle, performs native AF3 template search, and publishes the standard AF3 feature artifact.
-- **MSA bundle**: an atomic intermediate JSON containing one sequence, merged unpaired A3M, paired A3M, and complete MMseqs/database provenance.
+- **Feature finalization**: the CPU stage that reads an MSA bundle, performs the backend's native template search (AF3's, or AF2's hmmsearch/hhsearch), and publishes that backend's standard feature artifact.
+- **MSA bundle**: an atomic intermediate JSON containing one sequence, merged unpaired A3M, paired A3M, how many unpaired rows each database contributed, and complete MMseqs/database provenance. Its A3Ms carry both full database headers and insertions.
+- **Two-pass format**: formatting one MMseqs2 search result twice and joining the passes row by row, because the format with full headers drops insertions and the format with insertions drops the headers.
- **Database identifier**: the caller-supplied immutable identity of one MMseqs2 database build; cache validity depends on it, not only its filesystem path.
-- **Feature artifact**: the standard AlphaFold 3 JSON (optionally LZMA-compressed) produced for one feature request.
+- **Feature artifact**: the standard features one backend consumes for one feature request: an AlphaFold 3 JSON, or an AlphaFold 2 MonomericObject pickle (either optionally LZMA-compressed).
- **MSA cache hit**: an existing MSA bundle whose sequence, MMseqs2 executable version, search settings, and database identifiers match the request.
-- **Feature cache hit**: an existing feature artifact whose MSA provenance, maximum template date, PDB seqres identity, and mmCIF identity match the request.
+- **Feature cache hit**: an existing feature artifact whose MSA provenance, maximum template date, PDB seqres identity, and mmCIF identity match the request (for AlphaFold 2, also the template searcher).
- **Recoverable failure**: a failure isolated to one sequence; remaining requests continue and the batch reports a nonzero summary after writing successful artifacts.
- **Database role**: whether a configured MMseqs2 database supplies unpaired hits
(uniref90, mgnify, small_bfd, merged into one MSA) or paired hits (uniprot, whose
- UniProt taxon headers let AlphaFold 3 pair chains by species). Roles are named, not
+ UniProt taxon headers let AlphaFold pair chains by species). Roles are named, not
inferred from a position in the configured list.
- **RNA database set**: the three nucleotide databases AlphaFold 3 merges into one
unpaired RNA MSA (rfam, rnacentral, nt_rna). All unpaired - AlphaFold 3 never pairs
diff --git a/README.md b/README.md
index 6dbf591f..f6b0835d 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
### Quick install (recommended)
```bash
-curl -O https://raw.githubusercontent.com/KosinskiLab/AlphaPulldownSnakemake/2.8.0/install.sh
+curl -O https://raw.githubusercontent.com/KosinskiLab/AlphaPulldownSnakemake/2.9.0/install.sh
bash install.sh
conda activate snake
cd AlphaPulldownSnakemake
@@ -25,7 +25,7 @@ Useful options:
| Option | Meaning |
| --- | --- |
| `-d, --dest DIR` | working directory to deploy into (default `AlphaPulldownSnakemake`) |
-| `-v, --version TAG` | workflow version to deploy (default `2.8.0`) |
+| `-v, --version TAG` | workflow version to deploy (default `2.9.0`) |
| `-i, --image-dir DIR` | shared container image directory |
| `-n, --env-name NAME` | conda environment name (default `snake`) |
| `--no-pull` | skip container pre-fetch (Snakemake will fetch on first run) |
@@ -43,7 +43,7 @@ Create and activate the conda environment:
```bash
conda env create \
-n snake \
- -f https://raw.githubusercontent.com/KosinskiLab/AlphaPulldownSnakemake/2.8.0/workflow/envs/alphapulldown.yaml
+ -f https://raw.githubusercontent.com/KosinskiLab/AlphaPulldownSnakemake/2.9.0/workflow/envs/alphapulldown.yaml
conda activate snake
```
@@ -55,7 +55,7 @@ Then deploy the workflow into a new processing directory for your project:
snakedeploy deploy-workflow \
https://github.com/KosinskiLab/AlphaPulldownSnakemake \
AlphaPulldownSnakemake \
- --tag 2.8.0
+ --tag 2.9.0
cd AlphaPulldownSnakemake
```
@@ -71,12 +71,13 @@ images are still shared across projects. See
| section | what it holds |
| --- | --- |
-| **REQUIRED** | inputs, output directory, databases, weights, prediction container |
-| **COMMON** | features, backend flags, analysis, batching, SLURM partition |
-| **ADVANCED** | memory sizing, length filtering, GPU routing, spilling, CPU partitions |
+| **REQUIRED** | inputs, output directory, databases, weights, matching backend settings, SLURM partitions |
+| **COMMON** | precomputed features, feature-only runs, analysis, duplicate complexes |
+| **ADVANCED** | batching, resource limits, GPU selection, local MMseqs2, detailed report options |
-Each key carries a one-line comment naming the section below that documents it in full.
-A first run normally only needs the REQUIRED section.
+The comments explain each group and point to the relevant section below. A first run
+normally only needs REQUIRED. Desktop runs ignore the SLURM settings. Local MMseqs2
+is off by default; its complete configuration is kept together under ADVANCED.
### Setup protein folding jobs
@@ -104,24 +105,25 @@ You can also specify:
- **Combinations**: `Q8I2G6:2:1-100+Q8I5K4` (dimer of residues 1-100 plus another protein)
- **Copies plus discontinuous regions**: `Q8I2G6:2:1-100:150-200+Q8I5K4`
-The same copy/range syntax also works with AlphaFold 3 JSON features
-(`--data_pipeline: alphafold3`). Examples:
+The same copy/range syntax also works when the workflow generates AlphaFold 3
+JSON features (`--data_pipeline: alphafold3`). Examples:
- `Q8I2G6_af3_input.json:1-100`
- `Q8I2G6_af3_input.json:1-100:150-200`
- `Q8I2G6_af3_input.json:2:1-100:150-200+Q8I5K4_af3_input.json`
-When a workflow or wrapper maps a logical token such as `Q8I2G6:1-100:150-200`
-to `Q8I2G6_af3_input.json:1-100:150-200`, AlphaPulldown preserves the region
-selection and keeps the AF3 JSON feature input as one discontinuous polymer
-chain with preserved residue-number gaps, so chopped regions stay intra-chain
-and template contacts between retained fragments are not masked as inter-chain
-interactions. The original residue IDs are written to the mmCIF author-numbering
-fields (`auth_seq_id` and `pdbx_PDB_ins_code`); overlapping IDs are disambiguated
-with insertion codes such as `2A`, `2B`, and so on.
-This syntax is parsed by the shared `alphapulldown-input-parser` package used by
-both AlphaPulldown and AlphaPulldownSnakemake; make sure the execution
-environment carries `alphapulldown-input-parser>=0.5.1`.
+In that mode the Snakefile rewrites logical inputs such as
+`Q8I2G6:1-100:150-200` to the corresponding
+`Q8I2G6_af3_input.json:1-100:150-200` feature reference automatically.
+AlphaPulldown preserves those discontinuous regions as one gapped polymer
+chain with preserved residue-number gaps.
+This keeps retained fragments intra-chain, so template contacts between those
+fragments are not masked as inter-chain interactions.
+The original residue IDs are written to the mmCIF author-numbering fields
+(`auth_seq_id` and `pdbx_PDB_ins_code`); overlapping IDs are disambiguated with
+insertion codes such as `2A`, `2B`, and so on.
+Make sure the prediction container or runtime environment includes a matching
+AlphaPulldown build together with `alphapulldown-input-parser>=0.5.1`.
@@ -136,7 +138,7 @@ input_files:
### Setting up databases
-If you do not already have the AlphaFold databases, `scripts/setup_databases.sh`
+If you do not already have the AlphaFold databases, `scripts/setup_databases.sh` from AlphaPulldown
fetches them and builds the MMseqs2 versions:
```bash
@@ -335,18 +337,18 @@ prediction_container: "/path/to/images/alphafold3-2.5.0.sif"
### GPU compatibility
The containers carry their own CUDA runtime (pip `nvidia-*` wheels), so GPU support depends on the
-image tag, not on the driver installed on the node. Releases 2.5.0 and newer run on every GPU in the
-EMBL cluster, with both AlphaFold 2 and AlphaFold 3:
-
-- RTX 3090, 24 GB, sm_86 (`gpu21-22`, `gpu29-37`)
-- A100, 40 GB, sm_80 (`gpu25-28`)
-- A40, 48 GB, sm_86 (`sb03-05` to `sb03-20`)
-- L40S, 48 GB, sm_89 (`gpu40-48`)
-- H100, 80 GB, sm_90 (`gpu38-39`, and `hgx2-3` in `gpu-training`)
-- H200, 141 GB, sm_90 (`hgx4-5` in `gpu-training`)
-- B200, 180 GB, sm_100 (`bgx1` in `gpu-training`)
-- RTX PRO 4500 Blackwell, 16 GB MIG slices, sm_120 (`gpu60-68`)
-- RTX PRO 6000 Blackwell, 96 GB, sm_120 (`gpu51-53`)
+image tag, not on the driver installed on the node. Releases 2.5.0 and newer have been tested on
+the following GPUs, with both AlphaFold 2 and AlphaFold 3:
+
+- RTX 3090, 24 GB, sm_86
+- A100, 40 GB, sm_80
+- A40, 48 GB, sm_86
+- L40S, 48 GB, sm_89
+- H100, 80 GB, sm_90
+- H200, 141 GB, sm_90
+- B200, 180 GB, sm_100
+- RTX PRO 4500 Blackwell, 16 GB MIG slices, sm_120
+- RTX PRO 6000 Blackwell, 96 GB, sm_120
On other clusters the same rule applies by compute capability: sm_80 (Ampere) through sm_120
(Blackwell) all work with a 2.5.0 or newer image.
@@ -375,7 +377,7 @@ While you are still on an older image, keep inference off those nodes with `slur
-MIG slices (gpu60-68)
+MIG slices
Those nodes are RTX PRO 4500 cards split into 16 GB `1g.16gb` MIG instances. They need no special
`slurm_gres`: a plain `gpu:1` request lands on one slice and SLURM sets
@@ -450,15 +452,15 @@ you hit these.
uses the biggest tier and spills to host RAM via unified memory.
```yaml
- # Example for the EMBL GPU pool; replace nodes with your cluster's (nothing is hard-coded):
+ # Example GPU tiers; replace these node names with your cluster's:
structure_inference_gpu_vram_headroom: 1.0 # <1.0 tolerates that fraction of host spill
structure_inference_gpu_tiers:
- - {min_vram_gb: 16, nodes: "gpu60,gpu61,gpu62,gpu63,gpu64,gpu65,gpu66,gpu67,gpu68"} # RTX PRO 4500, 16GB MIG
- - {min_vram_gb: 24, nodes: "gpu21,gpu22,gpu29,gpu30,gpu31,gpu32,gpu33,gpu34,gpu35,gpu36,gpu37"}
- - {min_vram_gb: 40, nodes: "gpu25,gpu26,gpu27,gpu28"}
- - {min_vram_gb: 48, nodes: "gpu40,gpu41,gpu42,gpu43,gpu44,gpu45,gpu46,gpu47,gpu48"}
- - {min_vram_gb: 80, nodes: "gpu38,gpu39"}
- - {min_vram_gb: 96, nodes: "gpu51,gpu52,gpu53"} # RTX PRO 6000 Blackwell
+ - {min_vram_gb: 16, nodes: "gpu-16gb-01,gpu-16gb-02"} # RTX PRO 4500, 16GB MIG
+ - {min_vram_gb: 24, nodes: "gpu-24gb-01,gpu-24gb-02"}
+ - {min_vram_gb: 40, nodes: "gpu-40gb-01,gpu-40gb-02"}
+ - {min_vram_gb: 48, nodes: "gpu-48gb-01,gpu-48gb-02"}
+ - {min_vram_gb: 80, nodes: "gpu-80gb-01,gpu-80gb-02"}
+ - {min_vram_gb: 96, nodes: "gpu-96gb-01,gpu-96gb-02"} # RTX PRO 6000 Blackwell
```
When set this drives `--exclude` per job and **overrides** `structure_inference_gpu_model` (the two
@@ -468,7 +470,7 @@ you hit these.
partition(s); it excludes nodes by name, so if you span **multiple partitions** (see above) make
sure the tier node lists cover every partition you submit to.
- **Exclude specific nodes** with `slurm_exclude_nodes`, passed verbatim to `sbatch --exclude`
- (e.g. `"gpu51,gpu52"`). `--exclude` is allowed in `slurm_extra` whereas
+ (e.g. `"gpu-96gb-01,gpu-96gb-02"`). `--exclude` is allowed in `slurm_extra` whereas
`--constraint`/`--gres`/`--gpus` are not, so it is the supported way to drop a few nodes while
keeping the rest of the partition. The usual reason to need it is a GPU the container image is too
old for; see [GPU compatibility](#gpu-compatibility).
@@ -512,8 +514,7 @@ read with `nvidia-smi` once the job lands on a node, and the host RAM is the job
ceiling within the SLURM allocation so XLA cannot oversubscribe host RAM beyond what the
job requested — which would otherwise get the job OOM-killed. The chosen fraction is
logged as a `[unified-memory]` line at the top of the job log. Pin a number instead if
-you want a fixed multiplier regardless of GPU/RAM (mirrors the EMBL `run_AF_multimer.sh`
-convention).
+you want a fixed multiplier regardless of GPU/RAM.
> The fraction is computed in the job shell rather than via the SLURM executor: the
> executor passes the submit environment through with `--export=ALL` but offers no
@@ -542,7 +543,8 @@ structure_inference mem = safety * (structure_inference_ram_bytes + per_token_s
```
- `seq_len` is the query length; `N` is the **total residues of the complex** (the
- AlphaFold token count, summed over chains and copy numbers). AlphaFold's pair
+ AlphaFold token count, summed over chains and copy numbers). For AlphaFold 3, `N` is
+ rounded up to the `--buckets` size the model pads to. AlphaFold's pair
representation is `O(N^2)`, hence the quadratic inference term.
- **The coefficients default by backend** (selected from `--data_pipeline` / `--fold_backend`).
AlphaFold-Multimer (AF2) is heavier than AlphaFold 3 — measured AF2 inference host RSS was
@@ -677,38 +679,117 @@ batch_max_tokens: 0 # optional cap on summed residues per batch (0 = no cap)
-### Batched local MMseqs2-GPU features (AlphaFold 3)
+### Using precomputed features
+
+If you have precomputed protein features, specify the directory:
+
+```yaml
+feature_directory:
+ - "/path/to/directory/with/features/"
+```
+
+> **Note**: If your features are compressed, set `compress-features: True` in the config.
+
+### Feature generation flags (`create_individual_features.py`)
+
+Tweak the feature-generation step by editing `create_feature_arguments` (or by running the script
+manually).
+
+
+Commonly used flags
+
+- `--data_pipeline {alphafold2,alphafold3}` – choose the feature format to emit.
+- `--db_preset {full_dbs,reduced_dbs}` – switch between the full BFD stack or the reduced databases.
+- `--use_mmseqs2` – rely on the remote MMseqs2 API; skips local jackhmmer/HHsearch database lookups.
+ To reuse a3m files generated locally with `colabfold_search`, also set `--use_precomputed_msas=True`
+ (see the [mmseqs2 manual](https://github.com/KosinskiLab/AlphaPulldown/blob/main/manuals/mmseqs2_manual.md));
+ otherwise the remote API is contacted again and your a3m files are overwritten.
+- `--skip_msa` – generate query-only single-sequence features instead of running bulk MSA searches.
+ Use those feature pickles with `run_structure_prediction.py --pair_msa=False`.
+- `--use_precomputed_msas` / `--save_msa_files` – reuse stored MSAs (`/.a3m`) or
+ keep new ones for later runs. Required to reuse precomputed MMseqs2/ColabFold a3m files rather
+ than regenerating them.
+- `--compress_features` – compress the generated features to save space: `*.pkl.xz` for the AlphaFold2 pipeline, `*_af3_input.json.xz` for AlphaFold3. Both are read back transparently, so compressed feature sets can be used directly (this is how the [features database](https://alphapulldown.s3.embl.de) ships them).
+- `--skip_existing` – leave existing feature files untouched (safe for reruns).
+- `--keep_msas` – refresh **templates only** in features that already exist in `--output_dir`, keeping their MSAs. Use it when the template database or `--max_template_date` has moved but the alignments are still valid: it costs a template search (minutes) instead of a full MSA run (hours). Works for both pipelines — AlphaFold2 features get their `template_*` block replaced, AlphaFold3 features are re-processed through AF3's "search for templates only" path. Proteins with no stored features are generated normally, and it takes precedence over `--skip_existing`. Cannot be combined with `--use_mmseqs2` (which fetches MSAs and templates together) or `--skip_msa` (no MSAs to keep).
+- `--seq_index N` – only process the N‑th sequence from the FASTA list.
+- `--use_hhsearch`, `--re_search_templates_mmseqs2` – toggle template search implementations.
+- `--path_to_mmt`, `--description_file`, `--multiple_mmts` – enable TrueMultimer CSV-driven feature sets.
+- `--max_template_date YYYY-MM-DD` – required cutoff for template structures; keeps runs reproducible.
+
+
+
+### Batched local MMseqs2 features (AlphaFold 2 and 3)
-Faster AlphaFold 3 MSAs using local MMseqs2 instead of jackhmmer/HHblits
+Faster MSAs using local MMseqs2 instead of jackhmmer/HHblits
-Off by default. Proteins are split into bounded GPU shards searched with MMseqs2, and a
-separate CPU stage runs AlphaFold 3's own template search and writes one standard AF3
-JSON per chain — so template work can use CPU and big-memory partitions in parallel.
-AlphaFold 2 feature generation and the remote `--use_mmseqs2` path are unchanged. RNA
-chains are supported once the RNA databases are configured.
+Off by default. Missing proteins are split into bounded shards searched with MMseqs2 —
+as GPU jobs, or CPU jobs with `use_gpu: false` — and a separate CPU stage turns each
+chain's alignment into standard features, so template work can use CPU and big-memory
+partitions in parallel. Which features follows `--data_pipeline` in
+`create_feature_arguments`: an AF3 JSON per chain, or an AF2 pickle. The remote
+`--use_mmseqs2` path is unchanged. RNA chains are supported for AlphaFold 3 once the RNA
+databases are configured.
```yaml
mmseqs2_features:
enabled: true
+ use_gpu: true
temp_dir: /local-fast-scratch/mmseqs
+ template_database_ids:
+ pdb_seqres: pdb-seqres-2026-08
+ mmcif: pdb-mmcif-2026-08
+ # pdb70: pdb70-2026-08 # required for AF2 --use_hhsearch
databases:
- uniref90: {path: /db/mmseqs/uniref90, identifier: uniref90-2026-08, max_sequences: 10000}
- mgnify: {path: /db/mmseqs/mgnify, identifier: mgnify-2026-08, max_sequences: 5000}
- small_bfd: {path: /db/mmseqs/small_bfd, identifier: small-bfd-2026-08, max_sequences: 5000}
- uniprot: {path: /db/mmseqs/uniprot, identifier: uniprot-2026-08, max_sequences: 50000}
+ uniref90: {path: /db/mmseqs/uniref90_gpu, identifier: uniref90-2026-08, max_sequences: 10000}
+ mgnify: {path: /db/mmseqs/mgnify_gpu, identifier: mgnify-2026-08, max_sequences: 5000}
+ small_bfd: {path: /db/mmseqs/small_bfd_gpu, identifier: small-bfd-2026-08, max_sequences: 5000}
+ uniprot: {path: /db/mmseqs/uniprot_gpu, identifier: uniprot-2026-08, max_sequences: 50000}
```
The protein databases must be padded (`makepaddedseqdb`); the RNA ones must not be.
`scripts/setup_databases.sh --mmseqs` builds them. The native AlphaFold 3 database tree
-is still required — these are additive, not a replacement.
+is still required — these are additive, not a replacement. Memory and walltime for both
+stages are derived from the configured databases; the remaining knobs live in the
+ADVANCED section of `config/config.yaml`.
+
+**The GPU search reads every padded database in full**, about 375 GB for the four
+protein ones. On network storage a cold first attempt is bound by that read, not by the
+GPU: measured ~150 MB/s from NFS with the GPU idle, about an hour per shard, against
+minutes once the node's page cache holds the databases. If first attempts time out,
+raise `search_runtime_base_minutes` or stage the databases on local disk; the retry,
+with twice the walltime, recovers either way.
**Depth is not identical to the native pipeline.** Measured on eight *B. subtilis*
proteins it was ~90% of jackhmmer's unpaired depth overall, but only 54–68% on the
shallowest families. Whether that costs accuracy is untested, so treat it as opt-in and
spot-check your own targets.
-Databases, RNA, tuning, caching and caveats: [docs/mmseqs2_rna.md](docs/mmseqs2_rna.md).
+**For AlphaFold 2** set `--data_pipeline: alphafold2` and enable the block above. The
+MSA recipe is AlphaFold 2's `reduced_dbs` set (no BFD/UniRef30 HHblits arm); templates
+come from the AlphaFold 2 database tree, and `--use_hhsearch` and any explicit template
+paths in `create_feature_arguments` reach the finalization stage. The MSA cache
+remains reusable when only the template database changes. With
+`--use_hhsearch: true`, set `mmseqs2_features.template_database_ids.pdb70` to the
+immutable PDB70 build identity; `pdb_seqres` is then unused. Other template searches
+require `pdb_seqres`, and every search requires `mmcif`. Update the relevant ID when
+rebuilding a database, even at the same path; this invalidates finalized features.
+The native MSA arguments do not reach finalization because this stage replaces
+that search. Use a matching prediction image, such as
+`docker://kosinskilab/alphafold2:2.9.0`, for AlphaFold 2. AlphaFold 2 finalization is
+heavier than AlphaFold 3's because template featurization dominates it — median ~1 GB and 2 min, but up to
+19 GB and 90 min, set by which structures the templates come from rather than by length
+— so its defaults request 16 GB (times the safety factor) and 60 min. Against native
+`reduced_dbs` features on 12 heterodimers released after AF2-multimer's training cutoff,
+top-ranked DockQ averaged 0.56 against 0.59, with 9 of 12 interfaces acceptable either
+way.
+
+Alignments preserve insertions for both backends. Older MSA bundles that lost
+insertions are regenerated automatically.
+
+Databases, RNA, AlphaFold 2, tuning, caching and caveats:
+[AlphaPulldown docs/mmseqs2_rna.md](https://github.com/KosinskiLab/AlphaPulldown/blob/main/docs/mmseqs2_rna.md).
@@ -822,51 +903,9 @@ structure_inference_arguments:
---
-### Using precomputed features
-
-If you have precomputed protein features, specify the directory:
-
-```yaml
-feature_directory:
- - "/path/to/directory/with/features/"
-```
-
-> **Note**: If your features are compressed, set `compress-features: True` in the config.
-
-### Feature generation flags (`create_individual_features.py`)
-
-Tweak the feature-generation step by editing `create_feature_arguments` (or by running the script
-manually).
-
-
-Commonly used flags
-
-- `--data_pipeline {alphafold2,alphafold3}` – choose the feature format to emit.
-- `--db_preset {full_dbs,reduced_dbs}` – switch between the full BFD stack or the reduced databases.
-- `--use_mmseqs2` – rely on the remote MMseqs2 API; skips local jackhmmer/HHsearch database lookups.
- To reuse a3m files generated locally with `colabfold_search`, also set `--use_precomputed_msas=True`
- (see the [mmseqs2 manual](https://github.com/KosinskiLab/AlphaPulldown/blob/main/manuals/mmseqs2_manual.md));
- otherwise the remote API is contacted again and your a3m files are overwritten.
-- `--skip_msa` – generate query-only single-sequence features instead of running bulk MSA searches.
- Use those feature pickles with `run_structure_prediction.py --pair_msa=False`.
-- `--use_precomputed_msas` / `--save_msa_files` – reuse stored MSAs (`/.a3m`) or
- keep new ones for later runs. Required to reuse precomputed MMseqs2/ColabFold a3m files rather
- than regenerating them.
-- `--compress_features` – compress the generated features to save space: `*.pkl.xz` for the AlphaFold2 pipeline, `*_af3_input.json.xz` for AlphaFold3. Both are read back transparently, so compressed feature sets can be used directly (this is how the [features database](https://alphapulldown.s3.embl.de) ships them).
-- `--skip_existing` – leave existing feature files untouched (safe for reruns).
-- `--keep_msas` – refresh **templates only** in features that already exist in `--output_dir`, keeping their MSAs. Use it when the template database or `--max_template_date` has moved but the alignments are still valid: it costs a template search (minutes) instead of a full MSA run (hours). Works for both pipelines — AlphaFold2 features get their `template_*` block replaced, AlphaFold3 features are re-processed through AF3's "search for templates only" path. Proteins with no stored features are generated normally, and it takes precedence over `--skip_existing`. Cannot be combined with `--use_mmseqs2` (which fetches MSAs and templates together) or `--skip_msa` (no MSAs to keep).
-- `--seq_index N` – only process the N‑th sequence from the FASTA list.
-- `--use_hhsearch`, `--re_search_templates_mmseqs2` – toggle template search implementations.
-- `--path_to_mmt`, `--description_file`, `--multiple_mmts` – enable TrueMultimer CSV-driven feature sets.
-- `--max_template_date YYYY-MM-DD` – required cutoff for template structures; keeps runs reproducible.
-
-
-
----
-
-## How to Cite
+## How to cite
-If AlphaPulldown contributed significantly to your research, please cite [the corresponding publication](https://doi.org/10.1093/bioinformatics/btaf115) in *Bioinformatics*:
+If AlphaPulldown (or this workflow) contributed to your research, please cite [Molodenskiy et al., 2025](https://doi.org/10.1093/bioinformatics/btaf115):
```bibtex
@article{Molodenskiy2025AlphaPulldown2,
diff --git a/alphapulldown/__init__.py b/alphapulldown/__init__.py
index 892994aa..43ce13db 100755
--- a/alphapulldown/__init__.py
+++ b/alphapulldown/__init__.py
@@ -1 +1 @@
-__version__ = "2.8.0"
+__version__ = "2.9.0"
diff --git a/alphapulldown/af2_feature_finalizer.py b/alphapulldown/af2_feature_finalizer.py
new file mode 100644
index 00000000..2319a2df
--- /dev/null
+++ b/alphapulldown/af2_feature_finalizer.py
@@ -0,0 +1,461 @@
+"""AlphaFold 2 features from a local MMseqs2 MSA bundle.
+
+The search stage (``feature_batch.MsaBatch``) is backend-neutral: it writes one MSA
+bundle per chain. This module turns a bundle into what the AlphaFold 2 backend
+reads -- a pickled ``alphapulldown.objects.MonomericObject`` -- building it the way
+``alphafold.data.pipeline.DataPipeline.process`` builds features from jackhmmer,
+so the result drops into existing AlphaFold 2 inference unchanged.
+
+What is reproduced from native AlphaFold 2:
+
+- per-database caps, counting the query row as AlphaFold 2 does: uniref90 at
+ 10 000 and mgnify at 501, small BFD uncapped (``pipeline.py``: jackhmmer's
+ ``max_sto_sequences``, which stops at that many sequence names, query first)
+- merge order uniref90, BFD, MGnify (``pipeline.py:265``). Row order matters:
+ AlphaFold 2 deduplicates in that order and samples its MSA from the top
+- templates searched from uniref90 ALONE, never from the merged alignment
+- the paired UniProt alignment truncated to 50 000 rows, as
+ ``MonomericObject.all_seq_msa_features`` does, and exposed as ``*_all_seq``
+
+Where it cannot be exact, and why that is acceptable:
+
+- The database recipe is uniref90, MGnify, small BFD and UniProt -- AlphaFold 2's
+ ``reduced_dbs`` set. There is no BFD/UniRef30 HHblits arm, so these features are
+ comparable to ``--db_preset=reduced_dbs``, not ``full_dbs``.
+- The bundle deduplicated rows across databases before this module sees them, so
+ the caps apply to each database's rows after that deduplication. Native
+ AlphaFold 2 caps raw hits first. The mgnify cap can therefore admit a few more
+ unique rows than native, and a sequence both MGnify and small BFD found counts
+ against MGnify's cap. Both effects touch only rows duplicated across databases.
+- The template profile is built from the uniref90 A3M with insertions removed.
+ jackhmmer's Stockholm carries insert columns; A3M insertions are per row and not
+ aligned to each other, so they cannot be turned back into columns faithfully.
+ Match columns -- which decide the profile's states -- are identical.
+
+And one deliberate improvement: UniProt accession identifiers are filled from the
+alignment headers, where native features leave them empty. Nothing here ever
+queries UniProt over the network; see :func:`_no_network`.
+"""
+
+from __future__ import annotations
+
+import copy
+import dataclasses
+from datetime import date
+import json
+import lzma
+import os
+from pathlib import Path
+import pickle
+import tempfile
+from typing import Any, Mapping, Sequence
+
+from alphapulldown.feature_batch import (
+ PROTEIN,
+ UNPAIRED_DATABASE_NAMES,
+ FeatureArtifact,
+ FeatureBatchResult,
+ FeatureFailure,
+ FeatureRequest,
+ SearchedMsas,
+ _fasta_records,
+ _validate_feature_requests,
+ read_msa_bundle,
+ searched_msas_from_payload,
+)
+
+
+# AlphaFold 2's own caps, counting the query row the way it does.
+AF2_MAX_SEQUENCES = {"uniref90": 10_000, "mgnify": 501}
+# pipeline.py:265 -- make_msa_features((uniref90_msa, bfd_msa, mgnify_msa)).
+AF2_MERGE_ORDER = ("uniref90", "small_bfd", "mgnify")
+# MonomericObject.all_seq_msa_features truncates the UniProt alignment here.
+PAIRED_MAX_SEQUENCES = 50_000
+TEMPLATE_SEARCHERS = ("hmmsearch", "hhsearch")
+# Bump when the construction below changes, so features an older construction
+# built are regenerated rather than reused.
+_AF2_FEATURE_SCHEMA = 1
+
+
+@dataclasses.dataclass(frozen=True, slots=True)
+class Af2MsaInputs:
+ """The three alignments AlphaFold 2 features are built from."""
+
+ # Becomes msa / deletion_matrix_int: all three databases, capped, in AF2 order.
+ main_a3m: str
+ # uniref90 alone: what the template profile is built from.
+ template_a3m: str
+ # UniProt: becomes *_all_seq, which pairs chains by species.
+ paired_a3m: str
+
+
+def _a3m(records: Sequence[tuple[str, str]]) -> str:
+ return "".join(f">{description}\n{sequence}\n" for description, sequence in records)
+
+
+def af2_msa_inputs(msas: SearchedMsas) -> Af2MsaInputs:
+ """Cut a bundle's alignments into the shapes native AlphaFold 2 would have."""
+ query, by_database = msas.rows_by_database()
+ missing = [name for name in UNPAIRED_DATABASE_NAMES if name not in by_database]
+ if missing:
+ raise ValueError(
+ "MSA bundle does not say which rows came from "
+ + ", ".join(missing)
+ + "; AlphaFold 2 needs each database's rows separately"
+ )
+
+ def capped(name: str) -> list[tuple[str, str]]:
+ rows = by_database[name]
+ cap = AF2_MAX_SEQUENCES.get(name)
+ # AlphaFold 2 counts the query toward its cap, so a cap of N keeps N - 1 hits.
+ return rows if cap is None else rows[: cap - 1]
+
+ blocks = {name: capped(name) for name in AF2_MERGE_ORDER}
+ paired_records = _fasta_records(msas.paired)
+ if not paired_records:
+ raise ValueError(
+ "MSA bundle has no paired UniProt alignment; AlphaFold 2 multimer "
+ "pairing needs one"
+ )
+ return Af2MsaInputs(
+ main_a3m=_a3m(
+ [query, *(row for name in AF2_MERGE_ORDER for row in blocks[name])]
+ ),
+ template_a3m=_a3m([query, *blocks["uniref90"]]),
+ paired_a3m=_a3m(paired_records[:PAIRED_MAX_SEQUENCES]),
+ )
+
+
+def _no_network(accessions: Sequence[str]) -> dict[str, str]:
+ """Resolve nothing, rather than ask UniProt.
+
+ The shared identifier helper falls back to UniProt REST lookups for
+ accessions whose header carries no species. A local batch of thousands of
+ chains must not start doing that unannounced -- and it has no need to: the
+ UniProt database's canonical ``sp|ACC|NAME_SPECIES`` headers carry the species
+ already, and AlphaFold 2 reads it from them directly. Anything unparseable
+ stays unresolved, exactly as it would in native features.
+ """
+ del accessions
+ return {}
+
+
+def _offline_accessions(a3m: str, *, rows: int):
+ """Accession per alignment row, deduplicated exactly as make_msa_features is."""
+ from alphapulldown.utils.mmseqs_species_identifiers import (
+ build_mmseq_identifier_features,
+ )
+
+ identifiers = build_mmseq_identifier_features(
+ a3m, species_resolver=_no_network, expected_rows=rows
+ )
+ accessions = identifiers["msa_uniprot_accession_identifiers"]
+ if len(accessions) != rows:
+ raise ValueError(
+ f"accession identifiers cover {len(accessions)} rows but the MSA has "
+ f"{rows}; they would index the wrong sequences"
+ )
+ return accessions
+
+
+@dataclasses.dataclass(frozen=True, slots=True)
+class Af2TemplateStackSettings:
+ """Everything the AlphaFold 2 template searcher and featurizer are built from.
+
+ Explicit values rather than global flags, so a caller states what it uses
+ instead of depending on some earlier call having rewritten FLAGS.
+ """
+
+ template_mmcif_dir: str
+ max_template_date: str
+ kalign_binary_path: str
+ obsolete_pdbs_path: str | None = None
+ use_hhsearch: bool = False
+ # hmmsearch against PDB seqres, the default.
+ hmmsearch_binary_path: str | None = None
+ hmmbuild_binary_path: str | None = None
+ pdb_seqres_database_path: str | None = None
+ # hhsearch against PDB70, under --use_hhsearch.
+ hhsearch_binary_path: str | None = None
+ pdb70_database_path: str | None = None
+
+ @property
+ def searcher_name(self) -> str:
+ return "hhsearch" if self.use_hhsearch else "hmmsearch"
+
+
+def build_af2_template_stack(settings: Af2TemplateStackSettings):
+ """The AlphaFold 2 template searcher and featurizer, as native features use."""
+ from alphafold.data import templates
+ from alphafold.data.tools import hhsearch, hmmsearch
+
+ if settings.use_hhsearch:
+ searcher = hhsearch.HHSearch(
+ binary_path=settings.hhsearch_binary_path,
+ databases=[settings.pdb70_database_path],
+ )
+ featurizer = templates.HhsearchHitFeaturizer(
+ mmcif_dir=settings.template_mmcif_dir,
+ max_template_date=settings.max_template_date,
+ max_hits=20,
+ kalign_binary_path=settings.kalign_binary_path,
+ release_dates_path=None,
+ obsolete_pdbs_path=settings.obsolete_pdbs_path,
+ )
+ return searcher, featurizer
+ featurizer = templates.HmmsearchHitFeaturizer(
+ mmcif_dir=settings.template_mmcif_dir,
+ max_template_date=settings.max_template_date,
+ max_hits=20,
+ kalign_binary_path=settings.kalign_binary_path,
+ obsolete_pdbs_path=settings.obsolete_pdbs_path,
+ release_dates_path=None,
+ )
+ searcher = hmmsearch.Hmmsearch(
+ binary_path=settings.hmmsearch_binary_path,
+ hmmbuild_binary_path=settings.hmmbuild_binary_path,
+ database_path=settings.pdb_seqres_database_path,
+ )
+ return searcher, featurizer
+
+
+@dataclasses.dataclass(frozen=True, slots=True)
+class Af2FeatureFinalizationSettings:
+ """CPU AlphaFold 2 finalization settings and complete template provenance."""
+
+ output_dir: Path
+ msa_input_dir: Path
+ max_template_date: str
+ template_seqres_database_id: str | None
+ template_mmcif_database_id: str
+ # hmmsearch against PDB seqres, or hhsearch against PDB70 (--use_hhsearch).
+ # The two find different templates, so which one ran is part of the identity.
+ template_searcher: str = "hmmsearch"
+ template_pdb70_database_id: str | None = None
+ compress: bool = False
+ base_metadata: Mapping[str, Any] = dataclasses.field(default_factory=dict)
+
+
+class Af2FeatureFinalizer:
+ """Turn persisted MSA bundles into AlphaFold 2 feature pickles on CPU."""
+
+ def __init__(
+ self,
+ *,
+ settings: Af2FeatureFinalizationSettings,
+ template_searcher: Any,
+ template_featurizer: Any,
+ ):
+ if not isinstance(settings, Af2FeatureFinalizationSettings):
+ raise TypeError(
+ "Af2FeatureFinalizer settings must be Af2FeatureFinalizationSettings"
+ )
+ self._settings = settings
+ self._template_searcher = template_searcher
+ self._template_featurizer = template_featurizer
+
+ def generate(self, requests: Sequence[FeatureRequest]) -> FeatureBatchResult:
+ requests = tuple(requests)
+ self._validate(requests)
+ self._settings.output_dir.mkdir(parents=True, exist_ok=True)
+ written = []
+ reused = []
+ failures = []
+ for request in requests:
+ try:
+ if request.molecule_type != PROTEIN:
+ raise ValueError(
+ f"{request.name!r} is {request.molecule_type}: AlphaFold 2 "
+ "has no MSA features for anything but protein chains"
+ )
+ payload = read_msa_bundle(
+ self._settings.msa_input_dir, request, require_row_spans=True
+ )
+ msas = searched_msas_from_payload(payload)
+ provenance = self._provenance(payload)
+ cached = self._read_matching_artifact(request, provenance)
+ if cached is not None:
+ reused.append(FeatureArtifact(name=request.name, path=cached))
+ continue
+ feature_dict = self._feature_dict(request, af2_msa_inputs(msas))
+ path = self._publish(request, feature_dict, provenance)
+ written.append(FeatureArtifact(name=request.name, path=path))
+ except Exception as exc:
+ failures.append(FeatureFailure(name=request.name, error=str(exc)))
+ return FeatureBatchResult(
+ written=tuple(written), reused=tuple(reused), failures=tuple(failures)
+ )
+
+ def _validate(self, requests: Sequence[FeatureRequest]) -> None:
+ _validate_feature_requests(requests)
+ if self._settings.template_searcher not in TEMPLATE_SEARCHERS:
+ raise ValueError(
+ "template_searcher must be one of "
+ f"{', '.join(TEMPLATE_SEARCHERS)}, not "
+ f"{self._settings.template_searcher!r}"
+ )
+ for field_name in (
+ "max_template_date",
+ "template_mmcif_database_id",
+ "template_pdb70_database_id" if self._settings.template_searcher == "hhsearch"
+ else "template_seqres_database_id",
+ ):
+ value = getattr(self._settings, field_name)
+ if value is None or not str(value).strip():
+ raise ValueError(f"{field_name} requires a non-empty value")
+
+ def _feature_dict(
+ self, request: FeatureRequest, inputs: Af2MsaInputs
+ ) -> dict[str, Any]:
+ from alphafold.data import msa_pairing, parsers, pipeline
+
+ from alphapulldown.objects import add_template_feature_defaults
+ from alphapulldown.utils.template_reuse import (
+ search_templates,
+ stockholm_from_a3m,
+ )
+
+ sequence = request.sequence
+ features = dict(
+ pipeline.make_sequence_features(
+ sequence=sequence, description=request.name, num_res=len(sequence)
+ )
+ )
+
+ main = pipeline.make_msa_features([parsers.parse_a3m(inputs.main_a3m)])
+ main["msa_uniprot_accession_identifiers"] = _offline_accessions(
+ inputs.main_a3m, rows=main["msa"].shape[0]
+ )
+ features.update(main)
+
+ features.update(
+ search_templates(
+ self._template_searcher,
+ self._template_featurizer,
+ query_sequence=sequence,
+ stockholm_msa=stockholm_from_a3m(inputs.template_a3m),
+ )
+ )
+
+ # The paired alignment is searched separately against UniProt, whose
+ # headers carry the species AlphaFold 2 pairs chains by. It is not a copy
+ # of the unpaired features, which is what the remote path makes do with.
+ paired = pipeline.make_msa_features([parsers.parse_a3m(inputs.paired_a3m)])
+ paired["msa_uniprot_accession_identifiers"] = _offline_accessions(
+ inputs.paired_a3m, rows=paired["msa"].shape[0]
+ )
+ pairable = msa_pairing.MSA_FEATURES + (
+ "msa_species_identifiers",
+ "msa_uniprot_accession_identifiers",
+ )
+ features.update(
+ {f"{key}_all_seq": value for key, value in paired.items() if key in pairable}
+ )
+
+ add_template_feature_defaults(features, sequence)
+ return features
+
+ def _provenance(self, msa_payload: Mapping[str, Any]) -> dict[str, Any]:
+ """Everything that decides the pickle's content, for cache reuse."""
+ return {
+ "af2_feature_schema": _AF2_FEATURE_SCHEMA,
+ "mmseqs2": msa_payload["provenance"],
+ "af2_templates": self._template_signature(),
+ }
+
+ def _template_signature(self) -> dict[str, Any]:
+ # Software versions, not base_metadata's wall-clock date, which would miss
+ # on every run -- the same choice the AlphaFold 3 finalizer makes.
+ database = (
+ {"pdb70_database_id": self._settings.template_pdb70_database_id}
+ if self._settings.template_searcher == "hhsearch"
+ else {"pdb_seqres_database_id": self._settings.template_seqres_database_id}
+ )
+ return {
+ "max_template_date": self._settings.max_template_date,
+ **database,
+ "mmcif_database_id": self._settings.template_mmcif_database_id,
+ "template_searcher": self._settings.template_searcher,
+ "software": dict(self._settings.base_metadata.get("software", {})),
+ }
+
+ def _read_matching_artifact(
+ self, request: FeatureRequest, provenance: Mapping[str, Any]
+ ) -> Path | None:
+ from alphapulldown.utils.lightweight_pickles import load_lightweight_pickle
+
+ path = self._artifact_path(request.name)
+ if not path.exists():
+ return None
+ try:
+ monomer = load_lightweight_pickle(path)
+ except Exception:
+ return None
+ if getattr(monomer, "sequence", None) != request.sequence:
+ return None
+ if getattr(monomer, "local_msa_provenance", None) != provenance:
+ return None
+ return path
+
+ def _publish(
+ self,
+ request: FeatureRequest,
+ feature_dict: dict[str, Any],
+ provenance: Mapping[str, Any],
+ ) -> Path:
+ from alphapulldown.objects import MonomericObject
+
+ monomer = MonomericObject(request.name, request.sequence)
+ monomer.feature_dict = feature_dict
+ monomer.skip_msa = False
+ # Carried on the object so a later run can tell, from the pickle alone,
+ # whether it was built from the same search and template settings.
+ monomer.local_msa_provenance = dict(provenance)
+
+ metadata = copy.deepcopy(dict(self._settings.base_metadata))
+ other = metadata.setdefault("other", {})
+ # The same keys the AlphaFold 3 finalizer writes, so one reader serves both.
+ # The search mode, cpu or gpu, is inside the provenance.
+ other["msa_backend"] = "mmseqs2-gpu"
+ other["mmseqs2_gpu"] = provenance["mmseqs2"]
+ other["af2_templates"] = provenance["af2_templates"]
+ metadata_suffix = ".json.xz" if self._settings.compress else ".json"
+ _write_atomic(
+ self._settings.output_dir
+ / f"{request.name}_feature_metadata_{date.today()}{metadata_suffix}",
+ json.dumps(metadata).encode("utf-8"),
+ )
+ # The pickle is the output a workflow waits for, so it is published last:
+ # its existence implies its metadata exists too.
+ path = self._artifact_path(request.name)
+ _write_atomic(path, pickle.dumps(monomer))
+ return path
+
+ def _artifact_path(self, name: str) -> Path:
+ suffix = ".pkl.xz" if self._settings.compress else ".pkl"
+ return self._settings.output_dir / f"{name}{suffix}"
+
+
+def _write_atomic(path: Path, content: bytes) -> None:
+ """Publish a file whole or not at all, compressed when its name says .xz."""
+ descriptor, temporary_name = tempfile.mkstemp(
+ prefix=f".{path.name}.", suffix=".tmp", dir=path.parent
+ )
+ temporary_path = Path(temporary_name)
+ try:
+ with os.fdopen(descriptor, "wb") as raw_handle:
+ if path.suffix == ".xz":
+ with lzma.open(raw_handle, "wb") as handle:
+ handle.write(content)
+ else:
+ raw_handle.write(content)
+ raw_handle.flush()
+ os.fsync(raw_handle.fileno())
+ os.replace(temporary_path, path)
+ directory_fd = os.open(path.parent, os.O_RDONLY)
+ try:
+ os.fsync(directory_fd)
+ finally:
+ os.close(directory_fd)
+ finally:
+ temporary_path.unlink(missing_ok=True)
diff --git a/alphapulldown/feature_batch.py b/alphapulldown/feature_batch.py
index 32fbdb2e..495c75a6 100644
--- a/alphapulldown/feature_batch.py
+++ b/alphapulldown/feature_batch.py
@@ -19,6 +19,11 @@
embed_metadata_in_af3_json,
extract_metadata_from_af3_json,
)
+from alphapulldown.utils.msa_formats import (
+ StitchMismatch,
+ stitch_headers_and_insertions,
+ strip_insertions,
+)
PROTEIN = "protein"
@@ -64,6 +69,12 @@
# future GPU-capable nucleotide search does not silently reuse these bundles.
NUCLEOTIDE_SEARCH_MODE = "cpu"
+# How the alignment text was produced, recorded in every bundle's provenance.
+# Bundles written before insertions were recovered came from mode 2 alone and carry
+# none -- 81.7% of small_bfd hits and 86.4% of uniprot hits lost theirs, measured on
+# a real 586-residue query -- so they must never satisfy a request made now.
+_MSA_FORMAT = {"headers": "result2msa mode 2", "sequences": "result2msa mode 5"}
+
def _describe_exit(returncode) -> str:
"""Say what an MMseqs2 exit code means, especially when it died on a signal.
@@ -283,6 +294,39 @@ class MsaFailure:
error: str
+@dataclasses.dataclass(frozen=True, slots=True)
+class SearchedMsas:
+ """What one search produced for one sequence, before it becomes a bundle."""
+
+ unpaired: str
+ paired: str
+ # How many rows of ``unpaired`` each database contributed, in merge order and
+ # after deduplication. The query row belongs to none of them. AlphaFold 2 builds
+ # its template profile from uniref90 ALONE and caps each database separately, so
+ # the merged alignment is unusable to it unless these boundaries are kept.
+ unpaired_rows: tuple[tuple[str, int], ...] = ()
+
+ def rows_by_database(
+ self,
+ ) -> tuple[tuple[str, str], dict[str, list[tuple[str, str]]]]:
+ """The query record, and each database's own rows, recovered from the spans."""
+ records = _fasta_records(self.unpaired)
+ if not records:
+ raise ValueError("MSA bundle has an empty unpaired alignment")
+ query, hits = records[0], records[1:]
+ by_database: dict[str, list[tuple[str, str]]] = {}
+ start = 0
+ for name, count in self.unpaired_rows:
+ by_database[name] = hits[start : start + count]
+ start += count
+ if start != len(hits):
+ raise ValueError(
+ f"MSA bundle row spans cover {start} rows but the alignment has "
+ f"{len(hits)} besides the query"
+ )
+ return query, by_database
+
+
@dataclasses.dataclass(frozen=True, slots=True)
class MsaBatchResult:
written: tuple[MsaArtifact, ...]
@@ -371,7 +415,19 @@ def result_to_msa(
database: DatabaseSpec,
result_db: Path,
msa_db: Path,
- ) -> None: ...
+ ) -> None:
+ """Format the hits with their full database headers and no insertions."""
+ ...
+
+ def result_to_a3m(
+ self,
+ query_db: Path,
+ database: DatabaseSpec,
+ result_db: Path,
+ msa_db: Path,
+ ) -> None:
+ """Format the same hits as A3M: insertions kept, headers cut to one token."""
+ ...
def unpack_msa(self, query_db: Path, msa_db: Path, output_dir: Path) -> None: ...
@@ -379,9 +435,26 @@ def unpack_msa(self, query_db: Path, msa_db: Path, output_dir: Path) -> None: ..
class SubprocessMmseqsProcess:
"""Production adapter for one local MMseqs2 executable."""
- def __init__(self, binary_path: str | Path, *, gpu: bool = True):
+ def __init__(
+ self,
+ binary_path: str | Path,
+ *,
+ gpu: bool = True,
+ db_load_mode: int | None = None,
+ ):
self._binary_path = str(binary_path)
self._gpu = gpu
+ # How MMseqs2 reads the target database (0 auto, 1 fread, 2 mmap,
+ # 3 mmap+touch). Deliberately a process-level setting rather than part of
+ # MsaBatchSettings: it changes memory behaviour and nothing else, so it
+ # must never reach the cache signature. Two runs that differ only here
+ # produce the same alignment and must keep reusing each other's bundles.
+ self._db_load_mode = db_load_mode
+
+ def _db_load_mode_option(self) -> tuple[str, ...]:
+ if self._db_load_mode is None:
+ return ()
+ return ("--db-load-mode", str(self._db_load_mode))
def _run(self, command: Sequence[str]) -> str:
try:
@@ -449,8 +522,14 @@ def search(
"1" if gpu else "0",
)
+ (
+ # Iterative profile search is protein-only: measured on the pinned
+ # build, --num-iterations 3 on a nucleotide search exits 1 ("Alignment
+ # died", or "no diagonal information" on a one-sequence database).
+ # RNA provenance correctly never records it.
("--num-iterations", str(settings.num_iterations))
- if settings.num_iterations and settings.num_iterations > 1
+ if settings.num_iterations
+ and settings.num_iterations > 1
+ and not nucleotide
else ()
)
+ (("--search-type", "3") if nucleotide else ())
@@ -459,6 +538,7 @@ def search(
if settings.split_memory_limit
else ()
)
+ + self._db_load_mode_option()
)
def result_to_msa(
@@ -478,6 +558,31 @@ def result_to_msa(
"--msa-format-mode",
"2",
)
+ + self._db_load_mode_option()
+ )
+
+ def result_to_a3m(
+ self,
+ query_db: Path,
+ database: DatabaseSpec,
+ result_db: Path,
+ msa_db: Path,
+ ) -> None:
+ # Mode 5 is the only format that keeps insertions, and it keeps nothing of
+ # the header but the database key -- so it is run alongside mode 2, not
+ # instead of it. Measured at 2 s against a 947 s search on small_bfd and
+ # 13 s against 3739 s on uniprot, roughly 16 ms per hit.
+ self._run(
+ (
+ "result2msa",
+ str(query_db),
+ str(database.path),
+ str(result_db),
+ str(msa_db),
+ "--msa-format-mode",
+ "5",
+ )
+ + self._db_load_mode_option()
)
def unpack_msa(self, query_db: Path, msa_db: Path, output_dir: Path) -> None:
@@ -531,7 +636,7 @@ def generate(self, requests: Sequence[FeatureRequest]) -> MsaBatchResult:
missing_requests = []
# Keyed by molecule type as well as sequence: the same letters searched as a
# protein and as RNA are two different searches with two different answers.
- msa_by_sequence: dict[tuple[str, str], tuple[str, str]] = {}
+ msa_by_sequence: dict[tuple[str, str], SearchedMsas] = {}
for request in requests:
cached = self._read_matching_msa(request)
if cached is None:
@@ -540,8 +645,7 @@ def generate(self, requests: Sequence[FeatureRequest]) -> MsaBatchResult:
path, payload = cached
reused.append(MsaArtifact(name=request.name, path=path))
msa_by_sequence.setdefault(
- _request_key(request),
- (payload["unpairedMsa"], payload["pairedMsa"]),
+ _request_key(request), searched_msas_from_payload(payload)
)
sequence_to_requests: dict[tuple[str, str], list[FeatureRequest]] = {}
@@ -557,7 +661,7 @@ def generate(self, requests: Sequence[FeatureRequest]) -> MsaBatchResult:
continue
for request in matching_requests:
try:
- payload = self._msa_payload(request, *cached_msas)
+ payload = self._msa_payload(request, cached_msas)
path = self._msa_path(request.name)
_write_atomic(path, payload)
written.append(MsaArtifact(name=request.name, path=path))
@@ -593,7 +697,7 @@ def generate(self, requests: Sequence[FeatureRequest]) -> MsaBatchResult:
for sequence, msas in chunk_msas.items():
for request in sequence_to_requests[(molecule_type, sequence)]:
try:
- payload = self._msa_payload(request, *msas)
+ payload = self._msa_payload(request, msas)
path = self._msa_path(request.name)
_write_atomic(path, payload)
written.append(MsaArtifact(name=request.name, path=path))
@@ -667,6 +771,10 @@ def _read_matching_msa(
payload.get("pairedMsa"), str
):
return None
+ # Raises on a bundle whose row spans are missing or do not add up, so a
+ # damaged one is re-searched instead of handed on to a consumer that
+ # would slice it at the wrong rows.
+ searched_msas_from_payload(payload)
return path, payload
except (
KeyError,
@@ -766,7 +874,7 @@ def _pack(self, sequences: Sequence[str]) -> tuple[tuple[str, ...], ...]:
def _search_chunk(
self, sequences: Sequence[str], molecule_type: str = PROTEIN
- ) -> dict[str, tuple[str, str]]:
+ ) -> dict[str, SearchedMsas]:
unpaired_databases, paired_database = self._databases(molecule_type)
with tempfile.TemporaryDirectory(
prefix="alphapulldown_mmseqs_", dir=self._settings.temp_dir
@@ -801,24 +909,33 @@ def _search_chunk(
result_db = database_root / "result_db"
work_dir = database_root / "work"
work_dir.mkdir()
- msa_db = database_root / "msa_db"
- output_dir = database_root / "a3m"
- output_dir.mkdir()
self._mmseqs.search(
query_db, database, result_db, work_dir, self._settings
)
- self._mmseqs.result_to_msa(query_db, database, result_db, msa_db)
- self._mmseqs.unpack_msa(query_db, msa_db, output_dir)
+ # One search, formatted twice: headers from one pass, insertions
+ # from the other. See msa_formats for why neither alone will do.
+ headers_db = database_root / "headers_db"
+ headers_dir = database_root / "headers"
+ headers_dir.mkdir()
+ self._mmseqs.result_to_msa(query_db, database, result_db, headers_db)
+ self._mmseqs.unpack_msa(query_db, headers_db, headers_dir)
+ insertions_db = database_root / "insertions_db"
+ insertions_dir = database_root / "insertions"
+ insertions_dir.mkdir()
+ self._mmseqs.result_to_a3m(
+ query_db, database, result_db, insertions_db
+ )
+ self._mmseqs.unpack_msa(query_db, insertions_db, insertions_dir)
by_database[database.name] = self._read_results(
- query_db, output_dir, query_ids, molecule_type
+ query_db, headers_dir, insertions_dir, query_ids, molecule_type
)
results = {}
for query_id, sequence in query_ids.items():
- unpaired = _merge_a3ms(
+ unpaired, unpaired_rows = _merge_a3ms(
sequence,
[
- by_database[database.name][query_id]
+ (database.name, by_database[database.name][query_id])
for database in unpaired_databases
],
)
@@ -829,13 +946,16 @@ def _search_chunk(
if paired_database is not None
else ""
)
- results[sequence] = (unpaired, paired)
+ results[sequence] = SearchedMsas(
+ unpaired=unpaired, paired=paired, unpaired_rows=unpaired_rows
+ )
return results
@staticmethod
def _read_results(
query_db: Path,
- output_dir: Path,
+ headers_dir: Path,
+ insertions_dir: Path,
query_ids: Mapping[str, str],
molecule_type: str = PROTEIN,
) -> dict[str, str]:
@@ -851,10 +971,7 @@ def _read_results(
str(index): query_id for index, query_id in enumerate(query_ids)
}
- results = {}
- for index, query_id in index_to_query.items():
- if query_id not in query_ids:
- continue
+ def unpacked_records(output_dir: Path, index: str, query_id: str):
candidates = (
output_dir / f"{index}.fasta",
output_dir / f"{index}.a3m",
@@ -868,14 +985,29 @@ def _read_results(
"MMseqs2 unpackdb did not produce an alignment for "
f"{query_id!r} in {output_dir.parent.name!r}"
)
- aligned_fasta = result_path.read_text(encoding="utf-8")
- if not _fasta_records(aligned_fasta):
+ records = _fasta_records(result_path.read_text(encoding="utf-8"))
+ if not records:
raise RuntimeError(
"MMseqs2 unpackdb produced no FASTA records for "
f"{query_id!r} in {output_dir.parent.name!r}"
)
- results[query_id] = _aligned_fasta_to_a3m(
- aligned_fasta, query_ids[query_id], molecule_type
+ return records
+
+ results = {}
+ for index, query_id in index_to_query.items():
+ if query_id not in query_ids:
+ continue
+ try:
+ stitched = stitch_headers_and_insertions(
+ unpacked_records(headers_dir, index, query_id),
+ unpacked_records(insertions_dir, index, query_id),
+ )
+ except StitchMismatch as exc:
+ raise RuntimeError(
+ f"{query_id!r} in {headers_dir.parent.name!r}: {exc}"
+ ) from exc
+ results[query_id] = _stitched_to_a3m(
+ stitched, query_ids[query_id], molecule_type
)
missing_queries = set(query_ids) - set(results)
if missing_queries:
@@ -886,16 +1018,19 @@ def _read_results(
return results
def _msa_payload(
- self, request: FeatureRequest, unpaired_msa: str, paired_msa: str
+ self, request: FeatureRequest, msas: SearchedMsas
) -> dict[str, Any]:
payload = {
- "schemaVersion": 2,
+ "schemaVersion": 3,
"name": request.name,
"sequence": request.sequence,
- "unpairedMsa": unpaired_msa,
- "pairedMsa": paired_msa,
- "unpairedDepth": _msa_depth(unpaired_msa),
- "pairedDepth": _msa_depth(paired_msa),
+ "unpairedMsa": msas.unpaired,
+ "pairedMsa": msas.paired,
+ "unpairedDepth": _msa_depth(msas.unpaired),
+ "pairedDepth": _msa_depth(msas.paired),
+ "unpairedDatabaseRows": [
+ {"name": name, "rows": rows} for name, rows in msas.unpaired_rows
+ ],
"provenance": self._cache_signature(request.molecule_type),
}
# Only non-protein bundles record their molecule type, so a protein bundle is
@@ -920,10 +1055,11 @@ def database_value(database: DatabaseSpec) -> dict[str, Any]:
if molecule_type == RNA:
return {
- "schema_version": 1,
+ "schema_version": 2,
"molecule_type": RNA,
"mmseqs_identity": self._process_identity(),
"search_mode": NUCLEOTIDE_SEARCH_MODE,
+ "msa_format": _MSA_FORMAT,
"e_value": self._settings.rna_e_value,
"unpaired_databases": [
database_value(database)
@@ -932,9 +1068,10 @@ def database_value(database: DatabaseSpec) -> dict[str, Any]:
}
signature = {
- "schema_version": 4,
+ "schema_version": 5,
"mmseqs_identity": self._process_identity(),
"search_mode": self._search_mode(),
+ "msa_format": _MSA_FORMAT,
"e_value": self._settings.e_value,
"unpaired_databases": [
database_value(database)
@@ -1029,44 +1166,7 @@ def _validate(self, requests: Sequence[FeatureRequest]) -> None:
raise ValueError(f"{field_name} requires a non-empty value")
def _read_msa(self, request: FeatureRequest) -> dict[str, Any]:
- path = self._settings.msa_input_dir / f"{request.name}_mmseqs_msa.json"
- try:
- encoded = path.read_text(encoding="utf-8")
- except OSError as exc:
- raise RuntimeError(f"Cannot read MMseqs2 MSA bundle {path}: {exc}") from exc
- try:
- try:
- payload = json.loads(encoded)
- except (TypeError, ValueError, json.JSONDecodeError) as exc:
- raise _InvalidMsaBundle(
- f"Cannot parse MMseqs2 MSA bundle {path}: {exc}"
- ) from exc
- if not isinstance(payload, dict):
- raise _InvalidMsaBundle(
- f"MMseqs2 MSA bundle {path} is not a JSON object"
- )
- if payload.get("sequence") != request.sequence:
- raise _InvalidMsaBundle(
- f"MMseqs2 MSA bundle sequence does not match {request.name!r}"
- )
- if payload.get("moleculeType", PROTEIN) != request.molecule_type:
- raise _InvalidMsaBundle(
- "MMseqs2 MSA bundle molecule type does not match "
- f"{request.name!r}"
- )
- if not isinstance(payload.get("provenance"), dict):
- raise _InvalidMsaBundle(
- f"MMseqs2 MSA bundle lacks provenance for {request.name!r}"
- )
- for key in ("unpairedMsa", "pairedMsa"):
- if not isinstance(payload.get(key), str):
- raise _InvalidMsaBundle(
- f"MMseqs2 MSA bundle lacks {key} for {request.name!r}"
- )
- return payload
- except _InvalidMsaBundle:
- path.unlink(missing_ok=True)
- raise
+ return read_msa_bundle(self._settings.msa_input_dir, request)
def _read_matching_artifact(
self, request: FeatureRequest, msa_payload: Mapping[str, Any]
@@ -1306,33 +1406,40 @@ def _transcribe(sequence: str) -> str:
return sequence.replace("T", "U").replace("t", "u")
-def _aligned_fasta_to_a3m(
- aligned_fasta: str, query_sequence: str, molecule_type: str = PROTEIN
+def _stitched_to_a3m(
+ records: Sequence[tuple[str, str]],
+ query_sequence: str,
+ molecule_type: str = PROTEIN,
) -> str:
- """Remove query-gap columns while retaining insertions and full headers."""
- from alphafold3.cpp import msa_conversion
-
- records = _fasta_records(aligned_fasta)
+ """Validate stitched A3M records against the query and write them out.
+
+ The mode-5 sequences are already A3M against the gapless query, so nothing is
+ rewritten. What is checked is that every row spans exactly the query: a row
+ whose match columns number anything else would silently shift every residue
+ after the discrepancy once AlphaFold reads it as a table. The stitch already
+ implies this -- mode 2 rows equal mode 5 rows minus insertions -- but a
+ malformed row should fail here with the query named, not deep in a parser.
+ """
if not records:
- raise ValueError("MMseqs2 aligned FASTA contains no records")
- query_alignment = records[0][1]
+ raise ValueError("MMseqs2 alignment contains no records")
normalise = _transcribe if molecule_type == RNA else (lambda sequence: sequence)
- if normalise(
- query_alignment.replace("-", "").replace(".", "").upper()
- ) != normalise(query_sequence.upper()):
- raise ValueError(
- "MMseqs2 aligned FASTA query does not match its input sequence"
- )
+ query_row = strip_insertions(records[0][1])
+ if normalise(query_row.replace("-", "").upper()) != normalise(
+ query_sequence.upper()
+ ):
+ raise ValueError("MMseqs2 alignment query does not match its input sequence")
converted = []
for description, sequence in records:
- a3m_sequence = msa_conversion.align_sequence_to_gapless_query(
- sequence=sequence,
- query_sequence=query_alignment,
- ).replace(".", "")
+ if len(strip_insertions(sequence)) != len(query_sequence):
+ raise ValueError(
+ f"MMseqs2 row {description.split()[0]!r} spans "
+ f"{len(strip_insertions(sequence))} query positions, not "
+ f"{len(query_sequence)}"
+ )
if molecule_type == RNA:
- a3m_sequence = _transcribe(a3m_sequence)
- converted.append(f">{description}\n{a3m_sequence}\n")
+ sequence = _transcribe(sequence)
+ converted.append(f">{description}\n{sequence}\n")
return "".join(converted)
@@ -1344,13 +1451,143 @@ def _normalise_query(a3m: str, query_sequence: str) -> str:
return "".join(f">{description}\n{sequence}\n" for description, sequence in records)
-def _merge_a3ms(query_sequence: str, a3ms: Sequence[str]) -> str:
+def _merge_a3ms(
+ query_sequence: str, a3ms: Sequence[tuple[str, str]]
+) -> tuple[str, tuple[tuple[str, int], ...]]:
+ """Merge per-database A3Ms in order, and say how many rows each contributed.
+
+ Rows are deduplicated on their aligned residues with the insertions removed.
+ That is the key this stage used before insertions were recovered, when the two
+ were the same string, so a merged alignment keeps exactly the rows it kept
+ then and only their content grows. Keying on the full row instead would keep a
+ second copy of every hit that two databases aligned with different insertions.
+
+ Databases are appended whole, one after another, so each one's rows are
+ contiguous and a count is enough to recover them.
+ """
rows = [("query", query_sequence)]
seen = {query_sequence}
- for a3m in a3ms:
- for _, (description, sequence) in enumerate(_fasta_records(a3m)):
- if sequence in seen:
+ contributed = []
+ for database_name, a3m in a3ms:
+ added = 0
+ for description, sequence in _fasta_records(a3m):
+ key = strip_insertions(sequence)
+ if key in seen:
continue
- seen.add(sequence)
+ seen.add(key)
rows.append((description, sequence))
- return "".join(f">{description}\n{sequence}\n" for description, sequence in rows)
+ added += 1
+ contributed.append((database_name, added))
+ text = "".join(f">{description}\n{sequence}\n" for description, sequence in rows)
+ return text, tuple(contributed)
+
+
+def read_msa_bundle(
+ msa_input_dir: Path, request: FeatureRequest, *, require_row_spans: bool = False
+) -> dict[str, Any]:
+ """Read one request's MSA bundle, deleting it if it is unsafe to use.
+
+ Shared by every finalizer, so each backend refuses the same damaged bundles.
+ Deleting is what gets a bundle rebuilt: the workflow's Shard completion then no
+ longer validates, and a repair shard is scheduled. A bundle that is merely
+ rejected, and left in place, fails the same finalization on every retry.
+
+ ``require_row_spans`` is for consumers that slice the unpaired alignment by
+ database -- AlphaFold 2 does. A bundle without usable spans is unusable to them,
+ so it is treated as damaged, not as a failure to report and keep.
+ """
+ path = msa_input_dir / f"{request.name}_mmseqs_msa.json"
+ try:
+ encoded = path.read_text(encoding="utf-8")
+ except OSError as exc:
+ raise RuntimeError(f"Cannot read MMseqs2 MSA bundle {path}: {exc}") from exc
+ try:
+ try:
+ payload = json.loads(encoded)
+ except (TypeError, ValueError, json.JSONDecodeError) as exc:
+ raise _InvalidMsaBundle(
+ f"Cannot parse MMseqs2 MSA bundle {path}: {exc}"
+ ) from exc
+ if not isinstance(payload, dict):
+ raise _InvalidMsaBundle(
+ f"MMseqs2 MSA bundle {path} is not a JSON object"
+ )
+ if payload.get("sequence") != request.sequence:
+ raise _InvalidMsaBundle(
+ f"MMseqs2 MSA bundle sequence does not match {request.name!r}"
+ )
+ if payload.get("moleculeType", PROTEIN) != request.molecule_type:
+ raise _InvalidMsaBundle(
+ "MMseqs2 MSA bundle molecule type does not match "
+ f"{request.name!r}"
+ )
+ if not isinstance(payload.get("provenance"), dict):
+ raise _InvalidMsaBundle(
+ f"MMseqs2 MSA bundle lacks provenance for {request.name!r}"
+ )
+ for key in ("unpairedMsa", "pairedMsa"):
+ if not isinstance(payload.get(key), str):
+ raise _InvalidMsaBundle(
+ f"MMseqs2 MSA bundle lacks {key} for {request.name!r}"
+ )
+ if require_row_spans:
+ try:
+ searched_msas_from_payload(payload)
+ except (KeyError, TypeError, ValueError) as exc:
+ raise _InvalidMsaBundle(
+ f"MMseqs2 MSA bundle {path} has no usable per-database row "
+ f"spans: {exc}"
+ ) from exc
+ return payload
+ except _InvalidMsaBundle:
+ path.unlink(missing_ok=True)
+ raise
+
+
+def searched_msas_from_payload(payload: Mapping[str, Any]) -> SearchedMsas:
+ """Read a bundle back, refusing row spans that do not describe its alignment.
+
+ The spans are what a consumer slices by, so a wrong count does not fail -- it
+ hands AlphaFold 2 the wrong database's rows as uniref90. Check that they add up.
+ """
+ unpaired = payload["unpairedMsa"]
+ raw_rows = payload.get("unpairedDatabaseRows")
+ if not isinstance(raw_rows, list):
+ raise ValueError("MSA bundle lacks unpairedDatabaseRows")
+ rows = []
+ for entry in raw_rows:
+ if (
+ not isinstance(entry, Mapping)
+ or not isinstance(entry.get("name"), str)
+ or not isinstance(entry.get("rows"), int)
+ or isinstance(entry.get("rows"), bool)
+ or entry["rows"] < 0
+ ):
+ raise ValueError(f"MSA bundle has a malformed row span: {entry!r}")
+ rows.append((entry["name"], entry["rows"]))
+ # The producer always searches the complete named recipe. Counts alone do
+ # not detect a missing database or a duplicate name that would overwrite an
+ # earlier span in rows_by_database(). Validate before any finalizer uses it.
+ molecule_type = payload.get("moleculeType", PROTEIN)
+ required_names = (
+ RNA_DATABASE_NAMES if molecule_type == RNA else UNPAIRED_DATABASE_NAMES
+ )
+ names = tuple(name for name, _ in rows)
+ if len(names) != len(required_names) or set(names) != set(required_names):
+ raise ValueError(
+ "MSA bundle database row spans must name each of "
+ f"{', '.join(required_names)} exactly once"
+ )
+ if molecule_type == PROTEIN and _msa_depth(payload["pairedMsa"]) == 0:
+ raise ValueError("Protein MSA bundle has no paired UniProt alignment")
+ # The query row belongs to no database. An empty alignment is invalid too:
+ # its depth is zero, so no nonnegative span total can account for its query.
+ if sum(count for _, count in rows) != _msa_depth(unpaired) - 1:
+ raise ValueError(
+ "MSA bundle row spans account for "
+ f"{sum(count for _, count in rows)} rows but the alignment has "
+ f"{_msa_depth(unpaired) - 1} besides the query"
+ )
+ return SearchedMsas(
+ unpaired=unpaired, paired=payload["pairedMsa"], unpaired_rows=tuple(rows)
+ )
diff --git a/alphapulldown/objects.py b/alphapulldown/objects.py
index d9e61b23..40409060 100644
--- a/alphapulldown/objects.py
+++ b/alphapulldown/objects.py
@@ -44,6 +44,22 @@ def _query_only_stockholm(sequence: str, query_id: str = "query") -> str:
)
+def add_template_feature_defaults(
+ feature_dict: Dict[str, Any], sequence: str
+) -> None:
+ """Fill the two template features native AlphaFold 2 features lack.
+
+ The mmseqs2 path produces ``template_confidence_scores`` and
+ ``template_release_date``; jackhmmer features do not. Every AlphaFold 2
+ feature source adds them here, so pickles from any source carry the same
+ keys and a multimer built from mixed sources does not fail on a missing one.
+ """
+ if feature_dict.get("template_confidence_scores") is None:
+ feature_dict["template_confidence_scores"] = np.array([[1] * len(sequence)])
+ if feature_dict.get("template_release_date") is None:
+ feature_dict["template_release_date"] = np.array(["none"])
+
+
def _ensure_identifier_feature_arrays(
feature_dict: Dict[str, np.ndarray],
feature_groups: Tuple[Tuple[str, Tuple[str, ...]], ...],
@@ -226,16 +242,8 @@ def make_features(
fasta_file, self._uniprot_runner, msa_output_dir, use_precomputed_msa
)
self.feature_dict.update(pairing_results)
-
- # Add extra features to make it compatible with pickle features obtaiend from mmseqs2
- template_confidence_scores = self.feature_dict.get('template_confidence_scores', None)
- template_release_date = self.feature_dict.get('template_release_date', None)
- if template_confidence_scores is None:
- self.feature_dict.update(
- {'template_confidence_scores': np.array([[1] * len(self.sequence)])}
- )
- if template_release_date is None:
- self.feature_dict.update({"template_release_date" : np.array(['none'])})
+
+ add_template_feature_defaults(self.feature_dict, self.sequence)
# post processing
if (not save_msa) and (not use_precomputed_msa):
diff --git a/alphapulldown/scripts/_mmseqs2_cli.py b/alphapulldown/scripts/_mmseqs2_cli.py
index babe96e0..409b3b22 100644
--- a/alphapulldown/scripts/_mmseqs2_cli.py
+++ b/alphapulldown/scripts/_mmseqs2_cli.py
@@ -110,6 +110,16 @@ def define_msa_search_flags(
8,
"CPU threads for MMseqs2 operations.",
)
+ _define_once(
+ "mmseqs_db_load_mode",
+ flags.DEFINE_integer,
+ None,
+ "How MMseqs2 reads the target database: 0 auto, 1 fread, 2 mmap, "
+ "3 mmap+touch. Left unset MMseqs2 chooses, which reads the whole target "
+ "database into RSS; 2 memory-maps it instead and lowers peak memory. It "
+ "changes memory behaviour only, never the alignment, so it is not part of "
+ "the MSA cache identity and switching it reuses existing bundles.",
+ )
_define_once(
"mmseqs_rna_e_value",
flags.DEFINE_float,
@@ -160,6 +170,13 @@ def define_msa_search_flags(
def define_template_provenance_flags() -> None:
+ _define_once(
+ "template_pdb70_database_id",
+ flags.DEFINE_string,
+ None,
+ "Immutable identity of the PDB70 build used with AF2 --use_hhsearch. "
+ "Change this identity whenever PDB70 is rebuilt, even at the same path.",
+ )
_define_once(
"template_seqres_database_id",
flags.DEFINE_string,
@@ -300,5 +317,23 @@ def always_required_msa_flag_names() -> tuple[str, ...]:
return required_msa_flag_names(molecule_types=())
-def required_template_flag_names() -> tuple[str, ...]:
- return ("template_seqres_database_id", "template_mmcif_database_id")
+def required_template_flag_names(
+ *, data_pipeline: str = "alphafold3", use_hhsearch: bool = False
+) -> tuple[str, ...]:
+ database = (
+ "template_pdb70_database_id"
+ if data_pipeline == "alphafold2" and use_hhsearch
+ else "template_seqres_database_id"
+ )
+ return (database, "template_mmcif_database_id")
+
+
+def require_template_flags(flag_values: flags.FlagValues) -> None:
+ """Validate identities for the databases the selected template search reads."""
+ required = required_template_flag_names(
+ data_pipeline=_flag_value(flag_values, "data_pipeline"),
+ use_hhsearch=bool(_flag_value(flag_values, "use_hhsearch")),
+ )
+ missing = [name for name in required if not str(_flag_value(flag_values, name) or "").strip()]
+ if missing:
+ raise ValueError("Template finalization requires " + ", ".join(f"--{name}" for name in missing))
diff --git a/alphapulldown/scripts/compare_msa_backends.py b/alphapulldown/scripts/compare_msa_backends.py
index 0c13f09b..a06f0212 100644
--- a/alphapulldown/scripts/compare_msa_backends.py
+++ b/alphapulldown/scripts/compare_msa_backends.py
@@ -13,10 +13,17 @@
flags.DEFINE_string(
- "reference_dir", None, "Directory of native/jackhmmer AF3 JSON artifacts."
+ "reference_dir", None, "Directory of native/jackhmmer feature artifacts."
)
-flags.DEFINE_string("candidate_dir", None, "Directory of MMseqs2 AF3 JSON artifacts.")
+flags.DEFINE_string("candidate_dir", None, "Directory of MMseqs2 feature artifacts.")
flags.DEFINE_string("output_path", None, "JSON report path.")
+flags.DEFINE_enum(
+ "artifact_format",
+ "af3_json",
+ ["af3_json", "af2_pickle"],
+ "af3_json: _af3_input.json[.xz]. af2_pickle: .pkl[.xz], the "
+ "MonomericObject pickles AlphaFold 2 reads.",
+)
FLAGS = flags.FLAGS
@@ -137,16 +144,138 @@ def mean(key: str, backend: str) -> float:
}
+def _af2_artifacts(directory: Path) -> dict[str, Path]:
+ result = {}
+ for path in sorted(directory.glob("*.pkl*")):
+ filename = path.name
+ for suffix in (".pkl.xz", ".pkl"):
+ if filename.endswith(suffix):
+ result[filename[: -len(suffix)]] = path
+ break
+ return result
+
+
+def _af2_side(features: dict) -> dict:
+ """What one AlphaFold 2 feature set offers the model, measured."""
+ import numpy as np
+
+ # The alphabet AlphaFold 2 encodes MSAs in, spelled out without importing it.
+ from alphapulldown.utils.af2_to_af3_msa import AF2_ID_TO_A3M
+
+ msa = np.asarray(features["msa"])
+ length = int(msa.shape[1])
+ unpaired = "".join(
+ f">row{index}\n{''.join(AF2_ID_TO_A3M[int(i)] for i in row)}\n"
+ for index, row in enumerate(msa)
+ )
+ deletions = np.asarray(features["deletion_matrix_int"])
+ species = {
+ value.decode() if isinstance(value, bytes) else str(value)
+ for value in features.get("msa_species_identifiers_all_seq", [])
+ }
+ species.discard("")
+ templates = [
+ name for name in features.get("template_domain_names", [])
+ if (name.decode() if isinstance(name, bytes) else str(name))
+ ]
+ return {
+ "unpaired": measure_a3m(unpaired, query_length=length),
+ "unpaired_neff": neff(unpaired),
+ # Rows carrying at least one insertion: all zero for a local MMseqs2
+ # alignment built from result2msa mode 2 alone.
+ "rows_with_insertions": int((deletions.sum(axis=1) > 0).sum()),
+ "paired_depth": int(np.asarray(features.get("msa_all_seq", msa[:1])).shape[0]),
+ # Pairing needs a species in common; distinct labels are what it has to use.
+ "paired_species": len(species),
+ "template_count": len(templates),
+ }
+
+
+def compare_af2_directories(reference_dir: Path, candidate_dir: Path) -> list[dict]:
+ """Paired measurements of two directories of AlphaFold 2 feature pickles.
+
+ No homolog overlap: a pickle stores its alignment as integer rows without the
+ sequence headers, so there is no accession to match on, and residue strings
+ are not a substitute -- two backends align the same homolog over different
+ extents. Compare the raw alignments for overlap; this compares what the
+ model is given.
+ """
+ from alphapulldown.utils.lightweight_pickles import (
+ extract_feature_dict,
+ load_lightweight_pickle,
+ )
+
+ references = _af2_artifacts(reference_dir)
+ candidates = _af2_artifacts(candidate_dir)
+ missing = sorted(references.keys() ^ candidates.keys())
+ if missing:
+ raise ValueError("Artifact sets differ: " + ", ".join(missing))
+ rows = []
+ for name in sorted(references):
+ reference = load_lightweight_pickle(references[name])
+ candidate = load_lightweight_pickle(candidates[name])
+ if reference.sequence != candidate.sequence:
+ raise ValueError(f"Sequence mismatch for {name!r}")
+ rows.append(
+ {
+ "name": name,
+ "reference_path": str(references[name]),
+ "candidate_path": str(candidates[name]),
+ "reference": _af2_side(extract_feature_dict(reference)),
+ "candidate": _af2_side(extract_feature_dict(candidate)),
+ }
+ )
+ return rows
+
+
+def summarize_af2(rows: list[dict]) -> dict:
+ if not rows:
+ return {"protein_count": 0}
+
+ def mean(side: str, *path: str) -> float:
+ total = 0.0
+ for row in rows:
+ value = row[side]
+ for key in path:
+ value = value[key]
+ total += value
+ return total / len(rows)
+
+ summary = {"protein_count": len(rows)}
+ for side in ("reference", "candidate"):
+ summary.update(
+ {
+ f"mean_{side}_unpaired_depth": mean(side, "unpaired", "depth"),
+ f"mean_{side}_unpaired_neff": mean(side, "unpaired_neff"),
+ f"mean_{side}_rows_with_insertions": mean(side, "rows_with_insertions"),
+ f"mean_{side}_paired_depth": mean(side, "paired_depth"),
+ f"mean_{side}_paired_species": mean(side, "paired_species"),
+ f"mean_{side}_template_count": mean(side, "template_count"),
+ }
+ )
+ return summary
+
+
def main(argv) -> None:
del argv
- proteins = compare_directories(Path(FLAGS.reference_dir), Path(FLAGS.candidate_dir))
+ if FLAGS.artifact_format == "af2_pickle":
+ proteins = compare_af2_directories(
+ Path(FLAGS.reference_dir), Path(FLAGS.candidate_dir)
+ )
+ summary = summarize_af2(proteins)
+ else:
+ proteins = compare_directories(
+ Path(FLAGS.reference_dir), Path(FLAGS.candidate_dir)
+ )
+ summary = summarize(proteins)
report = {
"schemaVersion": 1,
"warning": (
"MSA/template metrics are diagnostic only; run matched inference and "
"DockQ against experimental references before claiming accuracy equivalence."
),
- "summary": summarize(proteins),
+ "artifactFormat": FLAGS.artifact_format,
+ "summary": summary,
"proteins": proteins,
}
Path(FLAGS.output_path).write_text(
diff --git a/alphapulldown/scripts/create_batch_features.py b/alphapulldown/scripts/create_batch_features.py
index 84c4f749..25735216 100644
--- a/alphapulldown/scripts/create_batch_features.py
+++ b/alphapulldown/scripts/create_batch_features.py
@@ -93,7 +93,9 @@ def main(argv) -> None:
template_mmcif_database_id=FLAGS.template_mmcif_database_id,
),
mmseqs_process=SubprocessMmseqsProcess(
- FLAGS.mmseqs_binary_path, gpu=FLAGS.mmseqs_use_gpu
+ FLAGS.mmseqs_binary_path,
+ gpu=FLAGS.mmseqs_use_gpu,
+ db_load_mode=FLAGS.mmseqs_db_load_mode,
),
af3_pipeline=pipeline,
).generate(requests)
diff --git a/alphapulldown/scripts/create_batch_msas.py b/alphapulldown/scripts/create_batch_msas.py
index fe61ddeb..4ed43be0 100644
--- a/alphapulldown/scripts/create_batch_msas.py
+++ b/alphapulldown/scripts/create_batch_msas.py
@@ -57,7 +57,9 @@ def main(argv) -> None:
result = MsaBatch(
settings=settings,
mmseqs_process=SubprocessMmseqsProcess(
- FLAGS.mmseqs_binary_path, gpu=FLAGS.mmseqs_use_gpu
+ FLAGS.mmseqs_binary_path,
+ gpu=FLAGS.mmseqs_use_gpu,
+ db_load_mode=FLAGS.mmseqs_db_load_mode,
),
).generate(requests)
logging.info(
diff --git a/alphapulldown/scripts/create_individual_features.py b/alphapulldown/scripts/create_individual_features.py
index 8d433acd..f1c3f8ac 100644
--- a/alphapulldown/scripts/create_individual_features.py
+++ b/alphapulldown/scripts/create_individual_features.py
@@ -21,13 +21,15 @@
from colabfold.utils import DEFAULT_API_SERVER
# AlphaFold2 imports
-from alphafold.data import templates
from alphafold.data.pipeline import DataPipeline as AF2DataPipeline
-from alphafold.data.tools import hmmsearch, hhsearch
# AlphaPulldown helpers
from alphapulldown.utils.create_custom_template_db import create_db
from alphapulldown.objects import MonomericObject
+from alphapulldown.af2_feature_finalizer import (
+ Af2TemplateStackSettings,
+ build_af2_template_stack,
+)
from alphapulldown.utils.file_handling import (
iter_seqs,
parse_csv_file,
@@ -395,29 +397,35 @@ def get_af3_feature_metadata(chain_kinds, *, skip_msa, flag_values=None):
# =================== AlphaFold 2 Feature Creation ===================
+def af2_template_stack_settings():
+ """The AF2 template stack as this run's flags describe it, mutating nothing.
+
+ Paths not given explicitly come from --data_dir, the same defaults
+ create_arguments() would have written into FLAGS.
+ """
+ def path(flag_name, database_key):
+ explicit = getattr(FLAGS, flag_name)
+ if explicit:
+ return explicit
+ return get_database_path(database_key) if FLAGS.data_dir else None
+
+ return Af2TemplateStackSettings(
+ template_mmcif_dir=path("template_mmcif_dir", "template_mmcif_dir"),
+ max_template_date=FLAGS.max_template_date,
+ kalign_binary_path=FLAGS.kalign_binary_path,
+ obsolete_pdbs_path=path("obsolete_pdbs_path", "obsolete_pdbs"),
+ use_hhsearch=FLAGS.use_hhsearch,
+ hmmsearch_binary_path=FLAGS.hmmsearch_binary_path,
+ hmmbuild_binary_path=FLAGS.hmmbuild_binary_path,
+ pdb_seqres_database_path=path("pdb_seqres_database_path", "pdb_seqres"),
+ hhsearch_binary_path=FLAGS.hhsearch_binary_path,
+ pdb70_database_path=path("pdb70_database_path", "pdb70"),
+ )
+
+
def _create_af2_template_stack():
"""Create the AF2 template searcher and featurizer."""
- if FLAGS.use_hhsearch:
- template_searcher = hhsearch.HHSearch(
- binary_path=FLAGS.hhsearch_binary_path, databases=[FLAGS.pdb70_database_path]
- )
- template_featuriser = templates.HhsearchHitFeaturizer(
- mmcif_dir=FLAGS.template_mmcif_dir, max_template_date=FLAGS.max_template_date,
- max_hits=20, kalign_binary_path=FLAGS.kalign_binary_path,
- release_dates_path=None, obsolete_pdbs_path=FLAGS.obsolete_pdbs_path
- )
- else:
- template_featuriser = templates.HmmsearchHitFeaturizer(
- mmcif_dir=FLAGS.template_mmcif_dir, max_template_date=FLAGS.max_template_date,
- max_hits=20, kalign_binary_path=FLAGS.kalign_binary_path,
- obsolete_pdbs_path=FLAGS.obsolete_pdbs_path, release_dates_path=None
- )
- template_searcher = hmmsearch.Hmmsearch(
- binary_path=FLAGS.hmmsearch_binary_path,
- hmmbuild_binary_path=FLAGS.hmmbuild_binary_path,
- database_path=FLAGS.pdb_seqres_database_path
- )
- return template_searcher, template_featuriser
+ return build_af2_template_stack(af2_template_stack_settings())
def create_pipeline_af2():
diff --git a/alphapulldown/scripts/finalize_batch_features.py b/alphapulldown/scripts/finalize_batch_features.py
index 6ac0024c..27f29dfc 100644
--- a/alphapulldown/scripts/finalize_batch_features.py
+++ b/alphapulldown/scripts/finalize_batch_features.py
@@ -1,17 +1,27 @@
#!/usr/bin/env python3
-"""CPU-only native AF3 template search and feature finalization stage."""
+"""CPU-only template search and feature finalization for local MMseqs2 bundles.
+
+Reads the MSA bundles the search stage wrote and publishes standard features for
+either backend: AlphaFold 3 input JSON, or AlphaFold 2 MonomericObject pickles.
+"""
from __future__ import annotations
import os
-# AF3 imports JAX transitively; this CPU stage must never initialize a GPU.
+# AF3 imports JAX transitively, and so does alphapulldown.objects via ColabFold;
+# this CPU stage must never initialize a GPU.
os.environ["JAX_PLATFORMS"] = "cpu"
from pathlib import Path
from absl import app, flags, logging
+from alphapulldown.af2_feature_finalizer import (
+ Af2FeatureFinalizationSettings,
+ Af2FeatureFinalizer,
+ build_af2_template_stack,
+)
from alphapulldown.feature_batch import (
MOLECULE_TYPES,
PROTEIN,
@@ -22,8 +32,9 @@
from alphapulldown.scripts import create_individual_features as legacy_features
from alphapulldown.scripts._mmseqs2_cli import (
define_template_provenance_flags,
- required_template_flag_names,
+ require_template_flags,
)
+from alphapulldown.utils import save_meta_data
flags.DEFINE_string("msa_input_dir", None, "Directory containing MMseqs2 MSA bundles.")
@@ -34,14 +45,88 @@
def main(argv) -> None:
del argv
- if FLAGS.data_pipeline != "alphafold3":
- raise ValueError("MMseqs2 MSA finalization requires --data_pipeline=alphafold3")
if FLAGS.keep_msas or FLAGS.skip_msa or FLAGS.path_to_mmt or FLAGS.use_mmseqs2:
raise ValueError(
"MMseqs2 MSA finalization cannot be combined with --keep_msas, "
"--skip_msa, --path_to_mmt, or --use_mmseqs2"
)
+ require_template_flags(FLAGS)
+ if FLAGS.data_pipeline == "alphafold2":
+ result = _finalize_alphafold2()
+ backend = "AF2"
+ else:
+ result = _finalize_alphafold3()
+ backend = "AF3"
+ logging.info(
+ "%s feature finalization: %d written, %d reused, %d failed",
+ backend,
+ len(result.written),
+ len(result.reused),
+ len(result.failures),
+ )
+ if result.failures:
+ detail = ", ".join(
+ f"{failure.name} ({failure.error})" for failure in result.failures
+ )
+ raise RuntimeError(
+ f"{backend} feature finalization failed for {len(result.failures)} "
+ f"chain(s): {detail}"
+ )
+
+
+def af2_template_metadata(stack) -> dict:
+ """Provenance for the resources an AlphaFold 2 finalization actually uses.
+
+ Not the run's whole flag set: the jackhmmer and HHblits binary flags default to
+ whatever is on PATH, so recording them would claim this MSA came from tools
+ that never touched it. The MSA's own provenance is the bundle's, added by the
+ finalizer. Only the template stack, which does run here, is recorded.
+ """
+ used = {
+ "template_mmcif_dir": stack.template_mmcif_dir,
+ "obsolete_pdbs_path": stack.obsolete_pdbs_path,
+ "kalign_binary_path": stack.kalign_binary_path,
+ "max_template_date": stack.max_template_date,
+ "data_pipeline": "alphafold2",
+ }
+ if stack.use_hhsearch:
+ used["hhsearch_binary_path"] = stack.hhsearch_binary_path
+ used["pdb70_database_path"] = stack.pdb70_database_path
+ else:
+ used["hmmsearch_binary_path"] = stack.hmmsearch_binary_path
+ used["hmmbuild_binary_path"] = stack.hmmbuild_binary_path
+ used["pdb_seqres_database_path"] = stack.pdb_seqres_database_path
+ return save_meta_data.get_meta_dict(used)
+
+def _finalize_alphafold2():
+ # Explicit settings, as for AlphaFold 3 below: paths come from --data_dir
+ # without create_arguments() rewriting the global FLAGS.
+ stack = legacy_features.af2_template_stack_settings()
+ template_searcher, template_featurizer = build_af2_template_stack(stack)
+ # Every molecule type the search stage can produce is read, so an RNA chain
+ # fails here by name, with the reason, rather than as a missing bundle.
+ requests = feature_requests_from_fastas(
+ FLAGS.fasta_paths, molecule_types=MOLECULE_TYPES
+ )
+ return Af2FeatureFinalizer(
+ settings=Af2FeatureFinalizationSettings(
+ output_dir=Path(FLAGS.output_dir),
+ msa_input_dir=Path(FLAGS.msa_input_dir),
+ max_template_date=FLAGS.max_template_date,
+ template_seqres_database_id=FLAGS.template_seqres_database_id,
+ template_mmcif_database_id=FLAGS.template_mmcif_database_id,
+ template_searcher=stack.searcher_name,
+ template_pdb70_database_id=FLAGS.template_pdb70_database_id,
+ compress=FLAGS.compress_features,
+ base_metadata=af2_template_metadata(stack),
+ ),
+ template_searcher=template_searcher,
+ template_featurizer=template_featurizer,
+ ).generate(requests)
+
+
+def _finalize_alphafold3():
# No create_arguments() here: it worked by mutating the global FLAGS and the two
# calls below then read that mutation back, so this stage depended on call order
# across a script boundary. The settings resolve the same paths explicitly.
@@ -59,7 +144,7 @@ def main(argv) -> None:
skip_msa=True,
flag_values=settings.flag_values_with_resolved_paths(FLAGS.flag_values_dict()),
)
- result = FeatureFinalizer(
+ return FeatureFinalizer(
settings=FeatureFinalizationSettings(
output_dir=Path(FLAGS.output_dir),
msa_input_dir=Path(FLAGS.msa_input_dir),
@@ -71,19 +156,6 @@ def main(argv) -> None:
),
af3_pipeline=pipeline,
).generate(requests)
- logging.info(
- "AF3 feature finalization: %d written, %d reused, %d failed",
- len(result.written),
- len(result.reused),
- len(result.failures),
- )
- if result.failures:
- detail = ", ".join(
- f"{failure.name} ({failure.error})" for failure in result.failures
- )
- raise RuntimeError(
- f"AF3 feature finalization failed for {len(result.failures)} chain(s): {detail}"
- )
if __name__ == "__main__":
@@ -94,7 +166,7 @@ def main(argv) -> None:
"output_dir",
"data_dir",
"max_template_date",
- *required_template_flag_names(),
+ "template_mmcif_database_id",
]
)
app.run(main)
diff --git a/alphapulldown/utils/msa_formats.py b/alphapulldown/utils/msa_formats.py
new file mode 100644
index 00000000..4fafb74c
--- /dev/null
+++ b/alphapulldown/utils/msa_formats.py
@@ -0,0 +1,91 @@
+"""Turn MMseqs2 output into A3M that keeps both its headers and its insertions.
+
+No AlphaFold dependency of any kind. The search stage used to convert results
+with ``alphafold3.cpp.msa_conversion``, and the AlphaFold 2 image installs
+AlphaPulldown without the ``alphafold3`` extra, so the shared stage imported
+cleanly there and then died on the first search result.
+
+The formats. ``mmseqs result2msa`` offers several, and none gives both things an
+AlphaFold alignment needs. Measured on the pinned build
+(8cc5ce367b5638c4306c2d7cfc652dd099a4643f), with a target carrying a deliberate
+four-residue insertion::
+
+ mode 2 >sp|P00002|INSERT_MOUSE has a 4-residue insertion OS=Mus musculus
+ MKTAYIAKQRQISFVKSHFSRQLEE... <- the WWWW is gone
+ mode 5 >P00002
+ MKTAYIAKQRQISFVKSHwwwwFSRQLEE... <- kept, as an A3M insertion
+
+Mode 2 keeps the full header and drops every column the query does not span, so
+an alignment built from it alone has no insertions and AlphaFold derives an
+all-zero deletion matrix from it. That is not a small detail: against a real
+586-residue query, 98 of 120 small_bfd hits (81.7%) and 712 of 824 uniprot hits
+(86.4%) carry insertions, 13035 residues of them on uniprot alone.
+
+Mode 5 keeps the insertions and cuts the header to the database key. How much
+that loses depends on the FASTA the database was built from: small_bfd headers
+are a single token and survive whole, but uniprot's ``sp|P83570|GWA_SEPOF …``
+becomes ``P83570`` -- and AlphaFold 2 reads the species out of the long form, and
+species is what pairs chains in a complex. The same holds for nucleotide
+searches, so RNA takes the same route.
+
+So both are run over one search result and joined by
+:func:`stitch_headers_and_insertions`. The second pass costs little: 2 s against
+a 947 s search on small_bfd, 13 s against 3739 s on uniprot, roughly 16 ms a hit.
+"""
+
+from __future__ import annotations
+
+from typing import Sequence
+
+
+def strip_insertions(a3m_row: str) -> str:
+ """Drop the insertion residues, leaving one column per query position."""
+ return "".join(residue for residue in a3m_row if not residue.islower())
+
+
+class StitchMismatch(ValueError):
+ """Two result2msa passes over one result set disagreed about their rows."""
+
+
+def stitch_headers_and_insertions(
+ headers_from: Sequence[tuple[str, str]],
+ insertions_from: Sequence[tuple[str, str]],
+) -> list[tuple[str, str]]:
+ """Join mode-2 headers to mode-5 sequences, verifying the join row by row.
+
+ Both arguments are ``(description, sequence)`` records read from one search
+ result formatted twice: ``headers_from`` carries the full database headers and
+ no insertions, ``insertions_from`` carries the insertions and a bare accession.
+ MMseqs2 emits both in result order, so they line up positionally.
+
+ Positional joins are exactly the kind that rot silently, so this one is
+ checked rather than trusted: removing the insertions from a mode-5 row has to
+ reproduce the mode-2 row character for character, on every row. If a future
+ MMseqs2 ever reorders, filters or realigns one pass and not the other, this
+ raises instead of emitting a chimeric alignment in which headers describe the
+ wrong sequences -- which for the paired database would mean pairing chains by
+ the wrong species, a wrong answer that looks entirely plausible.
+
+ Verified against real data: 120/120 rows on small_bfd, and 31/31 on a
+ synthetic set built with random insertions and deletions.
+ """
+ if len(headers_from) != len(insertions_from):
+ raise StitchMismatch(
+ "the two result2msa passes returned different row counts "
+ f"({len(headers_from)} with headers, {len(insertions_from)} with "
+ "insertions); they cannot describe the same search result"
+ )
+ stitched = []
+ for index, ((description, aligned), (_, with_insertions)) in enumerate(
+ zip(headers_from, insertions_from)
+ ):
+ if strip_insertions(with_insertions) != aligned:
+ raise StitchMismatch(
+ f"row {index} differs between the two result2msa passes: "
+ f"{strip_insertions(with_insertions)!r} from the insertion pass "
+ f"does not match {aligned!r} from the header pass. The two are "
+ "no longer in the same order, so headers cannot be trusted to "
+ "describe these sequences"
+ )
+ stitched.append((description, with_insertions))
+ return stitched
diff --git a/docs/mmseqs2_rna.md b/docs/mmseqs2_rna.md
index 94f74c85..8da2aee1 100644
--- a/docs/mmseqs2_rna.md
+++ b/docs/mmseqs2_rna.md
@@ -1,9 +1,10 @@
-# Local MMseqs2 features (AlphaFold 3)
+# Local MMseqs2 features (AlphaFold 2 and 3)
An alternative to the per-protein jackhmmer/HHblits MSA search: proteins are split into
-bounded shards searched with MMseqs2, and a separate CPU stage runs AlphaFold 3's own
-template search and writes one standard AF3 JSON per chain. Off by default. Existing
-AlphaFold 2 feature generation and the remote `--use_mmseqs2` path are untouched.
+bounded shards searched with MMseqs2, and a separate CPU stage turns each chain's
+alignment into standard features — an AF3 JSON with AlphaFold 3's own template search,
+or an AF2 `MonomericObject` pickle; see [AlphaFold 2](#alphafold-2) below. Off by
+default. Native feature generation and the remote `--use_mmseqs2` path are untouched.
RNA chains can use the same path once the RNA databases are configured; see
[RNA chains](#rna-chains) below.
@@ -131,6 +132,84 @@ Useful flags: `--mmseqs_rna_e_value` (default `1e-3`) and
`--mmseqs__max_sequences` (default `10000` per RNA database), both matching
AlphaFold 3's own settings.
+## AlphaFold 2
+
+The search is the same; only finalization differs. Pass `--data_pipeline alphafold2` to
+`finalize_batch_features.py` and it writes `.pkl` (or `.pkl.xz` with
+`--compress_features`), the pickle the AlphaFold 2 backend reads:
+
+```bash
+python -m alphapulldown.scripts.finalize_batch_features \
+ --data_pipeline alphafold2 --fasta_paths complex.fasta \
+ --msa_input_dir msas/ --output_dir features/ --data_dir /db/alphafold2 \
+ --max_template_date 2026-08-01 \
+ --template_seqres_database_id pdb-seqres-2026-08 --template_mmcif_database_id pdb-mmcif-2026-08
+```
+
+Templates come from the AlphaFold 2 database tree under `--data_dir` (`pdb_seqres`,
+`pdb_mmcif`), searched with hmmsearch, or with hhsearch against PDB70 under
+`--use_hhsearch`. The MSA databases are the MMseqs2 ones the search stage used.
+
+For HHsearch, replace `--template_seqres_database_id` in the example with
+`--template_pdb70_database_id pdb70-2026-08`. The selected database identity and
+the mmCIF identity are required. Change the relevant identity whenever that
+database is rebuilt, even if its path stays the same. This regenerates features
+while reusing the existing MSA bundle; changing an unused database does not
+invalidate features. Existing HHsearch pickles without a PDB70 identity are
+regenerated once. The hmmsearch and AF3 cache identities are unchanged.
+
+The features are built the way native AlphaFold 2 builds them from jackhmmer:
+
+- uniref90 capped at 10 000 rows and MGnify at 501, counting the query as AlphaFold 2
+ does; small BFD uncapped
+- merged in AlphaFold 2's order, UniRef90, BFD, MGnify — row order matters, since it
+ samples its MSA from the top
+- templates searched from UniRef90 **alone**, never from the merged alignment; the
+ bundle records which rows each database contributed so this is possible
+- pairing features (`*_all_seq`) from the separate UniProt search, whose headers carry
+ the species AlphaFold 2 pairs chains by
+
+What differs, and why:
+
+- **The recipe is `reduced_dbs`.** There is no BFD/UniRef30 HHblits arm, so compare
+ against `--db_preset reduced_dbs`, not `full_dbs`.
+- **Caps apply after cross-database deduplication**, where native AlphaFold 2 caps raw
+ hits first. This only affects rows two databases both found.
+- **The template profile has no insert columns.** A3M insertions are per row and not
+ aligned to each other, so they cannot be turned back into Stockholm columns; the match
+ columns, which decide the profile's states, are the same.
+- **Accession identifiers are filled in** from the UniProt headers, where native
+ features leave them empty. Nothing on this path queries UniProt over the network.
+
+The pickles carry the same feature keys as native ones plus those two accession arrays,
+and assemble into multimers alongside pickles from other sources. RNA and DNA chains are
+refused: AlphaFold 2 has no MSA features for them.
+
+### Measured against native AlphaFold 2
+
+32 monomers spread over the quartiles of their native MSA depth, plus 12 heterodimers
+released after AF2-multimer's training cutoff, featurized natively with `reduced_dbs` and
+through this path, with the same databases and templates up to 2021-09-30:
+
+| median, unless stated | native | local, GPU search | local, CPU search |
+|---|---|---|---|
+| MSA depth, shallowest quartile | 52 | 29 | 28 |
+| MSA depth, deepest quartile | 12 247 | 11 756 | 5 181 |
+| Neff, all monomers | 778 | 627 | 572 |
+| templates per chain | 16 | 16 | 15 |
+| AF2-multimer DockQ, top-ranked, mean of 12 | 0.59 | 0.56 | 0.56 |
+| acceptable interfaces (DockQ ≥ 0.23) | 9 / 12 | 9 / 12 | 9 / 12 |
+
+- The MSAs are shallower, most on the shallowest families, as for AlphaFold 3. A GPU
+ search recovers about three quarters of native's unpaired hits.
+- A CPU search, at MMseqs2's default sensitivity, finds far fewer distant hits than the
+ GPU prefilter on deep families, without changing DockQ here.
+- One interface (9HMX) lost about 0.3 DockQ against native; the other eleven moved by
+ less than 0.1.
+- Finalization is dominated by template featurization: median ~1 GB and 2 min per chain,
+ but up to 19 GB and 90 min, set by which structures the templates come from rather
+ than by chain length or MSA depth.
+
## The binary
Both maintained prediction images bundle the same pinned MMseqs2-GPU build at
diff --git a/test/cluster/check_alphafold2_predictions.py b/test/cluster/check_alphafold2_predictions.py
index 0b7423f9..a9a7715f 100755
--- a/test/cluster/check_alphafold2_predictions.py
+++ b/test/cluster/check_alphafold2_predictions.py
@@ -810,5 +810,195 @@ def test_issue_614_precomputed_mmseqs_features_enable_af2_multimer_inference(sel
f"Expected AF2 ipTM > 0.6 from precomputed MMseq features, got {result_payload['iptm']}",
)
+
+MMSEQS_DATABASE_DIR = Path(
+ os.getenv("MMSEQS_DATABASE_DIR", "/g/alphafold/AlphaFold_DBs/mmseqs")
+)
+# GPU-padded builds of the AlphaFold 3.0.0 FASTAs (scripts/setup_databases.sh --mmseqs),
+# each named _gpu, with the identifiers the AlphaFold 2 benchmark used.
+LOCAL_MMSEQS_DATABASE_IDS = {
+ "uniref90": "uniref90-2022_05-padded",
+ "mgnify": "mgy_clusters-2022_05-padded",
+ "small_bfd": "small-bfd-padded",
+ "uniprot": "uniprot_all-2021_04-padded",
+}
+# A seeded random 90-mer with no homologs anywhere. In the Snakemake end-to-end run the
+# local path returned only the query for it.
+ORPHAN_SEQUENCE = (
+ "MYNARDGTQMSKFWKTDQPEWVTSYVYMRCQGQFWPAKCVIWGGAYNDV"
+ "HSGVVSGENWKIGSTWMNISMVDQDMITGQAMWSVRNVLFC"
+)
+
+
+class TestLocalMmseqsAgainstRemote(_TestBase):
+ """Opt-in: AF2 features from the local MMseqs2 path against the remote ColabFold API.
+
+ The two search different databases -- ColabFold's UniRef30 and environmental sets
+ remotely; UniRef90, MGnify, small BFD and UniProt locally -- so this asserts
+ agreement, not equality. The bands come from a 32-monomer benchmark: on families
+ with hundreds of hits or more, local over remote depth ran 0.26-3.7 (one outlier at
+ 0.03), and Neff alike. Needs network access to the ColabFold API, a GPU-capable
+ MMseqs2 build, and ~200 GB of host RAM, because the search reads every padded
+ database in full:
+
+ RUN_MMSEQS_FUNCTIONAL_TESTS=1 MMSEQS_INTEGRATION_BINARY=/path/to/mmseqs \\
+ python test/cluster/run_alphafold2_predictions.py \\
+ -k TestLocalMmseqsAgainstRemote --constraint "" --mem 200G --time 06:00:00
+ """
+
+ # A deep family with hundreds of structures, and a moderate one from the
+ # benchmark (1517 rows remotely, 1264 locally).
+ FAMILY_CHAINS = ("P61626", "O31718")
+ MAX_TEMPLATE_DATE = "2024-05-02"
+ RATIO_BAND = (0.2, 5.0)
+
+ def _require_local_mmseqs_environment(self) -> Path:
+ skip_reason = _mmseqs_functional_test_skip_reason()
+ if skip_reason:
+ self.skipTest(skip_reason)
+ binary = os.getenv("MMSEQS_INTEGRATION_BINARY")
+ if not binary or not Path(binary).is_file():
+ self.skipTest("Set MMSEQS_INTEGRATION_BINARY to a GPU-capable MMseqs2 build.")
+ missing = [
+ name
+ for name in LOCAL_MMSEQS_DATABASE_IDS
+ if not (MMSEQS_DATABASE_DIR / f"{name}_gpu.dbtype").is_file()
+ ]
+ if missing:
+ self.skipTest(
+ f"Padded MMseqs2 databases missing under {MMSEQS_DATABASE_DIR}: "
+ + ", ".join(missing)
+ )
+ return Path(binary)
+
+ def _run_step(self, label: str, args: list[str]) -> None:
+ env = _af2_subprocess_env()
+ # The scripts default their template tools (kalign, hmmsearch, hmmbuild) to
+ # whatever is first on PATH. Put this interpreter's environment first, so a
+ # job launched from another environment's shell still gets the tools installed
+ # alongside AlphaPulldown; otherwise kalign resolves to None and every chain
+ # fails at template realignment.
+ env["PATH"] = os.pathsep.join(
+ [str(Path(sys.executable).parent), env.get("PATH", "")]
+ )
+ res = subprocess.run(
+ [sys.executable, *args], capture_output=True, text=True, env=env
+ )
+ self.assertEqual(
+ res.returncode,
+ 0,
+ f"{label} failed.\nSTDOUT:\n{res.stdout}\nSTDERR:\n{res.stderr}",
+ )
+
+ def test_local_mmseqs_features_agree_with_remote(self):
+ binary = self._require_local_mmseqs_environment()
+ orphan = self.output_dir / "orphan.fasta"
+ orphan.write_text(f">orphan\n{ORPHAN_SEQUENCE}\n", encoding="utf-8")
+ fasta_paths = ",".join(
+ [
+ str(self.test_data_dir / "fastas" / f"{name}.fasta")
+ for name in self.FAMILY_CHAINS
+ ]
+ + [str(orphan)]
+ )
+ remote_dir = self.output_dir / "remote"
+ local_dir = self.output_dir / "local"
+ msa_dir = self.output_dir / "msas"
+ scripts = self.script_create_features.parent
+ shared = [
+ f"--fasta_paths={fasta_paths}",
+ f"--data_dir={DATA_DIR}",
+ f"--max_template_date={self.MAX_TEMPLATE_DATE}",
+ "--compress_features=True",
+ ]
+
+ self._run_step(
+ "Remote MMseqs2 features",
+ [
+ str(self.script_create_features),
+ *shared,
+ f"--output_dir={remote_dir}",
+ "--use_mmseqs2=True",
+ "--data_pipeline=alphafold2",
+ "--skip_existing=False",
+ ],
+ )
+ self._run_step(
+ "Local MMseqs2 search",
+ [
+ str(scripts / "create_batch_msas.py"),
+ f"--fasta_paths={fasta_paths}",
+ f"--msa_output_dir={msa_dir}",
+ f"--summary_path={self.output_dir / 'msa_summary.json'}",
+ f"--mmseqs_binary_path={binary}",
+ f"--mmseqs_temp_dir={self.output_dir / 'mmseqs_tmp'}",
+ f"--mmseqs_use_gpu={'true' if _has_nvidia_gpu() else 'false'}",
+ "--mmseqs_threads=8",
+ # One shard for all three chains, as the workflow would batch them.
+ "--mmseqs_batch_max_sequences=8",
+ "--mmseqs_batch_max_residues=100000",
+ *(
+ argument
+ for name, identifier in LOCAL_MMSEQS_DATABASE_IDS.items()
+ for argument in (
+ f"--mmseqs_{name}_database_path={MMSEQS_DATABASE_DIR / f'{name}_gpu'}",
+ f"--mmseqs_{name}_database_id={identifier}",
+ )
+ ),
+ ],
+ )
+ self._run_step(
+ "Local AlphaFold 2 finalization",
+ [
+ str(scripts / "finalize_batch_features.py"),
+ *shared,
+ "--data_pipeline=alphafold2",
+ f"--msa_input_dir={msa_dir}",
+ f"--output_dir={local_dir}",
+ "--template_seqres_database_id=pdb-seqres-cluster-check",
+ "--template_mmcif_database_id=pdb-mmcif-cluster-check",
+ ],
+ )
+
+ from alphapulldown.scripts.compare_msa_backends import (
+ compare_af2_directories,
+ summarize_af2,
+ )
+
+ # Raises on a missing artifact or a sequence mismatch between the two sides.
+ rows = compare_af2_directories(remote_dir, local_dir)
+ # The measured numbers, for the job log: the assertions below are loose.
+ print(
+ json.dumps(
+ {"summary": summarize_af2(rows), "rows": rows}, indent=1, default=str
+ )
+ )
+ by_name = {row["name"]: row for row in rows}
+ self.assertEqual(set(by_name), {*self.FAMILY_CHAINS, "orphan"})
+
+ low, high = self.RATIO_BAND
+ for name in self.FAMILY_CHAINS:
+ remote = by_name[name]["reference"]
+ local = by_name[name]["candidate"]
+ with self.subTest(chain=name):
+ remote_depth = remote["unpaired"]["depth"]
+ local_depth = local["unpaired"]["depth"]
+ self.assertGreaterEqual(min(remote_depth, local_depth), 100)
+ self.assertBetween(local_depth / remote_depth, low, high)
+ self.assertBetween(
+ local["unpaired_neff"] / remote["unpaired_neff"], low, high
+ )
+ # An all-zero deletion matrix is the defect the two-pass format fixed.
+ self.assertGreater(local["rows_with_insertions"], 0)
+ self.assertGreater(remote["rows_with_insertions"], 0)
+ # Local pairing comes from its own UniProt search, which carries species.
+ self.assertGreaterEqual(local["paired_species"], 5)
+ self.assertGreaterEqual(by_name["P61626"]["candidate"]["template_count"], 1)
+ # Neither backend may invent a family for a sequence that has none.
+ for side in ("reference", "candidate"):
+ with self.subTest(orphan=side):
+ self.assertLessEqual(by_name["orphan"][side]["unpaired"]["depth"], 20)
+
+
if __name__ == "__main__":
absltest.main()
diff --git a/test/integration/test_create_individual_features.py b/test/integration/test_create_individual_features.py
index e8d979b1..caba7971 100644
--- a/test/integration/test_create_individual_features.py
+++ b/test/integration/test_create_individual_features.py
@@ -1369,8 +1369,8 @@ def test_create_pipeline_af2_uses_hhsearch_template_stack(tmp_flags):
create_features.FLAGS.kalign_binary_path = "/bin/kalign"
create_features.FLAGS.obsolete_pdbs_path = "/db/obsolete.dat"
- with patch.object(create_features.hhsearch, "HHSearch", return_value="searcher") as mock_searcher, \
- patch.object(create_features.templates, "HhsearchHitFeaturizer", return_value="featurizer") as mock_featurizer, \
+ with patch("alphafold.data.tools.hhsearch.HHSearch", return_value="searcher") as mock_searcher, \
+ patch("alphafold.data.templates.HhsearchHitFeaturizer", return_value="featurizer") as mock_featurizer, \
patch.object(create_features, "AF2DataPipeline", return_value="pipeline") as mock_pipeline:
pipeline = create_features.create_pipeline_af2()
@@ -1402,8 +1402,8 @@ def test_create_pipeline_af2_uses_hmmsearch_template_stack(tmp_flags):
create_features.FLAGS.kalign_binary_path = "/bin/kalign"
create_features.FLAGS.obsolete_pdbs_path = "/db/obsolete.dat"
- with patch.object(create_features.hmmsearch, "Hmmsearch", return_value="searcher") as mock_searcher, \
- patch.object(create_features.templates, "HmmsearchHitFeaturizer", return_value="featurizer") as mock_featurizer, \
+ with patch("alphafold.data.tools.hmmsearch.Hmmsearch", return_value="searcher") as mock_searcher, \
+ patch("alphafold.data.templates.HmmsearchHitFeaturizer", return_value="featurizer") as mock_featurizer, \
patch.object(create_features, "AF2DataPipeline", return_value="pipeline") as mock_pipeline:
pipeline = create_features.create_pipeline_af2()
@@ -1437,8 +1437,8 @@ def test_create_pipeline_af2_skip_msa_returns_template_only_pipeline(tmp_flags):
create_features.FLAGS.kalign_binary_path = "/bin/kalign"
create_features.FLAGS.obsolete_pdbs_path = "/db/obsolete.dat"
- with patch.object(create_features.hmmsearch, "Hmmsearch", return_value="searcher") as mock_searcher, \
- patch.object(create_features.templates, "HmmsearchHitFeaturizer", return_value="featurizer") as mock_featurizer, \
+ with patch("alphafold.data.tools.hmmsearch.Hmmsearch", return_value="searcher") as mock_searcher, \
+ patch("alphafold.data.templates.HmmsearchHitFeaturizer", return_value="featurizer") as mock_featurizer, \
patch.object(create_features, "AF2DataPipeline") as mock_pipeline:
pipeline = create_features.create_pipeline_af2()
diff --git a/test/integration/test_mmseqs2_af2.py b/test/integration/test_mmseqs2_af2.py
new file mode 100644
index 00000000..b93b9dfa
--- /dev/null
+++ b/test/integration/test_mmseqs2_af2.py
@@ -0,0 +1,210 @@
+"""Local MMseqs2 to AlphaFold 2 features, end to end, with nothing faked.
+
+A real MMseqs2 search over a small UniProt-headed database, through the real
+``create_batch_msas.py``; then the real ``finalize_batch_features.py
+--data_pipeline=alphafold2``, running real hmmsearch against a PDB seqres whose
+entry is backed by a real mmCIF (3L4Q, influenza NS1 bound to p85beta). The
+pickle it publishes is then loaded and checked for what the two stages exist to
+deliver: a real template, recovered insertions, and parseable species.
+
+Opt-in: needs MMSEQS_INTEGRATION_BINARY and the AlphaFold 2 template tools.
+"""
+
+from __future__ import annotations
+
+import os
+from pathlib import Path
+import pickle
+import random
+import shutil
+import subprocess
+import sys
+
+import pytest
+
+pytestmark = [pytest.mark.integration, pytest.mark.external_tools]
+
+pytest.importorskip("alphafold.data.pipeline", reason="needs AlphaFold 2")
+
+TEMPLATES = Path(__file__).resolve().parents[1] / "test_data" / "templates"
+
+# 3L4Q chain A without its His tag: the NS1 effector domain.
+NS1 = (
+ "SDEALKMTMASVPASRYLTDMTLEEMSRDWSMLIPKQKVAGPLCIRMDQAIMDKNIILKANFSVIFDRLETLIL"
+ "LRAFTEEGAIVGEISPLPSLPGHTAEDVKNAVGVLIGGLEWNDNTVRVSETLQRFAWRSSNENGRPPLTPKQ"
+ "KREMAGTIRSEV"
+)
+NS1_WITH_TAG = "HHHHHH" + NS1
+P85B = (
+ "YQQDQIVKEDSVEAVGAQLKVYHQQYQDKSREYDQLYEEYTRTSQELQMKRTAIEAFNETIKIFEEQGQTQEKSS"
+ "KEYLERFRREGNEKEMQRILLNSERLKSRIAEIHESRTKLEQELRAQASDNREIDKRMNSLKPDLMQLRKIRDQ"
+ "YLVWLTQKGARQKKINEWLGI"
+)
+SPECIES = ("HUMAN", "MOUSE", "CHICK", "PIG", "BOVIN", "RAT")
+
+
+def _mutated(sequence: str, count: int, seed: int) -> str:
+ rng = random.Random(seed)
+ residues = list(sequence)
+ for position in rng.sample(range(len(residues)), count):
+ residues[position] = "W" if residues[position] != "W" else "F"
+ return "".join(residues)
+
+
+# The query is an NS1 HOMOLOG, about 90% identical, not NS1 itself. AlphaFold 2
+# rightly discards a template identical to its query -- a DuplicateError it drops
+# without so much as a warning -- so a query copied from 3L4Q would find no
+# template at all, and that is not the case features exist for.
+QUERY = _mutated(NS1, 16, seed=11)
+
+
+def _tool(name: str) -> str:
+ path = shutil.which(name) or str(Path(sys.executable).parent / name)
+ if not Path(path).exists():
+ pytest.skip(f"{name} is not installed")
+ return path
+
+
+def _run(*command, env=None):
+ completed = subprocess.run(
+ [str(part) for part in command],
+ capture_output=True,
+ text=True,
+ env=env,
+ timeout=600,
+ )
+ if completed.returncode:
+ raise AssertionError(
+ f"{command[0]} failed ({completed.returncode}):\n"
+ f"{completed.stdout[-3000:]}\n{completed.stderr[-3000:]}"
+ )
+ return completed
+
+
+def _homologs() -> str:
+ """Query homologs under UniProt headers: substitutions, and one insertion."""
+ rng = random.Random(3)
+ residues = "ACDEFGHIKLMNPQRSTVWY"
+ records = []
+ for index, species in enumerate(SPECIES):
+ sequence = list(QUERY)
+ for _ in range(8):
+ position = rng.randrange(len(sequence))
+ sequence[position] = rng.choice(residues)
+ if index == 0:
+ # Well inside the domain, so the alignment has to open an insertion.
+ sequence[60:60] = list("WWWWW")
+ accession = f"P{index:05d}"
+ records.append(
+ f">sp|{accession}|NS1_{species} Non-structural protein 1 "
+ f"OS=Influenza OX={1000 + index}\n{''.join(sequence)}\n"
+ )
+ return "".join(records)
+
+
+@pytest.fixture
+def mmseqs_binary() -> Path:
+ configured = os.environ.get("MMSEQS_INTEGRATION_BINARY")
+ if not configured:
+ pytest.skip("set MMSEQS_INTEGRATION_BINARY to run against real MMseqs2")
+ binary = Path(configured)
+ if not binary.is_file():
+ pytest.fail(f"MMSEQS_INTEGRATION_BINARY does not exist: {binary}")
+ return binary
+
+
+def test_local_mmseqs2_to_alphafold2_features_end_to_end(tmp_path, mmseqs_binary):
+ hmmsearch, hmmbuild, kalign = (_tool(n) for n in ("hmmsearch", "hmmbuild", "kalign"))
+ env = {**os.environ, "OPENBLAS_NUM_THREADS": "1", "OMP_NUM_THREADS": "1"}
+
+ # A padded MMseqs2 database standing in for all four protein databases.
+ target_fasta = tmp_path / "homologs.fasta"
+ target_fasta.write_text(_homologs(), encoding="utf-8")
+ target_db, padded_db = tmp_path / "homologs", tmp_path / "homologs_gpu"
+ _run(mmseqs_binary, "createdb", target_fasta, target_db, "--threads", "1")
+ _run(mmseqs_binary, "makepaddedseqdb", target_db, padded_db, "--threads", "1")
+
+ # A PDB seqres whose NS1 entry is backed by the real 3L4Q mmCIF.
+ template_root = tmp_path / "pdb"
+ mmcif_dir = template_root / "mmcif_files"
+ mmcif_dir.mkdir(parents=True)
+ shutil.copy(TEMPLATES / "3L4Q.cif", mmcif_dir / "3l4q.cif")
+ seqres = template_root / "pdb_seqres.txt"
+ seqres.write_text(
+ f">3l4q_A mol:protein length:{len(NS1_WITH_TAG)} NS1\n{NS1_WITH_TAG}\n"
+ f">3l4q_C mol:protein length:{len(P85B)} P85B\n{P85B}\n",
+ encoding="utf-8",
+ )
+ obsolete = template_root / "obsolete.dat"
+ obsolete.write_text("", encoding="utf-8")
+
+ query_fasta = tmp_path / "ns1.fasta"
+ query_fasta.write_text(f">ns1\n{QUERY}\n", encoding="utf-8")
+ msa_dir = tmp_path / "msas"
+ database_flags = [
+ flag
+ for name in ("uniref90", "mgnify", "small_bfd", "uniprot")
+ for flag in (
+ f"--mmseqs_{name}_database_path={padded_db}",
+ f"--mmseqs_{name}_database_id=homologs-v1",
+ )
+ ]
+
+ _run(
+ sys.executable, "-m", "alphapulldown.scripts.create_batch_msas",
+ f"--fasta_paths={query_fasta}",
+ f"--msa_output_dir={msa_dir}",
+ f"--summary_path={tmp_path / 'summary.json'}",
+ f"--mmseqs_binary_path={mmseqs_binary}",
+ f"--mmseqs_temp_dir={tmp_path / 'work'}",
+ "--mmseqs_batch_max_sequences=4",
+ "--mmseqs_batch_max_residues=10000",
+ "--mmseqs_threads=2",
+ f"--mmseqs_use_gpu={'true' if os.environ.get('MMSEQS_INTEGRATION_GPU') == '1' else 'false'}",
+ *database_flags,
+ env=env,
+ )
+ assert (msa_dir / "ns1_mmseqs_msa.json").exists()
+
+ features_dir = tmp_path / "features"
+ _run(
+ sys.executable, "-m", "alphapulldown.scripts.finalize_batch_features",
+ "--data_pipeline=alphafold2",
+ f"--fasta_paths={query_fasta}",
+ f"--msa_input_dir={msa_dir}",
+ f"--output_dir={features_dir}",
+ f"--data_dir={tmp_path}",
+ "--max_template_date=2050-01-01",
+ "--template_seqres_database_id=seqres-3l4q",
+ "--template_mmcif_database_id=mmcif-3l4q",
+ f"--pdb_seqres_database_path={seqres}",
+ f"--template_mmcif_dir={mmcif_dir}",
+ f"--obsolete_pdbs_path={obsolete}",
+ f"--hmmsearch_binary_path={hmmsearch}",
+ f"--hmmbuild_binary_path={hmmbuild}",
+ f"--kalign_binary_path={kalign}",
+ env=env,
+ )
+
+ with open(features_dir / "ns1.pkl", "rb") as handle:
+ monomer = pickle.load(handle)
+ features = monomer.feature_dict
+
+ assert type(monomer).__module__ == "alphapulldown.objects"
+ assert monomer.sequence == QUERY
+
+ # A real template, found by real hmmsearch from the uniref90 profile.
+ assert b"3l4q_A" in list(features["template_domain_names"])
+ assert features["template_aatype"].shape[1] == len(QUERY)
+
+ # The inserted homolog's five residues reach the deletion matrix.
+ assert features["deletion_matrix_int"].sum() >= 5
+
+ # Species parsed from the UniProt headers, for pairing.
+ species = {value.decode() for value in features["msa_species_identifiers_all_seq"]}
+ assert set(SPECIES) <= species
+
+ # Provenance records what built it, and not the tools that did not run.
+ metadata = next(features_dir.glob("ns1_feature_metadata_*.json")).read_text()
+ assert "jackhmmer" not in metadata and "hhblits" not in metadata
+ assert '"msa_backend": "mmseqs2-gpu"' in metadata
diff --git a/test/integration/test_mmseqs2_af2_edge_cases.py b/test/integration/test_mmseqs2_af2_edge_cases.py
new file mode 100644
index 00000000..c4b13d6d
--- /dev/null
+++ b/test/integration/test_mmseqs2_af2_edge_cases.py
@@ -0,0 +1,288 @@
+"""Edge cases for local MMseqs2 AlphaFold 2 features, end to end, nothing faked.
+
+Four separate MMseqs2 databases stand in for UniRef90, MGnify, small BFD and
+UniProt, so every stage and every cap is exercised on its own database. One real
+pass through ``create_batch_msas.py`` and ``finalize_batch_features.py
+--data_pipeline=alphafold2`` covers all the cases at once, as a workflow shard
+would; each test then checks one case's pickle.
+
+The cases are the ones that fail silently when wrong: a cap that never bites, an
+orphan chain whose empty alignment breaks a later stage, a template search that
+finds nothing, residues the pipeline does not know, headers with no species.
+
+``build_edge_case_features`` is importable, so the same features can be written
+somewhere durable and folded on a GPU.
+
+Opt-in: needs MMSEQS_INTEGRATION_BINARY and the AlphaFold 2 template tools.
+"""
+
+from __future__ import annotations
+
+import os
+from pathlib import Path
+import pickle
+import random
+import shutil
+import subprocess
+import sys
+
+import numpy as np
+import pytest
+
+pytestmark = [pytest.mark.integration, pytest.mark.external_tools]
+
+TEMPLATES = Path(__file__).resolve().parents[1] / "test_data" / "templates"
+RESIDUES = "ACDEFGHIKLMNPQRSTVWY"
+
+# 3L4Q chain A, NS1 effector domain, His tag removed.
+NS1 = (
+ "SDEALKMTMASVPASRYLTDMTLEEMSRDWSMLIPKQKVAGPLCIRMDQAIMDKNIILKANFSVIFDRLETLIL"
+ "LRAFTEEGAIVGEISPLPSLPGHTAEDVKNAVGVLIGGLEWNDNTVRVSETLQRFAWRSSNENGRPPLTPKQ"
+ "KREMAGTIRSEV"
+)
+MGNIFY_HITS = 600 # past AlphaFold 2's 501 cap, which counts the query
+AF2_MGNIFY_CAP = 501
+SPECIES = ("HUMAN", "MOUSE", "RAT", "BOVIN", "PIG", "CHICK", "DANRE", "XENLA")
+
+
+def _random_protein(rng: random.Random, length: int) -> str:
+ return "".join(rng.choice(RESIDUES) for _ in range(length))
+
+
+def _homolog(rng: random.Random, sequence: str, fraction: float = 0.15) -> str:
+ """About 85% identical: found easily, never mistaken for the query itself."""
+ residues = list(sequence)
+ for position in rng.sample(range(len(residues)), max(1, int(len(residues) * fraction))):
+ residues[position] = rng.choice(RESIDUES.replace(residues[position], ""))
+ return "".join(residues)
+
+
+def _mutated(sequence: str, count: int, seed: int) -> str:
+ rng = random.Random(seed)
+ residues = list(sequence)
+ for position in rng.sample(range(len(residues)), count):
+ residues[position] = "W" if residues[position] != "W" else "F"
+ return "".join(residues)
+
+
+def _cases():
+ """Query sequences, each unrelated to the others, and where their hits live."""
+ rng = random.Random(20260911)
+ deep = _random_protein(rng, 120)
+ x_query = list(_random_protein(rng, 110))
+ for position in (10, 55, 90):
+ x_query[position] = "X"
+ return {
+ "deep": deep,
+ "deep_copy": deep, # same sequence, second name
+ "shallow": _random_protein(rng, 100),
+ "orphan": _random_protein(rng, 90),
+ "notemplate": _random_protein(rng, 130),
+ "templated": _mutated(NS1, 16, seed=11), # NS1 homolog: 3L4Q is a template
+ "xresidues": "".join(x_query),
+ "nospecies": _random_protein(rng, 115),
+ "peptide": _random_protein(rng, 20),
+ }
+
+
+def _databases(cases):
+ """FASTA text per database: which hits each case gets, and where."""
+ rng = random.Random(7)
+ uniref90, mgnify, small_bfd, uniprot = [], [], [], []
+
+ def uniref(name, sequence, count):
+ for index in range(count):
+ uniref90.append((f"UniRef90_U{name}{index:04d} {name} homolog",
+ _homolog(rng, sequence)))
+
+ def uniprot_hits(name, sequence, count, *, with_species=True):
+ for index in range(count):
+ accession = f"Q{abs(hash((name, index))) % 10**5:05d}"
+ header = (
+ f"sp|{accession}|{name.upper()[:5]}_{SPECIES[index % len(SPECIES)]} "
+ f"{name} OS=Organism OX={9000 + index}"
+ if with_species
+ # A UniParc-style header: no species anywhere in it.
+ else f"UPI{index:010d} {name} unassigned"
+ )
+ uniprot.append((header, _homolog(rng, sequence)))
+
+ uniref("deep", cases["deep"], 30)
+ for index in range(MGNIFY_HITS):
+ mgnify.append((f"MGYP{index:012d}", _homolog(rng, cases["deep"])))
+ for index in range(20):
+ small_bfd.append((f"BFD_deep_{index:04d}", _homolog(rng, cases["deep"])))
+ uniprot_hits("deep", cases["deep"], 8)
+
+ uniref("shallow", cases["shallow"], 1)
+ uniref("notemplate", cases["notemplate"], 12)
+ uniprot_hits("notemplate", cases["notemplate"], 4)
+ uniref("templated", cases["templated"], 12)
+ uniprot_hits("templated", cases["templated"], 6)
+ uniref("xresidues", cases["xresidues"], 10)
+ uniprot_hits("xresidues", cases["xresidues"], 3)
+ uniref("nospecies", cases["nospecies"], 6)
+ uniprot_hits("nospecies", cases["nospecies"], 5, with_species=False)
+ uniref("peptide", cases["peptide"], 3)
+ # "orphan" gets nothing, anywhere.
+ return {"uniref90": uniref90, "mgnify": mgnify, "small_bfd": small_bfd,
+ "uniprot": uniprot}
+
+
+def _run(*command, env=None):
+ completed = subprocess.run(
+ [str(part) for part in command], capture_output=True, text=True, env=env,
+ timeout=1200,
+ )
+ if completed.returncode:
+ raise AssertionError(
+ f"{command[:4]} failed ({completed.returncode}):\n"
+ f"{completed.stdout[-3000:]}\n{completed.stderr[-4000:]}"
+ )
+ return completed
+
+
+def build_edge_case_features(workdir: Path, mmseqs: Path, *, tools: dict, python=None,
+ use_gpu: bool = False) -> dict[str, Path]:
+ """Build every case's AlphaFold 2 pickle through the real CLIs; return the paths."""
+ python = python or sys.executable
+ env = {**os.environ, "OPENBLAS_NUM_THREADS": "1", "OMP_NUM_THREADS": "1"}
+ cases = _cases()
+ workdir.mkdir(parents=True, exist_ok=True)
+
+ database_flags = []
+ for name, records in _databases(cases).items():
+ fasta = workdir / f"{name}.fasta"
+ fasta.write_text("".join(f">{h}\n{s}\n" for h, s in records), encoding="utf-8")
+ plain, padded = workdir / f"{name}_db", workdir / f"{name}_gpu"
+ _run(mmseqs, "createdb", fasta, plain, "--threads", "2")
+ _run(mmseqs, "makepaddedseqdb", plain, padded, "--threads", "2")
+ database_flags += [f"--mmseqs_{name}_database_path={padded}",
+ f"--mmseqs_{name}_database_id={name}-edge-v1",
+ # High enough that AlphaFold 2's own cap is what bites.
+ f"--mmseqs_{name}_max_sequences=2000"]
+
+ template_root = workdir / "pdb"
+ mmcif_dir = template_root / "mmcif_files"
+ mmcif_dir.mkdir(parents=True, exist_ok=True)
+ shutil.copy(TEMPLATES / "3L4Q.cif", mmcif_dir / "3l4q.cif")
+ seqres = template_root / "pdb_seqres.txt"
+ seqres.write_text(f">3l4q_A mol:protein length:{len(NS1) + 6} NS1\nHHHHHH{NS1}\n",
+ encoding="utf-8")
+ (template_root / "obsolete.dat").write_text("", encoding="utf-8")
+
+ queries = workdir / "queries.fasta"
+ queries.write_text("".join(f">{n}\n{s}\n" for n, s in cases.items()), encoding="utf-8")
+ msa_dir, features_dir = workdir / "msas", workdir / "features"
+
+ _run(python, "-m", "alphapulldown.scripts.create_batch_msas",
+ f"--fasta_paths={queries}", f"--msa_output_dir={msa_dir}",
+ f"--summary_path={workdir / 'summary.json'}",
+ f"--mmseqs_binary_path={mmseqs}", f"--mmseqs_temp_dir={workdir / 'work'}",
+ "--mmseqs_batch_max_sequences=32", "--mmseqs_batch_max_residues=100000",
+ "--mmseqs_threads=2", f"--mmseqs_use_gpu={'true' if use_gpu else 'false'}",
+ *database_flags, env=env)
+ _run(python, "-m", "alphapulldown.scripts.finalize_batch_features",
+ "--data_pipeline=alphafold2", f"--fasta_paths={queries}",
+ f"--msa_input_dir={msa_dir}", f"--output_dir={features_dir}",
+ f"--data_dir={workdir}", "--max_template_date=2050-01-01",
+ "--template_seqres_database_id=seqres-edge", "--template_mmcif_database_id=mmcif-edge",
+ f"--pdb_seqres_database_path={seqres}", f"--template_mmcif_dir={mmcif_dir}",
+ f"--obsolete_pdbs_path={template_root / 'obsolete.dat'}",
+ f"--hmmsearch_binary_path={tools['hmmsearch']}",
+ f"--hmmbuild_binary_path={tools['hmmbuild']}",
+ f"--kalign_binary_path={tools['kalign']}", env=env)
+ return {name: features_dir / f"{name}.pkl" for name in cases}
+
+
+def _tool(name: str) -> str:
+ path = shutil.which(name) or str(Path(sys.executable).parent / name)
+ if not Path(path).exists():
+ pytest.skip(f"{name} is not installed")
+ return path
+
+
+@pytest.fixture(scope="module")
+def features(tmp_path_factory):
+ pytest.importorskip("alphafold.data.pipeline", reason="needs AlphaFold 2")
+ configured = os.environ.get("MMSEQS_INTEGRATION_BINARY")
+ if not configured:
+ pytest.skip("set MMSEQS_INTEGRATION_BINARY to run against real MMseqs2")
+ tools = {name: _tool(name) for name in ("hmmsearch", "hmmbuild", "kalign")}
+ paths = build_edge_case_features(
+ tmp_path_factory.mktemp("edge"), Path(configured), tools=tools,
+ use_gpu=os.environ.get("MMSEQS_INTEGRATION_GPU") == "1",
+ )
+ loaded = {}
+ for name, path in paths.items():
+ with open(path, "rb") as handle:
+ loaded[name] = pickle.load(handle)
+ return loaded
+
+
+def _msa_rows(monomer) -> int:
+ return int(monomer.feature_dict["msa"].shape[0])
+
+
+def test_deep_alignment_hits_alphafold2s_mgnify_cap(features):
+ """600 MGnify hits were found; AlphaFold 2 keeps 501 counting the query."""
+ deep = features["deep"].feature_dict
+ rows = _msa_rows(features["deep"])
+ # query + 30 uniref90 + 20 BFD + 500 MGnify, all distinct by construction.
+ assert rows == 1 + 30 + 20 + (AF2_MGNIFY_CAP - 1), rows
+ assert deep["num_alignments"][0] == rows
+
+
+def test_the_same_sequence_under_two_names_gets_two_identical_pickles(features):
+ np.testing.assert_array_equal(features["deep"].feature_dict["msa"],
+ features["deep_copy"].feature_dict["msa"])
+ assert features["deep_copy"].description == "deep_copy"
+
+
+def test_a_shallow_alignment_is_kept_as_it_is(features):
+ assert _msa_rows(features["shallow"]) == 2
+
+
+def test_an_orphan_chain_gets_query_only_features(features):
+ orphan = features["orphan"].feature_dict
+ assert orphan["msa"].shape[0] == 1
+ assert orphan["msa_all_seq"].shape[0] == 1
+ assert orphan["deletion_matrix_int"].sum() == 0
+
+
+def test_no_template_gives_alphafold2s_empty_template(features):
+ templates = features["notemplate"].feature_dict
+ assert list(templates["template_domain_names"]) == [b""]
+ assert templates["template_aatype"].shape == (1, len(features["notemplate"].sequence), 22)
+ assert not templates["template_all_atom_masks"].any()
+
+
+def test_a_homolog_of_a_known_structure_finds_its_template(features):
+ assert b"3l4q_A" in list(features["templated"].feature_dict["template_domain_names"])
+
+
+def test_unknown_residues_survive_as_alphafold2s_unknown(features):
+ monomer = features["xresidues"]
+ aatype = monomer.feature_dict["aatype"].argmax(axis=1)
+ unknown = 20 # residue_constants.restype_order_with_x["X"]
+ assert [int(aatype[i]) for i in (10, 55, 90)] == [unknown] * 3
+ assert _msa_rows(monomer) > 1
+
+
+def test_pairing_rows_without_species_are_kept_but_unlabelled(features):
+ """No species in a UniProt header means no pairing -- not a failure, and not
+ a UniProt lookup to recover one."""
+ all_seq = features["nospecies"].feature_dict
+ assert all_seq["msa_all_seq"].shape[0] == 1 + 5
+ assert set(all_seq["msa_species_identifiers_all_seq"]) == {b""}
+
+
+def test_a_short_peptide_is_featurised(features):
+ peptide = features["peptide"]
+ assert peptide.feature_dict["aatype"].shape[0] == 20
+ assert _msa_rows(peptide) >= 1
+
+
+def test_every_case_carries_the_same_feature_keys(features):
+ keys = {name: frozenset(m.feature_dict) for name, m in features.items()}
+ assert len(set(keys.values())) == 1, keys
diff --git a/test/integration/test_mmseqs2_command_contract.py b/test/integration/test_mmseqs2_command_contract.py
index 2313267d..2bf641be 100644
--- a/test/integration/test_mmseqs2_command_contract.py
+++ b/test/integration/test_mmseqs2_command_contract.py
@@ -11,14 +11,12 @@
pytestmark = [pytest.mark.integration, pytest.mark.external_tools]
-try:
- from alphafold3.cpp import msa_conversion as _msa_conversion # noqa: F401
-except ImportError as exc:
- pytest.skip(
- f"AlphaFold 3 MSA conversion is unavailable: {exc}", allow_module_level=True
- )
-
-from alphapulldown.feature_batch import ( # noqa: E402
+# No AlphaFold 3 skip here any more. This module exercises the shared protein
+# search, which the AlphaFold 2 image has to run too -- and that image has no
+# AlphaFold 3 at all. Skipping the whole module on its absence meant an AlphaFold 2
+# environment reported success while silently skipping the one test that runs a
+# real MMseqs2 search end to end.
+from alphapulldown.feature_batch import (
DatabaseSpec,
FeatureRequest,
MsaBatch,
@@ -47,9 +45,15 @@ def test_real_createdb_padded_search_result2msa_and_unpack_contract(tmp_path):
query_sequence = "MKTAYIAKQRQISFVKSHFSRQDILDLWIYHTQGYFPQYQKVEKLLKQGADVVVT"
target_sequence = query_sequence[:-1] + "A"
+ # A UniProt-headed hit with a four-residue insertion. result2msa mode 2 keeps
+ # this header and drops the insertion; mode 5 keeps the insertion and cuts the
+ # header to "P0CTR1". The bundle has to carry both, on the same row.
+ inserted_sequence = query_sequence[:20] + "WWWW" + query_sequence[20:]
target_fasta = tmp_path / "target.fasta"
target_fasta.write_text(
- f">target_hit expected description OX=9606\n{target_sequence}\n",
+ f">target_hit expected description OX=9606\n{target_sequence}\n"
+ f">sp|P0CTR1|INSRT_HUMAN inserted OS=Homo sapiens OX=9606\n"
+ f"{inserted_sequence}\n",
encoding="utf-8",
)
target_db = tmp_path / "target"
@@ -87,9 +91,40 @@ def test_real_createdb_padded_search_result2msa_and_unpack_contract(tmp_path):
"gpu" if use_gpu else "cpu"
)
+ # The point of the two-pass format, against the real binary: the species
+ # header and the insertion arrive together, on one row, in the paired MSA
+ # AlphaFold pairs chains from.
+ paired = payload["pairedMsa"].splitlines()
+ header_index = next(
+ index for index, line in enumerate(paired) if line.startswith(">sp|P0CTR1|")
+ )
+ assert paired[header_index] == (
+ ">sp|P0CTR1|INSRT_HUMAN inserted OS=Homo sapiens OX=9606"
+ )
+ assert "wwww" in paired[header_index + 1], paired[header_index + 1]
+ assert (
+ paired[header_index + 1].replace("wwww", "").upper() == query_sequence
+ ), "removing the insertion must leave the row aligned to the query"
+
+ # And the bundle says which database contributed which unpaired rows.
+ assert [span["name"] for span in payload["unpairedDatabaseRows"]] == [
+ "uniref90",
+ "mgnify",
+ "small_bfd",
+ ]
+ assert (
+ sum(span["rows"] for span in payload["unpairedDatabaseRows"])
+ == payload["unpairedDepth"] - 1
+ )
+
+
+@pytest.mark.parametrize("num_iterations", (1, 3))
+def test_real_nucleotide_createdb_search_and_unpack_contract(tmp_path, num_iterations):
+ """The same contract for RNA: a nucleotide database, searched on CPU.
-def test_real_nucleotide_createdb_search_and_unpack_contract(tmp_path):
- """The same contract for RNA: a nucleotide database, searched on CPU."""
+ Also with the protein-only iterative search raised, which must not reach the
+ nucleotide search: there the pinned build exits 1.
+ """
configured_binary = os.environ.get("MMSEQS_INTEGRATION_BINARY")
if not configured_binary:
pytest.skip("set MMSEQS_INTEGRATION_BINARY to run the real command contract")
@@ -127,6 +162,7 @@ def test_real_nucleotide_createdb_search_and_unpack_contract(tmp_path):
max_residues_per_batch=1_000,
threads=2,
rna_databases=databases,
+ num_iterations=num_iterations,
)
result = MsaBatch(
diff --git a/test/test_data/fastas/O31718.fasta b/test/test_data/fastas/O31718.fasta
new file mode 100644
index 00000000..435bfcab
--- /dev/null
+++ b/test/test_data/fastas/O31718.fasta
@@ -0,0 +1,2 @@
+>O31718
+MIYKVFYQEKADEVPVREKTDSLYIEGVSERDVRTKLKEKKFNIEFITPVDGAFLEYEQQSENFKVLEL
diff --git a/test/unit/data/small_bfd.mode2.txt b/test/unit/data/small_bfd.mode2.txt
new file mode 100644
index 00000000..9369aaa2
--- /dev/null
+++ b/test/unit/data/small_bfd.mode2.txt
@@ -0,0 +1,240 @@
+>O31912
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A163VT74_9BACL
+-----------IDPAKWGISTDGTNSRATTDGLNAALADAKSKGFGEVYLPKGKYLIDAVCKTN-HSPEIGGGIRVPSNLKLTLDSEAELKVEPNGSYGYSCIFLDNVHNVTITGGIVTGDRNEHDYS--NKTKPTHEWGFGINVRGGTNITIDNVRIKDCSGDCIYVNAIGMINYGTVPYTPPQKVMIQNCTLDGSRRNNISISACDGVVIRNNLILNAGIQTIGPGFGIDIEGYGEGDIDYETPLNIVIQGNQFRGNRVYSVGNFNGYGVVIEGNFADNTLSYGNGTDTVIANNVLIRT-DRQRTGIDGQGVSQGLEANHVTIMGNIVKGFGSGMDIRGKDVVVTGNALSHEAGVGIAAFAAENVWIANNSVHRTKGTPYRIASCKDVQLVNNKAHGSDKT-AIEANASSQVILRGNVVRDCSGGIEASNSEVVHIDLTEY--KGKAYAISFDSKSEVTLKGNRIPGPRNTAIYGEGGIKRAKIADNEIADANSFTAIQIVGGAKHEIVGNNVTFNKSSNGGVGIYLKDAKDSIVAKNTVYSNSEYALTHSIATKESTGTKVLNN-------------------
+>A0A090ZKM7_PAEMA
+---------YVIDPAQWGIKTDGTEAVKTTEGLNKAIAHAKSAGYNEAFIPKGTYLIQGVGTTFPNTPEKGGGIVVPSHMKLTLDHEAELKVQPNAERGYSCIYLRKVQNVTISGGIITGDLDQHDFSKL--PKSTYEWGFGIYVHGGKNITIENMKIRKCIGDCIFLGSVGLLGVDPDYDKPEK-VAIRNCSLDGARRNNISITAADGVFVENNVITNAG--TVKPWAGIDIEGYGEGAIDYEEPRRVVVRGNVFRGNAEVSVLNFNGYGVIIEGNHADNTFSYGNGTDTVISNNVMVRTDGSK-VAIAAQQVSNGYDGNNVTIVGNIIKGFSSGIDARGKDVVVTGNTVSNTGGTGIGVWDAENVLVADNAVHRCAGLPYKVDNSNDVQFLNNKAL-HSERFGLELDKSTNVVLRGNSFGQCNGGIWGTKGTSVFAEGNYISYTGKNYAISFDKNSDVTLKENYIFGSRSVAIYGESSAGKIKIADNEISDITGNSAIQIKGGQRAEIVGNRITFKRKDDAAYGISLDNAEDAIIAQNTIYSNNGKSIPNAIVTESSKRTKVLNNLLINGKMLLNKDDTNI---
+>C2WEL3_BACCE
+---------YLIELSRWGI--INDGSKETEKEINNALQWAYDNGINRCILSSGTYLINAVGPPNDLQ---AGGIKIPDNMTLDLWHDTVLKVKANDSYSYSCIYLYNKNNIKIRGGTIQGDRYHHDFSTAPTGKLTHEWGRGINIIGCSNITIDNMNIKECTGDAIDVLSIGLMN--TQVYIPSSNITIRNCTLDKSRRNNLSLEGCDGVLVENNVITNAGDDGTAPRFGIDIEGYGEGATDYVVPLNIVIKNNKFEGNVTTSICNFNGYNVIIEGNISDNTISYAYGTQTIIS-NNIFKRVDLTTKAISSIGTAQGLDFNNTTITGNIITGFDTALDIRGKNVTVSSNIIYDVK-IGISLFQAESILVQGNLIKKATFGKIIINTCTNIKCTENQLK-DIGMLCIELNNSSAVTINQNDIFNSKQGIRISKSNAVSIDLNTF--NSPSYNIDFDATSNVLIINNLLKNCSSFAINGSASSKS-RIIKNIIENFTAISAINLSGG-RHELIDNILIANKNIAGGYGINLHSCNQSTVLRNHIFSSSIYNLSTPIKTNTSTNTKIIEN-------------------
+>A0A238U6X6_9FLAO
+-------------------------------------------------------------------------ILLPSNFHLSLHEETVFRVQPNAFPWYSLMTIDKKENVKISGGNFIGDRYEHDYPFFDLKRSTHEWGVLLLVRGSENINIDNITLKSSIADGLITGSEGHRIYPETVW--NKKVSLTNSIVSDNRRNNISITDGEDILIEGNEILDAGGETVAPRFGLDVEGYDESRKTYEWVENVIIRNNIFKGNEAGSIIVYTGDNVLIDGNFSDHVIAQN-----NTSGSKIINNTEARDDVRGRIGISTSDTGN--DVKNNTIRNFFGGYNIRGNNAEVSGNTVEGATVCLL------------------------INKAENIKVHDNTTSGAIASKAIRLTDANNIEIYNEKFT-LSNGFYLE-SIDFNMPNDDFHLN--------------------------------------------------------------------------------------------------------------------------------------------
+>LauGreSBDMM110SN_4_FD.fasta_scaffold226965_1
+-------------------------------------------------------------------------IHLPSDFHFKMSKSTFLRVQPNFWPRGVLLSVYEQKNTLVSGGNLIGDRYTHNYAPIKDERDTHEWPVLLSIAGCKDVIFEKIYMTDSTGDAVTGATNGSRDIGGADKKFNQNVIIRGCVMNASRRNNISITDGEDIFITNCIIQNGGGDTVAPRAGIDIEGYNPDGRNFEIVKRVTISGCTFKNNRVASIIDYSGINTTIKNNTSDHGFFASFSTGTKFLYNTFKASAINKDKVAIVTGINNTQLSKNNEVTGNKIEGFRVGITTQGDEGNVSNNTI-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_4058357
+-------------------------------------------------------------------------IKVPSNTHLLMSDNTFIRVQPSNNPFSRLLMTYKAQNVLIEGGNLVGDRYLHDYSEIGVSRATHGYGSLINIAGSQHVTVDNVNIYEGEGDGVLIQISAIRNKDGSIKAESSNVVIKNSLIDKCRRNNFSIIDANGVLIENNVISNAGGEGTAPEVGIDLEAYRERRSEYERVTNVTIRNNEFVGNDVADVIVYTASFVDIIGNTFDNRVGVHAGHDVKIANNEF--TAGERAVSFDNFIVNETETYN-IDVTGNTISGYDTAMKVGTQNVTVSENKIYDFVTGINITDI-ENAQISNNTLE-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1V5WUJ2_9DELT
+---------YVVDTDKWNIPTDGSDPERTSAGLSEALAWAVDNGFGTVRLPAGAYVVG-----REINSMFIEGVVVPGPLRLDFEPGAIIQMKPNDHPFYCILDIADASDVWIRGGTVLGDRESHQY----VGESTHEFGTAVCVGGSERILIENMSLAEATGDGITI-----NDAPG----SSRDITIRGNDIHHHRRQGISIISGSAIVIEDNEIHHIAG--TAPQFGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A090II36_9GAMM
+--LLNSSINFVFDNQRWGVIVNNEQAKENTRLFQYALNQAHNVHANVFRINKASFWVGNYKKFN--STEL-SGITLPSNIKLSMRHDTILRTQANGYARYALLGLYNADNVTIEGGVLIGDRDTHDYK--DPQSPKPYWGHLMKIGGSRNVTIKGVTFKNATADGLSIHSLGTYKRTGSIET--KNILVTDCLFDNNRRLGTAITSGSEIIVEHNTYLNSGSESVSPAWAIDIEGGYKDHEYLERPYNITIRNNIERNSYRGAFIGAIGDGITIENNNTENTIALG-SVFNSKAFNNTITRDLNKEY-LNPNGLSVAYDGEKMFYPTEEVVGIRARMYISGSGNSIFNNSISN-SLTGITIQKAKNAEIYNNSVHSNNSIGLSARDSNNVNVYDN--DFNIEGLAIRFISINE-KLGHENFS---------------MYLNNNRFTSSGY----NKAASVSRSRNVYFNENNFSNIGFI-MYNIQLIGNRV-ETKTRIGLQIEEGNEQIKLHDNLVIHPEKKK---CIRNLSEQIPDIKNNV--------------------------------------------
+>SRR5690625_80756
+---------YELELARWNVSNNGTRPHETTKGINEALNWAKENGYTSLLIPDGTYSIAKGNAENDRHAR----INMLSDMTFLMSNNTILQKEPNGFEEYSVLHVGAVKNVVIQGGTLIGDREDHNYSSGDWSSGTHEWGHGISIVGGENITVDGVKIKDFTGDGIYI----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_9554453
+---------YLVELDRWGISADGTNAEATTDGINEAIRWAQGEGYGRVRLPAGTYLIG-----KRLYDHYTGGIELVDDVALMMDDETVLQIVPNDTWAYCGIAMSGVRNAGVYGGTIRGDRDEHTYG----GSMTHEDGHCICIHESELVEIDGVTMEDPTGDGVAIVAEGGDG------SSCKHITIKNSEIARGRRQGISIVGGTNVWIENNEIHHIEG--TAPQFGIDIESLNFTSR------DIVIRNNRFHHN-RGGDFENADGKVWFEENHLD------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>APAga8741243855_1050100.scaffolds.fasta_scaffold124648_1
+---------YTIDNEQFGIYSNNTHARTTTDGINEALNWAKSHGYTKVRFAAGTYLIQC--TWNNRYCAPDDGILVPSGMTLDLG-TATFRMEANNYPAYTIFGIVNKSNVTITGGTLIGDLGSHTYSSV-SGSSSHEWGFGICISASKNVVIDDVTIKNMTGDGVILGSYAALSNGGRV---CSNIKVTDCTISNCRRQGISVIGADSELARNRIYGIKGTD---PQYGIDVEDYVVDDLKIHH---NNISDC-----SGGAINCNKGENYDVYSNTVDNIIA--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2G5GBI8_9FLAO
+------------------------------------------------------FVIDKLDAYFKIDGPLSEGIQIPSNFTFRMSENTHLRVQPNATDKCTLLSVYLSDNAVIEGGNLYGDRDEHDYSDGIND---HGWGHLFTSRGSTNVTVRNVTMIDAAGDALKLEGEGHAVNPD--YAPTRNFLATGCKFIRSRRNNLSITAADGVVIEDCDFIDAGIHTTIPGFALDIEALKPN----ELSENIIIRNNRETGSRRGGFLVAIGDKVTFEGNVINSAINLQSARNCIVRNNIVTAQSDAKEYGAGII-TGRSDRGNLVTIYNNTVNGFSTGISISNFDMKVYGNTINNCSNVDKSAGISMGASLNNVVVRNNDVNVMRFANVNNTDESGNKGNNIVSGSSTPINSSHGIELIENTFNNAYEFYNCSNLNII------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A167HAM4_9BURK
+---------------RWGVASNASNATATTDGMQAAIDWASSQGIGQFRVPAGEYLLGKIQTYN-----YAGGIKLPSNMALVLEPGAVLRMVPNDRWNYCVVTINGKKNVSVSGGTIVGDRYNHTYTPSSSGGTAHDEGHAICIEGSSQVEVQGVYITQANGDGILIV--------GKAPSTPQDITITGNNFDTNRRQGISIVGGARVLIEGNQIHHTKG--TSPQFGIDIEPLGGRGNNFHHNRGGDVVNTRTMHQGEASTTGGDDGRT-----YIDGPIVFWPEADQTIRNNNI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1I1IH73_9FLAO
+-------------------------------------------------------------------------INVPSDFHLIMTDNTHLRQQPNANKRATLLAAYLISNTIIEGGNLHGDRDTHDYSDTSTSQ---EWGHCIRVGASKNVIIKNMNIYDAGGDGIDIHAYGHAYNSHYTYTENLLITNNK--IYRSRRNGISITDGRNIVIEDNEFIDSGVSTVAPGWAIDVEAVRNSGVIFEIAEDILIKNNVERGSKYGGFIIHTGDRVTIDGNTMENSIAYAGTIGSVIKNNNLKSNSETALRGQTTGIIAQNKASSKNSVYGNTVYGYPIGIKVGDTNLNVYNN---NILECAVG---------------------ISLNTSKDSRIYGNTIKSTT---------ANSRGISNHTISNLIGSGLDENNESAKSNVIDVVIVFNGIKEIENSDTHSIIIKNNIIE--NGANLWLIDINNFEMHDNVI-----------------------------------------------------------------------------------------------
+>A0A238U509_9FLAO
+--LLNNSLTIQGDFDKWGIEGVTTNEISRT---NRDIL---ENNMTFIKLGASIFKIDKMDAFNVDEPDIEAAINVPSDFTLKMTNNTHLRMQPNAAIRPTLLATFTASNVTIDGGVLHGDRDSHDYTTINS---THEWGHLLRITGTKNSVFKNIRFEDATGDAIDVHAYGHSFDPH--YTYCDNVLITNNIMLRSRRNHISITDGRNITVEKNDFIDASIHTIAPGFAIDVEAV-----RHGNPRGISIAEDIFIKNNTGAVTVHTGDRVTIEGNKFENSISYSTSIGTIIRNNEIINNG----TAIVAGRADRYDDNYNGKVYGNTIENYAIGMTVSNKDLEVYANKITN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0P0CI41_9FLAO
+-----------------------------------------EGSFELVKLGVSTFIIDAMDAYFKVDDENFKGINPPSNFTLKMSENTHLRTQPTNFSNYALISVRDVENVVIDGGNLYGERDEHDYS----SGGSHEFGMCLTVSGSKDVTIKNMTITDALGDGIIIDNIG-HTYDSF-YTYTDNLLIQNNKIIRSRRNGISIVEGKNIVIDGNELVDTGITTAAPMWAIDIEPVWENGIKYQIVEYVTIKNNIERGSEKGGFINARGWYITYENNTMENTIAIGETVGSIVRNNIFKNPGKNSNVAIDPLGYGN-ERNYDNEVYGNTITGFPKGIELQDPGIDLHHNTM-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>J8DZ85_BACCE
+--MIEKVNIYVIELDKWNIKKDGTDAVNTTKGINKALLWAKENDYDVCKLPAGNYLVDK-----------DSNIEMVSDMTLDLF-GCTIRKETNGYQGYSIVRIFRQKNATILGGTIEGDKDTHDYSTIP---GTHEWGIGIDVSGNRNIKIDSVKIKNTTGYGVRTGTYGHLSW---VYTTDESGTVLKADVNFTRSNQIQENGYFSIMGNGYGFTKDGGEVNLDRVPITIYFFDESNKFLGKITKRTFDNIYYSSFPKGT----SKFKIGFRFNYNNNALSMTIRSMTYTKGINVIN---TDIYGCRALGIAITGAQNMLV---DNCEIYGIGGINPGYAIDIED-----------GYNINQNIIIRNNYIHDNNNGAIVVVSARNVLLESNKFYG-----SVFLGGSRGENYLSR--HNLYGSTNAGGGDAATITFDDYMLEGQLYNAFYDNDNMTFVLQSDTF----------------------------------------------------------------------------------------------------------------------
+>X4ZGB9_9BACL
+---------YLIELARWGIYNDGTHPVETVKGINNALVWARQKGITATTLPAGTYLIDKASRIN-----------MVGDMLFDLPMDAVLQKETNGKERYDVMYVGYANNVTLRGGTYLGDKLTHDYSQRDPNTGTHEGGYGIFVEGAKNTTIDGVKAMNFTGDGLVLGGFGTM----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1A5YEI2_9BACL
+---------HMIDLKRWGISSNGTKPVQTTQGINKALQWAAKSKITAVTLPPGTYLIDK----NSR-------INMVGNMLFQLSDDTILKKQENGKEHYELMFIGYANNVTLRGGTYLGDKDSHDYSKKDNPHTTHERGYGITVLGANNITIEGVKGTHFTGDGLIIGAH-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2B8JB68_BACME
+--------------EKWTIHNDGTYPIETTSGFNNALAWASAQGIHTFKVPAGIYLIK-----KGVDYDATARINMVSDMTFIADNKAIFQKETNGLTGYSVMYIGQVKNAIIKGGVYKGEKDTHDYSI----SSTHEWGYGVLVEGGENIIVDDIEAYNFTGDGLWVPTKGEVNIPASVYDNSKSVTVKNSKMHDNRRQGITVGGGYGVLLENNEIYNIRG--IAPQSGIDVEGYGINGNVHDNVYGVILYDGIGATVEENQIKNHSYPGLVVQEEYKDALVQNNYNSGMSIK----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1M6AGX2_9FLAO
+-------------------------------------------------------------TTNQNFYPSREAINVPSDFTLRMTDNTNLRVQPNSRKNYVLLAVRDASNVRVEGGNLIGDRLEHD---DNSQPGPHAFGFVLMIHGGSNVDLVGVRTILGTGDGIDVNSIGFTFEAG--YIPSNNIRITNCIMDSNRRNNMSITDGFNIVVDGCQFLNAGIDMPGPGVAMDVEAFAGNFILYERAYDLTFRN-NFEKGSKGSFVVAIGEDVTIENNTTEDGIAIGAGHGIKIIGNTLIAAADDNGAGITTGHPNSTDTYDNV-IANNRIIGHNIGIAAYQRDMKIYGNVIE------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>GraSoiStandDraft_43_1057313.scaffolds.fasta_scaffold3393195_1
+-----------IDNAYWGIVTETNTEIANMENINRAIKTAHENGIYKIKLAKATYWFDA--TSDKTTPSIG----LLSNMQFNL-XXAXLRVMPNNLTHHYFIYIESAENVKIFNGTITGDRYEHGY--VPATYPTHEWCHGLRVGSNSSNYCKNIEIYDLVVQE--------FTGDGINVSWSKNVTIRNTEVSNARRNGITISNTDETYIYDNYIHDTHG--VSPACGIDLEKAAGDGPKNIVIRNNRIYDCINPETGQGQAMAISGGQVTVRDNDIRGVIGFAYAEKILIENNRI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A229GVH8_9GAMM
+---------------------------DDTAAIQKAIDAVAAKGGGIVEIPAGTYMINGAATLGPGDVPRTSGLQVKSNVIIRMADDTVMQVIPNGEKHYDIFNIYNAENVAIMGGTLRGDRHSH---LNDQG----EWGSGIKIASAKNVVIEKVIAREFWGDAVHISDSG-----SLPRTPSQNVTIYQLAADGNRRQGISITSADKVLIEDSAFKNTGGQGTPPMAGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A098MBD8_9BACL
+---------HLIELSRWGIYNDGTHPVETTKGINNALTWAYQQGITATTLTPGTYLIDKASQINM----------VP-NMLFDLTMEVVLQKETNDKESYQIVSLDYGDNVTLRGGTYIGDRLTHDYSKKDGSAGTHEFGYGIIARGVKNLVIDRVKTTHFTGDGIILAGHGTM----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2A2AT09_9BURK
+-----------------------------------------------VWIPAGTYMIDTVNACGGWGQE-RCGLQMRSGVTVHMSQQAVLKAMPNGSRHYNIFHFNDVENAHVLGGQLQGERYAH---RIPTDGRLGEWGAGLVMRGARHAAIENVTAREFWGDGF--------------YVGGSSQNVKFCAVDKNRRQGMSITDVDTIVVQDSVFKNTHG--TPPQDGIDIEPWGENEPIREHVKNVTIRRSQFINNGIGMVTTHPGENVVLEGNFIDNSIGLGLSWKTRITGNRIIN----SQY--LNIGLGPLAT--FITVTDNAVTG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_2407419
+-----------------------------------AAIQAAINSLPTVTIPAGTYLIDTSKKIN-----------LKSNMLLKLDPNAILKAKSCSLIRHYLVYVNGKTNVEIAGGQLVGDRDGHNY----VGSSTHEWGHGIQILGSTKVTVRDLRVSKCTGDGVCIGG------------GASDVVIGNIIATNNRRQGLSITNCTNIKVYDSEFSYSKG--TSPECGIDIEGHSNNNGKYKRVSGVTITQCTLERN--GSLGLGTNGCSGIK--FTNNIVRYNSATGV-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1719318_174446
+---------YKLNLEDWDIPNNGHEPRKTTENLQKAIDWAHGNAYTKVLLPRGHFLLGITNGKRKEDNFSMRGLSMHSNTEFILDSAATLEMVSNDKVMYCIICIEDVTDVIIRGGTLKGDRETHTYTP-HHNRTTHEWGHGILISDRHRILVTNMEIKDVTGDGVYVKSEKK--------SIGSDIIIKNNDIHNARRQGVSIVGGLRVKIEDNEIHHIKG--TSPQFGVDIEG------PWTVTKDVIIHRNNFHDNRGGDVVNFDGKNVFITENKMIESDSYSYT----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>APHig6443718053_1056840.scaffolds.fasta_scaffold2008830_1
+-------IKYYTP-QQFGAVANDTG--DDTVAFNRALAAASSSSTDTVFVPAGTYMIKADGG--------DGGVQVLSKTKLKMDPGAVLQVITNAERGYNCVRTNGVTDAEISGGTICGDRTTHTGT-------SGEWGHGIGIYDSTDVTISNVVVKNCWGDGVYI---GTAN-DNSTTAKSRQISLSGVTTDNNRRNGLSVVAADGVTVDGCLFVNTNG--TDPQAGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_7665223
+---------------------------DVTSQLQTVLTNIAKNGGGIVYLPKGNYMIKATNPQSLLTPAKLEGLQVGSNTTILLDKDASLSVIPNNFWNYLVLNIQGADNVNILGGTLNGDRLSHDMSNPNNSPYYGEWGNGLSIQSSNNTLVSGVKFKNFWGDGISLFPDKDQAEAGAL-SQAKNVHITGCTFDYNRRQGISVGHANNVEIDHSLFENT--DGTGPAAGIDLE---PGGGSTEQVTNVKIHDNVFLNNNNAGLTAYAAPKSKV--------------SDVHVYNNTFINNG-------------AWMPG---QITFNN-----------AEYIEIDHNKFDNDD--ASRFHSSWIVNTANDNIHDN-----YGRNSSIAKEAHGEGKVTNNYVSSIMIENTGYDVANNHLPN-------------EISSTDLGTMGANWNYQNDVDYPGLATNEKVFNSRGKALNVTANPDNTVLNQSDPSNCQADISFDIDG----------------------------------------------------------------------------------
+>SRR5699024_10005537
+-------------------NAKGDGVTDDTNSINEAIDYAVENNINTVYFPSGIYMIDAEEIIPNGSK---GGIHLKSNITLKLDDNAILQAISNSAEGYNIIRAKESNNIKVIGGTIKGERSNHSGS-------EGEWGHGIHLKGCSNVYIQS-NIIDCWGDGIYVG--------GDVSTPTKNLIDENTVCDNNRRQGISIVSGKHIRLLNSDFINTNG-TL-PESGIDIE------PSHDRHIDVKVIDCNFNNNGTGFLIDGKSG--SVEDIYVNGI----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5207342_2131982
+---------------------------DDTRAFQDAIDAAKGG---IVIVPAGDYLIDPLHS-----------VRVRSGTQLRMDRNARLRAIPNAAPRAYVLLLQGVEDITISGGQILGDRKEH----LGT---TGEWGHGIAIYGASNVKVRDVRISGCWGDGISIGS--TKAGKGGVMRPSTDIEIANVASLGNRRQGLSIGRSRRVYVHDCEFSDTGG--TPPSAGIDVE--PDAG---DIAQDVRIERCILRRNGPGRATSVAIRDCTIEDNRNAGVLAVG-AIDLAIERNRIRGNG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_3757948
+-------------------------------------IQAAINSLPTVFVPAGTYLVDAVRS-----------VKLRSQMHLKLDPGAKLVAKPTSSESYNVVFADVAHDVEISGGQIIGERHQHKGTV-------GEGGHCIRIRGCERVTVRDIRLSDGWGDGITV---GPRPNRRKRFTYSQDVAIANIICDGNRRNGLSIGNVIGIKVYDCEFNNTNG--TAPQCGIDV----EPSPDFDHCDDVHIENCRMSGNGAMNVWKNTSNKNTIEGNKTCGLVTRG-MTSSSITGNTI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>R6FQI5_9CLOT
+---------YGVDIQKFNINNNGLNPIETSKGINDALNYAAKNKYDKITFPKGEYCI------SEENP-----ITMVSNLIVDLN-GATFKINDNGLQHYTVIDFSNCSNSQLINGIILGDRETHDYKTIE---GSHEWTCGIVFNNCDNCILDNVTISSFPG-------YGISSSLGENLS-DLIIGVTKENLSIGNINDKGLNNKKGTIIDPLNISNVGGEELGYNKGYMGYPYMQSKEYLSYFYDSKVDNCKQYK------------KVLIPDNYVHFVFKQDY-----------VPERGDTDFNGTTVFLTNYSSPNNITIKNCLIEKNKLGMGIGGYNWNIENNMFKGAPGYAIGWEYMDSFLFKNNKFNNNDIVSCAGDN---IIFENNSFTSTVYMWG----RTTNYKFLNNSFSNIAMNINYEYSTDTECSGNTYAITSK------NKDAEFNINNENIIDPENVSIIDADNIDNIRIYGN-FKDCH----ISKVTGSLVNFRGEKCKINNSN-----------------------------------------------------------------
+>SRR4249919_2030177
+-------------------------------------------------VPAGRYLIDAVKS-----------VKLPSNRKLKMHPDAILVAKANNAEGYNVLLVERVDNVQIVGGQIVGERDKH----IGT---TGEGGMGIRFRGATNSSVTDTIVSNFWGDGI-VAG----PYKGSKYIPSTDITLKNVTMSGNRRNGLSVGNVVRFLAEDCKVLDNGNDPDGPFCGVDVE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1S1V829_9FIRM
+---------YYAD------AAFTKPATDATQAINSAVKHASQNGIQKVVIPSGNYLIKAEGTGIEGDYAKTGGILLQSNMTLEMSSNAVLVTNTVNKPGYSLITVNNKSNVKIVGGKLVGDKDTH-------PANTHNACYGISINGSKNIYVDGTEITKMEDDGIMITDYAIDQSGG---TRSSDIEIRNVKSHNNGRQGLTI--ATGSNIKILNSEFSNQTKHEPKSGIDIE-----IESYDHVKNVEISGNKFEGNAFSGVSRHAEGKSNGLDMSNNNITVNNYSSGVVISGNNIISD-DSKAH--TSMGVYSTTPG--VSINGNNLVGQNVGMMLSGGGEQIVGNKIENEISVSGAAHLAENLAIKNNNFHDMKSYGINVRNT---EVSGNTMKNITEAFPNKASENTGINVTGNTFDGAYPTLYLGISYANSVKANSFTFSSYGYGM--------------------------------------------------------------------------------------------------------------------------------------
+>A0A1M5UZK5_9CLOT
+---------YTIELDKFGIKNDATFAVETSKGINDALQYAKEKGYEKIVFPKGEYLISELNPV------------VIDLKNVVIDNQATFQINTNGLEKYSIIQIDGAENIRLTNGIIRGDKDTHDYKTIKT---PHEWGCGIVFKGGKDLEMDNITVTNVTGYGIYTESGTNSNRFDAVYT--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5687768_13918870
+--------------------------------------------------------------------------------------------------------------VSIRGGKIVGERGAHHGT-------TGEWGMGVRLAGCHDVRIQGVQITDCWGDGIYVGANGVGN-------ESRRIKITECILRNNRRQGLSITGCIGALIRDCEFTDTNG-TL-PASGIDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A250E5Q6_9FLAO
+---------------------------DDTEAIQNAINEASKKGGGVVYIPEGTYLIDAKQSLVIRS---NVTLQLAANAILEAKANTILEAKANTSERYDILYIKNVENVKVVGGTIKGDRNIH-------IGNRGEWGMGIGIYDGKNIVIENVSVRDCWGDGIYI---------GKNRNRSENIILEKVKSVNNRRQGVSITAAHKVTINHCVFSQTNG--IPPQAGVDIE-----PNAADTVSNVVIKNSIFDSNENSGILIYTGAERS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_21041421
+--------------------ADNTGSVSTQSAINAAIALQNARGGGVVYVPRGTYLIDT-------NYLTGGSVRVLSNVTLHLDPGAVLQAVPTSNGQGAIVWAYNAENIIIQGGYIRGERDGH----IGTDQP--DGNHGISIFSCDNVTVKNVRVSHCWGDGMYIRNDTGGNNTG--DTLSTQIRVLDSSFFNNRRTGLACVAVDGLTISKCYF--YGNTGANPYAGLNLEPNSDGWVR-----NCVVSDC--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1H9W652_BUTFI
+---------------------------------------ASNGGLNTIYLPAGVYNITDIGNYDH-------GIELKSNVNLIMDKNAVLKVSGMPYGDYEIFSMRYLSNVTIAGGQLVGERYSHSYG---------ESGHGIAMHGCSNITITNMCISANWGDGIYFGTQAVWLGSGQGYFGNTNVTISGCDIFDNRRNSISFTDADYITVDRCNLRDSHG--TAPQCCVYFEPNGDSSDK--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR2546423_4745973
+-----------INVRDWG--ALGDGISDDTPAFAAALATLADRG-GTLSVPDGDYRIDPLKS-----------VRLTDNVALNLSRDAILRAIPVTARNSAVVLVERARNVRIIGGTIIGERDGH----LGVGG---EGGMGIWVSASSNVRIERVTALDCWGDGFYIAGRGSYDANSLHESHSDNVTVSRCIARNNRRQGLSVVGCIGGLIERCGFTDTNG--TAPQSGIDIEPQG----------NWTVSNVTV----RNCVTARNAGWGIL---VCGNDIYNASVSDILIEGNR-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6185503_5510564
+-----------------------------------------------VDVPAGRYRIDPVRSIHLADSEMASGAVLAA-LPVAQGNSAVIRL--DGIQGAS-----------IRGGMIIGERDGH----LGT---AGEWGMGIQIMGGSTISVEGVRIEGCWGDGIYVG--------GRSGVEATHITIRRCVVTNNRRQGMSMTGCRDSLVEGCTFASTHG--TAPQAGIDLEGYGLSGGREQHVQTITLDDNRVADNG-----FHGIGVVS--------------SVDCSVRGNTVEHNG---RDGVQIAGSSRVRTGNTIRDNSRRTAGVWDNVIV--QSLSTDNTVANN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1E7DPH2_9BACI
+-----------INITDYGANADDSK--DDTSSIQAAIDAAAGKN-GIVLIPAGTFLINT-------DPET-GSLNVKDNIEINMDEKTILKSIPNGLPIYRMLTIYNRENVKITGGTLIGDRYKHEGT-------EGEFGHGIYIGGSSEITISNVRAQDFWGDGFFVEGNASQTYP-------SSITIDNVESHNNRRQGISITAGKQIVVKNSIFSGTNG--TPPAAGIDLE--------RDPPYSLPLEEVELLNN-----------EVFNNEGY---GISFIYASNSSAQKNIVKNKGGIYIGGGVEQGIAKNNT-----VDDNFISENGLGIFVNSTQNNISNNVIEKSKKDGIVNHVGQN-RLVKNLVRDNQGNGLYIHDQSGIVVQQNKSKNSKAGIAVNVLDATITD--NDLLDNAGAGLHREEAKESTIERN-------------------------------------------------------------------------------------------------------------------------------------------------
+>F3B2U2_9FIRM
+---------------------------DDTAAIQRAIDAVSAAGGGIVDIPAGNYMI---NTLHQTGHSYRAGLVLKSNIIVRMANGAVLRAIPNGERSYQIFSITHVDNVHIMGGKLIGDRDTHIGNLGQT-------GYGVRITDATNVVIEDLYAGEFWGDGVFLG------------EDSRNITLYRVICDHNRRQGMSIVGGHNVKILESEFKRS--DGTPPKSGIDIEPEG------DHPIGVEIRNCLFEGSSTGFVVSNQSNSVAENIIFADNI----------VRGNKT---------AVNLVGIQSGETGNTISITEN------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A177L0L1_9BACI
+--------------------------IDDTDRIQKTIDFVNKKGGGVVTFPKGIYLIDA---------EI--SLKLKDNITLKFEKGAILKALPNNAESYEIVKIHDVENVSLLGDTIIGERKEH-------IGKTGEWGFGISIRGAENITIENPFIKDCWGDGIYIGATTKKKY-------SKRVTIINPLIENNRRQGISVISAVDLTIISPKLLNTNG--TSPQGGIDFEPNSEN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A150W909_9BACL
+--------------------ATGNGEVDDTIAIQNAIDFAYSNGNKTVFFSKGIYLVDSSTSL-----------VVKDGIVLKFENEAILKAIPNALERSEVIRIHDVKNVKILGPEIIGERDEHLGS-------TGEWGFGVSIRGAENIYIENAKISNFWGDGIYIGSTAKKNY-------NINIEINNVELTNNRRQGISIISVENLLIKDATITNTNG--TSPQCGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1G2XYR5_9BACT
+--------------------------------------------------PSAVYNIDADGTGDQ-----SAGLKLPSDVNVAFEEGSKLKVIPNSSTVYSVITITGKNNISLSGACIEGDRNFHTGT-------TGEWGFGISISNSQNITIKDVNVYDCWGDGIYIC------------SVSDRVTVRDSIFNHNRRNGCSIISAKNVLFENCVFSNS--DGTSPYKGVDIEPNYENCRSYNNPVSITFSNCSSDGDGTGAGPRNTLGTITFRDCTSTNAVENGFSINTVIDGLYIVNPG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6478735_8854003
+-----------VDVREFG--AKGDGRADDTDAFEEAIEALPAGG--ILDVPDGDYMIDTLRSIRLRD---GIHLRLARNARLIAQPNAA----PRSY----VILLRNVRDIRITGGAIVGDRDRH----LGLDG---EWGHGIAIYSVRNLVISGIHISKCWGDGMSIG--GKSAQKGQPATPSMDIEIANVTSVGNRRQGLSIGRSRRVWVHDSEFSGTGG--TPPQAGIDVENRGPGIQVWKDTHDVSISDCTIEDNRNAGILAVDATDVTIRDNRIRDNTQVGITRQVSISGN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1C7EEP3_9BACL
+--------------------SYGNDKMDDTQFIQNAIDFQSSKGGGVVYFNKGEYLIDSTKSITLRD-----------NITLEFEQGAILKAIPNSAERYEIVKIHNVKNVNITGQSIVGDRSEHTSSL-------GEWGVGISIRGAQDINIENVSISDSWGDGIYIGNTSKKNY-------SENIKINNSNFDNNRRQGITVVSVKKLEIINATITNTNG--ISPQSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1I2HG07_9BACL
+-----------------------------------ARINAAINSLPTVYIPEGTYMI---NTGNPYNPVTNATISLKNNITIKMTENTVLKAITNAYNNYAIFLVRAVSNVTIEGGILQGERYTH------TGPTAGQVGVGVWLEGATNVTIRDVTCKEFWGDGIYTLYHSTLG-------NTKKVTVENVSFIDNRRQGISICANENFRVIGCSFEPAAGIDIEPELGVTITGNVFKGNKIGGDASATITGNVFEGNTMGIYLASSSRYYSVTGNIVYASGNYGISTDNVISGNVVYNNG--------SHGIYLLNNADRNVITDNKVYGNS------GEGI----NVYKSFDNII-----------------------------NDNNVTNNKGRG----IFIAVSTDNSING-NTSSSNALSGIYLWNSKYNLVDSNRCSKNGQ-HGIFVKGDAANDSLSNSI--------------SNNQCKENSQTTNQGYQNIFLSSGAQGANTINNVQGNMCRAGGYGILIDNTSETLLKNNDTRGGGAK--------------------------------------
+>M2U1I2_9SPHN
+--------------------------------------------------------LDVVSPTNGRR-----GLVIPSGSHWVMHPEMRIRALPNASSHYEILNILDEEDIVINGARLIGER--------DTHRGAEEWGFGLSVRGARNVLVENLIAEDCWGDGFYIGS-GRRKY-------SQDILFRNTKAIRARRNGLSLISVRGFLSEDHESAHTFGSA--PQWGVDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690349_1434838
+--------------DVTSMGALGNGVHDDTAAFQSA-IDALPADGGVIDVPPGTYMIDATHTCPGRGTALQCGLILRSHVALSMDVGAVLRVIPNDQERYYAIYVRGLSDVEIVGGRLVGDRTTH----LGT---TGEHGYGIAIAGSSNVRVRWTEVSNFWGDGFIVSRTGGDTNP----TYSRYVTLDHVKSSNNRRQGLVAGGVQYLLVQYSTFRDSNG--TAPEAGVDFE--------PDEPTVAPVSDIRLYDN---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_575702
+----------------------------------------------------GTYIING--ELEGHTYESVGGIILHDNIILQFAEGAILKVMPSESEFYSDITLKDCNNVSVLGATIYGDRSEH-------RGVTGEWGHGVKVIRGENINIKNVRVSDCWGD-------------GVYFRDTKNVTVEYVISDNNRRQGMSIVGGENIYVRSSVFKNTNG--TQPETGVDI----EPNHDYQVVKNISFNDCSFHDNVSKGLMLFTNGGT-----FEDIVVN-----NCSFSGN-----------GAESFRVSGRGNHCNIKITNSTLEHMALGTSA---------THVLNAS--------ADNVIITNNYID-----KIVLNNTSNSIISKN-----IIIENIVLVDSNNIRIENNIFNDLYDEVYDDASKYIYITNN--TISGGKRGVF--VQSTEFLSLYSTINIKNNMFIGLTE----------------------------------------------------------------------------------------------------------
+>SRR3546814_95907
+-------------------------------------IYALPSTGGTVVVPDGTYMIDAVRK-----------VRLRSRMHLKLSSGAKLVAKTNSSPRYYVLDDGNASDLEISGGQIIGDRHRHTGT-------TGQWGQGIMIRGCRRVTIRDMRISDCWGDGMSISSI-RLNGRYDPWTPSNDVVIANVVSTGNRRMGLTLGGTRNIRVHGCEFSNTRG--IEPGCGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>R6GIV0_9FIRM
+-------------------------------------------------------------------------LTVHSGQRLLFD-AATFQLTANGYDFYAVLNIHNVNNVTVEGGTIIGDRESHTAT-------TGESGHGIRIVNSHNVHVSDVDIRYTWGDGVCVGGNGTM------AEISQNVTLERIRTYKCSRNGLSIIEADGVVVRDCDFTYT--DRTAPQYGIDVE------PNLGTATNITIENVRMLNNGIGGFALYTT-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A088F0B6_9SPHI
+-----------------------------------------------------------------------GGVALSSNTIVYGNNAKITAFADYNQPAYNIFRIENIENVIVKDLELIGDRNSHTGTL-------GEWGYGIAVLGSRNILLNNVVSKNMWGDGVNIQMLN-ANQAGVTQTHCSNVTLENCIFSNNRRQGLSIEDGSTIRVSGCTFDKSNGKA--PQCGIDIEPI-VAGRAFVD--GVTIEDCMFSDNNSGILMESLNGPISHKKAKISNAVYIGINTSRNNLNTKIL--GNTFDKSLDTGGMYMAISGNYINSTDTNLPEFYTDNLV------IDNNTL--LSGLTLESGVRK-VTISNNKIESPNTSSIGIFNKSQRLIANNNNNCETGIHSYNTTTTSAI-INENIFKNINIGVVAQLNS--KIISNQFINTGSGYG---------------------------------------------------------------------------------------------------------------------------------------
+>SRR5512133_1390
+-----------------------------------------------VSVPDGTYMINALTS-----------VLLKSNMTFSMSSGAVLKAITNSSSNYSILFANGVNHVNIIGGTIQGERTTHTGT-------GGEWGFGVRITGSQQIVVEKVLAKDCWGDGFYVSA-------------SASITLCNVTADHNRRQGLTITSVDGMVVRNSTFKNTQG-TL-PEDGIDIENAGET------VNNVLITGCTFTSNSGFGV------EIGVPISYTGQAWIKGVVVDNTVTGSGVNTLSTSPRAGIEASDIPS--AGNK--ITNNYCANNGLGILLRSNGMTISGNTVTQNTTDGIQVYSTDGNTITGNTATNNLGRGIYSTSNTNISISNNTVSG-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1X6W0S9_CHLAO
+---------YLIDVNEWGISNDGTNPLETTQGINNALQWAYQNGYSYVKLPEGVYTVSKGSASKDYSENACILLQNDTTLDLY---GCVIQKEANGWDYYAAISIVEKRNVTILGGKIVGDHLAHDYATL--ANSIHEGCIGIIVRGSRNITLNGVEV---------------MNFPG------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1035438_889792
+-----------------------------------------------VMVPDGTYMVNAV-------AQNAAGIRLGSKMTMKLSSGAVLKAIPNASGNYAILAVSFASHVTIVGGTLLGERGSH----TGTDG---EWGMGLSINNSAHVVVQDVTAKECWGDGFYVT------------SLSSDVTLCGVVADHNRRQGLSVTSVEGLVVRNSTFKNSVG--TAPECGIDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>WorMetHERISLAND2_1045183.scaffolds.fasta_scaffold180453_1
+---------YYLDPVVAGITVSDTIALANTVAINTALETAKTEGNTTFVVPTMDAYFDTGGNGNSREEEVSGAIQIPDNMHFKMGAGTVLRRQPNDNRGYGSL---LGENVEISGGTLIGDINDHTYVLMDDDNTTFEFGFGISLYGAHNTYIHDITIRNFHGDAIFIDKTGLRNIDATLFRTCENVLIQRAYMQNNRRQAISVVDCNGVIIDNCDIVDTGRDIYHPAYGIDLECYRQLGAEYARVENVIIKNSRFSGNRKGDLNLYNSQYVQVFNNEFTYKIGHVASNNVSIHDNTFTYDPIVYPENTDSVAISITELVYDFDIYSNTISGYTFGIIVSGDRFNVYSNNISN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_498154
+-------------------------------------------DFGSIVFPSGTYMVDG---NDPAGPGGRQGVRVPSNRAISWLDGAEVRVIPNSNTGYNAFLVDQVENVLFLNPRIKGDRDEH-------TGVAGEFGMGIEIRSAENIVLRDPYIYNCWGDGIYI---GQVSEAA---GPCKDIYIERGKVDNNRRQGMSVISVDGLFVDNTQFTNTNG--TPPQAGVDFE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0Q9EPM5_9GAMM
+----------------------------------QAVIDALPADGGTVYVPAGNYIIDPTRNLRLR-----------SNMHLQLADGAKLLAKRNSADRAYVLMAYKVSDVEISGGQIVGDRDNH----LGT---TGEWGHGVMVRGSSRVTIRDIRISRCWGDGISVGGAIVTGLPTVI---SQSVVIANVASTGNRRQGLSIGRSSEIKVYDSEFSDNVG--IAPGCGIDVEGNQGNGQVYKRVKGITIKRCTIEYNGYGILTAPVSGYIAIAHNYLMGVMLRSATTSYQVSGN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2G6EWH0_9GAMM
+-----------IDVTDAGYDAKGDGTTNDTTAIQKAIDAVADAGGGVVWIPKGRYMIDTEARLKMR-----------SNVTVQMTDDTVLEAIPNGAGSYSIFRFYNVENAHLLGGTLVGDRDSH----LGT---SGEWGTGVNISSSSNIRVENIVTKDFWGDGFYIGENGSLD-------KSENIVLYNVVGDNNRRQGLTIVNGDNIKIIDSTFQNTHG--TAPAAGICIEPNDNN-----LVSNVEILNCKTINNDGDGIGLYE--RVNAINNEIEN---------VRVDGNEIINSGGIIVSG--SV-TDSTITNNFINTTDSSEPGIRL-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_10317103
+----------------------------------------------------------------------GASIRLHSNSQIVIAPGAMLRAIPNNLNNHALFYCYDAENVYVTGGTLLGDRDDH------TDAEDGNAGMGWRISASSRVTVERQRILDFWGDGIYV-RNGTVETED-YDTLSTQVEIRQVECNNNRRTGIAAAGVEGLTVWKCWLRNTNGANAGANFEPNIDGYGNAGAGFQSGHDVTFDACTGRGNGNGFRILNTTG----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>S3Y1Z0_9ACTN
+---------------------------DDTAAIQRAINQASDAGGGTVNIPGGTYMIDSVHGLMMRN-----------NVTLKLADDAVLKALPTNTTHYSLISFVKVENANLVGGTLIGERYQH-------TGQGGEWGHGVNIQSSQKVTVQDVTSKDFWGDGFYIGQAWQV-------WDARSNQVALCNVTNNRRQGLSIVDGTNIRVLNSTFSRTNG--IAPQAGLDIE--PENGNLVEN---VEVRDSVFSENGDGI------------------VLTWGEQNDASIKG---------------------------VRLESNQVLDNESGIMLRAIGCQVINNTIRNAGN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_4714463
+-----------------------------------AIDYAVEKSIDLVWVPKGVYMIDAAGVNGEK------GLRLRSGITLKLHEEAVLKAMPNNVANYSILRVYDSANVKITGGSILGEKNEHTGT-------GGEWGMGIDIQSSNNIEISNVKVKECRGD--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1041385_954775
+----------------WG--ALGRSSPDQTKDDTQALQAALDSGARKVTIPNGHFMIDAARVQPGRTK---AGLNLPSNIELIMGTETFLHARNNSSISYNILVGWKVSNVIIRGGVLVGDN-------VTNSRRSNPSGFGLALFGAKNVWVYGLTSQEMFADGFFVCYD---DEPGS-HDECENVHLMDCRAYKNYRQGASVIGAKNSSIEGGQYRQTGGSP--PQDGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5581483_5383682
+--------------------AMGNGSMDDTKAIQAAIDALPESGGTII-VPNGTYMIDALK-----------GISLRSHDRLSLASGAALKAIGNSERRSWVVKVWNVNNVEIVGGGVIGERYSH------RGTSGGEWGYGINISSSDKVYVHDITIQDCWGDGLLIGALG--SGKGMV--EATNITLNRVKSKNNRRQGMSITPANRVYVVNSSFTGTHG--TAPESGIDIE---PRSQGWASQVRLENTDLS-NNNGNGNVDALTLYKVTAKNN---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1G7HPV6_9FLAO
+------------------------------------------------------------------------GLRIRSNSKLYFQKESLLKLKSSAKVLYAILNIAKVENVSIYSPTIEGDRYRR----VNPEDKKGEWGMGIWIQESKNISVFNAKVTHCWGDGIYIGG-------GRDIVPNDSIYIHRPIIDENRRNGISITSGKNIRIIEPVVSNSRGKS--PESGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1G2Y1Y7_9BACT
+-----------------------------------------------IRFPAGTYAIDGFDTIDKGNVTVYGGLKPASDTTLIFDIGAKLKAIPNDKIGYSILKIEGKNNVKIYGPTIEGERDSHTGT-------TGEYGMGIMLEGATNIVIKDANVYNCWGDGLLIGVHWT--------KPSDQIYVENSTFNNNRRLGCAVTNGTNILFKKCTFLNSNG--TAPQAGVDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1035438_766262
+----------------------------------QACINAVAGTGGTVVVPDGTYMI------NATHGSGVWGLMMGSNMTFAMTSGATLKAITNSSTDYGILCSNGASNFTITGGNIVGERSTHTGS-------GGEAGMGIYLNAS-NVTVSGVNVSECWGDGIYIC------------DASSNITITNCISNHNRRQGLSITAGNTFLISGCTFSNTTG--TDPQCGIDIEPNGSVPVTGVH-----ITNCQIFGNAGGGVQQGNVGNV---------------ASGTLLENCNIYSNGGG---GYNDGGIRFVETHDNI-IRNNNIHNNLNGMLDTNAGIGCPNNTVANNSGWGIYANLCNGSAITGNTI--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_3394488
+----------------------------------------------IVDVPAGTYMIDAETSILMRD-----------NTHLRLATGATLKAIPTSSAVYNVILCELVDSVEISGGAILGERDAHTGT-------GGEQGHGIRSRGATNVYIHDIHISKCWGDGI-DAGPDKSDSHNYVYT--ENLTIDNVVCTQNRRNGLSIGNVNTARVTDSEFSYTNG--TSPQCGIDVEPDGDADGDGDCS-DIVIDNCRLNNNAVYGINLYQRARVTISN--C--VIEYNSSCGIVSNG---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_325582
+-------------------------------------------------VPAGKYLINPVRVASGTS---FYGLLVGAGKRLEMDPNAVLVLKPNSAPRYCGVRI---DGGYMQGGQVLGDRLSHNYS----SGGTHEWGYGVQLRGTDSKAV-GVKVSQCTGDGF-----GMSGI---------RPVIENCISTQNRRQGVSLFGSDGLRISGCEFSNTGAAGTNPRCGVDFE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1E8BK68_BACMY
+---------YFLELERWNVKNDGTDANNTSKGINNALLWASQQGFIEVVLPMGIYLID------ENTP-----IEPQSFMTLNLG-GATLKIRDNGLVKYAIVYQRNQKFSRITNGRIEGDKDTHDYTTIP---HTHEWGYGIEVEGSSYISIDNMEILNCTGDGI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5512142_681238
+-----------------------------------------------VYVPRGTYLV-----LADGYRDGGGGLAPRSRTRVVLAPDAVLQARPTGSSDYVVVRIERVSGVTVEGGTIRGERHEH------TGRGG-EWGFGIGIFGASDVVVQDVTIRDCWGDGLFIEE----AQPDFSVMP-RNISIRRVVSANNRRQGMSVPG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>D7W8T5_9FLAO
+-------------------------------------------------------------------PLMTSGIFAQSNSQIYFQKNSSLILKPTADVRYQIISLHAVENVKIYNPTLIGDRDRHLGS-------KGEWGFGIDIRGSRNIEIYNANISDCWGDGI-VLVKTMRNMRSGVIFPTENINIIGGFINNVRRNGITIAGGKDIIIKNLLIANING--TNPMAGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_487370
+------------------------------------------------------------------------GIVLSSNTNIYFDVNSKLILKQSSKESYSMLKIYNVENVNLFNVHLVGDRYQHIGS-------EGEWGMGIRIQNAKNINIYNSTIRDMWGDGIYITSFG--------NTSNQNILIQSSWIDNTRRNGISIISGEDINIDYVKISNTNG--TAPASGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>H6LBC8_ACEWD
+-------------------NAKGDGKTDDTSAIQNAL-----NKSDSVYIPDGTYMIN-----------VDQSLKPNSNQTITMNANAVLKAISSSRGEQYVITIDGVTNVSIIGGKIVGERNEH--QGLDG-----EWGMGINVNGSSNIVIKDTTISDCWGDGIYLGGSPAVN----------TITIDGVTSDNNRRQGLSITNAKNVLINNSVFKNTNG--TAPEAGIDIEPYGNNQSGIDGIQRVEITDCTIKDNGLGILLFEASGNTSVTNNKDDGV----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6185312_3767693
+------------------VGAVGDGTTDDTWAFQKAIDSVAAQGGGTVYVPAGTYLIDADVSINMKD-----SVTLD-----MVDTTRVLMAKPTATVRNYVIKLNNISNSKVIAGKIVGDRYQH----LGT---TGEWGMGMGINGSTNITVTGTNIIDCWGYGITISSYNCV---------LKNVI---CD--NNRRQGLTIGSSDSLIVDSCTCTHTNG--TAPQDGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0D5BSE2_ELIMR
+------------------------------------------------------------------------GLVLNNNQVLLFQEKSVLKLNPTTQKEYSVLGLSNVNNVKIFFANIEGDKYQHLTNV-------GEWGFGIGIFSSNNISIYSPYIKQTWGDGIYIGQ--------IKNIPSTNIQVYNAVIDDVRRNGMSITSAKNIDVVNAYISNTNG--TSPESGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_13262863
+------------------------------------------------------------------------GLKLRDNSKVLFQQNSVLILKPSSKSQYSIILMDGVSNVKVYFPKIKGDRVGHKGT-------KGQWGMGIWINNSQNILVHNPYITNCWGDGIYLG--NVNNRP-----PNKDIQIIDGMLDNNRRNGISIISGRNVEINGTFISNTNGHN--PQSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1035438_2623855
+------------------------------------------------------------------------GIRFGNNMTLRLDSGAILQALSTSSSSYRILLLSGVQNINIIGGTIIGNR--NNNTITDSV----EDGMGIQIANSQHVVIEGVTVQDCWCDGVYVS------------DGSGDVTLNGVVAKNNRRCGSAIVSVSGMVVRGC--------TFQGTTGMMENGLWANGTGVDVEPNLTVQNIQFLGN---TFTQNATGGLGIGPSNAN--MATTFVINCVIDGNTVSSNGDAVK---GTFGIVASSTGGH-QILNNTVNNYGVGIYLYGSNILIQGNTVSGTS---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2A8TS41_9BACI
+-------------------------------------------------IPDGTYMI---------NADI--SLKPNSNQILSLSKKAKLKAKPNSDASYQIINIIEKENVIIEGGYIEGERDEH----VGVNG---EAGMGISVRNSKNITIRNTHISKCWADGIYIGG----------YLPCYNINIYNVTCDNNRRQGMSVVNVDTLTVRDSFFTNTAG-TL-PEAGIDIE--PEN---YSTVKNVTIDNCTGNRSGLDVFWAKTISNVQVLNSSMINNREYGFTTDILV-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5687768_6663082
+-----------------------------------------------VYVPAGTYLVDATRT-----------IRLRSRMHLKLDPGAKLLAKATSADRYYVVNAYKVHDVEISGGQIVGERDRHIGS-------SGQWGHCIGVRGCKRVTVRDIRLSKGWGDGISIGAAN-----GTTTVLSDDVAVANIVSTGNRRQGMTIGRCRNVKVYDSEFSYTSG--IKPGCGIDIE---------PDPFTIRIQNCWIHHNGNGVQVYKTVKNVTIK-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_2031064
+-----------------------------------------------------------------------------SNSYIKFHPDAVIKVNPNNYGDYDRKYIYMKDNIVIKNPRIVGDKHEKNYKKIDSE----EWAAGIQIRKSNNIKILNPHITAMWGDGISSAGRKSMGEP-------DNILISNCFIYDNGRNGYSITASSNTKVFGGIISKT--DRTEPISGIDVE-----PAQYSRDVSLNIKDVKF-TNGRGLILFKASQGAVIED----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5688500_1121635
+---------------------------------------------------------------------------------------------------------------IVGPGRITGARMVHRGS-------SGEWGMGISAWNSTNFRITGVEIADCWGDGIYVGSAGNGYCDGFLI---EGVKVRNC-----RRNGISVVAGRNGEIRNLDIAKI--DGIAPRGGIDLEPNSSNAPNRN----IRMSNGRIRDVAVGIYVTVANQRVSISDIEAENIIVSDNSVDVRIENNPNIKSIGGKEGGAFRTVVTRPETIRGLLIRNNQLSGFVIDIFGQGQGLVISGNRISNAGTQGIA----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_32025263
+------------------------------------------------------------------------GLKVKSNSVLEFQENSLLKLKASDKHTYNILEIHSVQKVKILNVKIKGD--------LDTHGKDGEHGMGISIRSSKDVEVVNAKIEDCWGDGIYIGRLNRYDRNGM-FEPSENIIIRDAYVNRNRRNAISITAGRNNLIDKLDANKTKG--TFPIIGIEIK----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5579883_944156
+-------------------------------------------------------------------------IQLRGRQEIIFEPGVVMLAKKGEFRGTGDSLLSIVSNLVLRGYGAILRMHKPDYQA--EPYKKGEWRMGIAIRGCKNVLIEGLRVESTGGDGFYVDGGADRGW-------SEDITIRNCTAYDNHRQGLSVISAMNLAVENCVFASTRG--TPPEAGIDLEPDTEENRLVN----CLIRNTVFQNNNGHQVLIHKSMPVSIRFENC-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1T3DZL3_9FLAO
+---IKKDGSYYERQFEGGINPAWYGEL-TEKSINKALHIASVLN-------------KDVELMNDYKIDCSGGVKLLNNSVLRFSNNARLLAIPSSSGNYRMLSIDKVKNVKVYNPVIIGERSAH----LST---TGEWGYGINITNSQNVEIHNAVVKDTWGDGIYIGG-DYFDKTQTISTLTDNVLIYNPYIDNVRRNGISICSVGKVRVYNAVIKNVNG--ANPQSGIDIEPEGDTG----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_10516162
+-SLLDRIVLYVDDF-----GAVGDGVSDDTDAIQQALNVAGELRTSVIFTKGKTYMTDG-----------SKGILPPSYSTLIMTGSKL-EVIPNALDRYICLYVLIAEHVTIIDPDLKGDRSNHSTNNNNVDGFTGEWGFGLRIARSKNVNVYNCKTSDFWGDGVLIGTDGIENTP-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262249_48802186
+---------------------------DDTSAIQAAIDAVAEKRGGTVLVPNGTYMVSAVR---------DNRLSLKSNVTLRLANDAALKAIPNDSDHYSVLRIANVSNVAVIGGTFEGDRNEH-------SEKTGDWGMGIWIKGAEHVTISGVTATKMWGDGFYI---------------QDANDVRLCSVENNRRQGLSIIQVNGLEIKNSTFKNTHG--TRPSAGIDIEPDNDE----QHVANVRIHDSKFLDNGAGIAVVAKKSLVS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1700750_2813068
+-----------------------------------------------VEVAAGEYLID-----------VTKSVKLRSGVALVLDPDATLRAIPTDAGNSAVIRIHDATGVRVEGGSIVGERDKH----LGTNG---EWGMGLGARGSHDVLIQDVLISGCWGDGVYVGS--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR2546423_7159601
+--------------------ALGNGVVDDTAGINAAIRSLAGTGGSVL-IPAGVYLVD---------PTV--SVQMASNVSLLLDDSAILQAVPVAAKSYAVIAASGVHNVKISGGKIIGERQTHLAA-------TGEWGMGVRVMGSSNVQIERVE---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5680860_103890
+-----------------------------------------------VLVPNGVYMVQAV----------GESLALGSKMTLRLADKATLKVIPNGETRYYTLRIHEASDVTVIGGTLLGDRRAH-------KGKKGEWGMGLHIVRSSRVTIAGVTSTRMWGDGFYVA---------------DGTDIAFCSVANNRRQGLSIISANRLLVTDSVFRDTRG--TRPSAGIDME-PNKASQRIAH---VRIERSKFIGNGDGIVIQGYKGRVSIRNNLFD------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1Z4RLG8_9CHRO
+------------------------------------------------------------------------------NQKILFQPGVVLEAQPGAFKGYESMVSVMADNVTLSGYGAEFKMRKADYANPSLYEKS-EWRHNIHVRGARNFIIEGLTLKDSGGDGI-LVEHGPNEPNQLPVSKYSSGTIRGINASDNYRQGISVVSAKDLLIENSTFQNTSG--TEPASGVDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2B2C9D0_9BACI
+---------YILELDVWSVSDFNDKTLSTSNGINNALTWASQRGYSEFMFPKGTYLIDE-------------NIPIPKNFMTLNLNGSTLRIRNNGLPKYS--VICYRQNQIVTNGIIQGDRYDHDYSN-PGELPTHEGGMGILFPNTTDTTIDNIEFLDLTGDGV-----SLFSSQGLVYTPTKSYAI-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2C2T0P3_BACME
+---------------------------------------------------------------------------------------------------------------------------------VDNERYTHEWGQGIEIAGSNHVEIKNIEICDCTGDAV---STGWLKYNSTDYTQNEHIWIHDCDIHHCRRQGITLASANDVCVYNNKIHHIGRNGIPPMFAIDIESVGESNIPYKQPYRLYIFNNHIHDNQRGHFVNADGNHVTVENN---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5215813_7905647
+-----------------------------------------------VFVPKGVYVVDAV--AKKRRLTLG------SDMTLKLDNDAVLKAMPTDSRKYSILTVSGVSNVTIVGGTLEGERAQH----MGNDG---EAGMGIRVGGAEHVTVSGVTSRKMWGDGFYVEDANDTKFCG--------------ETSDGRRQGLSIIEADGVLVTDSVFSNTHG--TRPSAGIDLE--------PDHPSQIRIQNSKFLNNGPGIEIAGKKGLVT-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6185312_5921845
+----------------------------------------------------------------------------------------------------------------------VGERQNHVYSGIGTG--TDEWCFGIQILGVTGMTIRGTQISQCTGDGIDLGNFGS--------SISSDIVICDVISTQNRRQALSITGGDGIFVYDSEFSYTNG--TAPLDGIDIEPGGAGAS------NITIENCLIRGNGCGQLNAHWGDIINVNVKNC-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690625_4101829
+------------------------------------------------------------------------GLEIHGNSTVFFDEGSVIKALPTSNGNYSILSIKGVDNVKIYNANIFGERNEH-------QGDTGEWGMGIRIEDADNVLVVNLKVSDCWGDGIYL----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1H6XJ90_9FLAO
+------------------------------------------------------------------------GLNLRSNSVLVFQENSYIWLKASSKPNYGVINIKDIKNVTLINPRIVGDRDSH-------LNKIGEWGMGINILNSDYINIFNAIISKCWGDGIYIG--------NKINGFSSNININGGLIDNNRRNGISIVSGEVVVIKDITVSNTNG-TL-PMSGIDLEPNTNEDTLKDIKL-VNVNSFNNRENGLGGLLGENKREVDISDQYSNTVVSIGLRNDYEKKVKKI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5512133_257377
+-----------------------------------------------VTVPDGTYLVNALTS-----------IQLRSSMTLSLSGGAILKAIPNSSSSYTILRISGVSNVNVVGGTLLGDRSAHAGT-------SGEQGVGLRITGAQHIAVVGVTSKECWGD-------------GFMVADASDVTLCNITADHNRRQGLSITGGNGIVVKNSSFINSQG-TI-PEDGLDIE--PNSGQIVSN---VLITACVFANNAGDGI---ENGVPVL-------FTGLAFIYNVVIDGNTMTGNGVGTLHAGPRSGIEVSNTSGHV-IKNNTIQGYGIYLRDGVAGTTVTHNTVKNALN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A110B3A3_9SPHI
+------------------------------------------------------------------------GLSLISNSTVIFRKYSKLVLQANGLPAYQILRIYNATNVNLYFPVVQGDR--------DLHSGNGQWGMGISISGSTKILVVNPKVSKCWGDGIYL---GRQN-----NAVDRNITIFYAELDNNRRNGLSITCADGVHLIRPIISNTAGQM--PMSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A229UP75_9BACL
+---IGSPVSYAIELDRWGIQNNGTDAETTTRGINDALVWAKSAGYNHVVLRGGTYLI-------QVDPN-GTAIYMPSGMHFEMHHDCILQLAGNSFPNYRMIEMKGIRYAKVSGGKMIGDKAFHQYEM-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262245_13989197
+-----------------------------------------------VVVPNGIYLIDAAGE---------NRIKLKSDMVLKLSDGATLKAIPTDAENYALLTIADASNVWVIGGTLEGERDRH-------KGKSGEWGMGIRIEGAKYITIMGLTSRKMWGDGFYVRG---------------AEDVRLCGVDANRRQGLSIIEADGLLVQKSVFKNTRG--TRPSAGIDF----EPNRDSQEISNVRIENSKFLDNGAGILVAGKKARIT-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5215831_1849565
+-----------------------------------------------VLIPAGTYMVNAVDS---------NRLSLKSNVTLKVANTAVVKAISNDSEHYSVLRIANVSNVAVIGGTLEGDRNQH-------LGKDGEWGMGIWIEGAEHVTISGVTALKMWGDGFYI---------------QDANDVRLCSVENNRRQGLSIIQVDGLEIRNSTFKNTHG--TRPSAGIDIEPDNDE----QHVANVRIHDSQFIDNGAGIAVVAKKSLVS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>OrbTnscriptome_3_FD_contig_123_161973_length_414_multi_3_in_0_out_1_1
+-------------------------------------------------------------------------VKLRSNINIVFEKGVVVEASQKGNAKYPMFEVKNVSNVAFIGGDKPGDVYIGKYRDNEERRRCHDYGSGFAIEGAQNVVIRNVKVAECSVDGISLSSLGRLN---------SNIYVQDVILDGNYRQACSICNADGLYFKNAFLNTSGGD---PMCGIDLEPTYE----LEPNSNIYLFDCRFEGNVGGGLTSSSYYPVTLHAKRCD------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262245_2037218
+-------------------------------------------------VPNGVYMVSAVE----------NNLKLKSDMTLKLAGGAVLKAIPNDATHYAILTISGVSNVWVSGGTLEGERSEH-------RGKLGEWGMGIRIDDAKNITIAGLSSKKMWGDGFYV---------------QEAEDVRFCGVDANRRQGLSIIDANGLLVLNSTFKNTRG--TRPGAGIDLE-PDKDAQQITH---VCIENSKFFDNAGGGIMVAGNKKARV------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0D4DCI2_9CAUD
+--------------------------------FMVGYIYATSKNRPVVDIP---IYVQSTRKQSGFYNQVHYAVVAQSNSILWFMPEGLIQIGVD-EAAYSILSLYGADNFLIKNPKLRGDKY-------TKTGNTGESGFGLTVTGCSNGIIEYPNISECRGDGIYLGQEYFNNNASSLI--PKNIKIIKPTILDSYRNGLALSAGEDIYFDAPFIDIAKG--TAPEACIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5688572_15557399
+-----------------------------------AAIQAAINSLPVVSIPAGTYLVDTTKRINLR-----------SLMLLSLASGAVLKAKTSSVRRAYILNVNNVRDVEIAGGQLVGERDTHKYVSGTTD----EWNHGIAINGSARVTVRDIRISKC-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6266566_4873650
+-----------------------------------------------IHVPPGTYSVDAV----------SGSINLKSGITLDL-TQATLVANPNNQIFSIIMRVSDCENVTILGGTIRGERTTH---LGSTAAFMGGGGGGVAIWRSKNIKIQGMKISDCFCDGLLVWHSGQVEIQGMSLVDSHDVHIHNSQFTHDIENDLETETCANILVEHC-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>G2KPW0_MICAA
+---------------------------------------------------------------------------------------------------------------------------------------------GIEVQGGKTVTVSGNNMDDVRGNGIQISSQGAVNHGIVVNTAPGAVVVDGNRVTDAGEFGIYTNGSKNVVVSDNRVS-------GGKNGIVVQNAAAS-AKIENNVVSGASDAGRVASGYGILVKDSAGAVSVTDNRSNANTGDGLNTDGAVVSGNITNDNGDK-------GIIINRSDNAV-VDDNRSNGNATGIWVESNGVDLTNNVIRHSKVDGIHLRDSDNTLVQGNQINDRNGIFVERSDSADIFRNTITGSGGYTGVKVEGSSNTDIGATDQT-SWVQTGFWPWQGHFVTVRGNTITNFDNGVTVAGGNDNDV--VRNTISVDYGVRLSGAT---NSDVLGNDLTG-NSIVGIEVVAGSHNAVIDNNTLDHFDT----GIVVNGSNNVDVTDNDLTDVGSGIVA-----------------------------------
+>SRR6266511_2426516
+-----------------------------------------------------------------------GGLVPRSNTHLHLAPDAVLKAKTTSASDYNVVRIERVSNVVVEGGTIAGERHRHAGS-------GGEWGYGIGIFGATNVTIRNV----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1Q6A375_9SPHI
+------------------------------------------------------------------------GLTLHTGQKVYFKKGSVLNLVPTAQPNYEMLRIHDVTNVSVYNVVIKGDKYSH---LV----KTGEWGMGISIRGASNINIYSAKIEQCWGDGMYIGTTPKQAF-------CENINLRYVNCNDNRRNGISVISARNVTILGPVLTNTSG--TQPMCGLDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_4058803
+------------------------------------------------------------------------GLNIISNQILNFSQNSKLIMKTNAEERYGILNIKYVKNVIVNNPNLIGDKEKH-------LGNRGEWGMGINIWASKDVTINNPRISETWGDGIYIGEPPVQE-------------KQKKKLKSYANHNIAIN---GGVIDDC-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6516164_3930632
+-----------------------------------------------VLVPNGTYMVNAVGDAR---------LFIESNVILKLANDAVLKAIPNDSKKYSVLRISNASNVAVIGGTIEGERYGHSGNV-------GEWGMGIWIEGAEHVTISGVTAAKMWGDGFYI----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262245_45879959
+-------------------------------------------------VPNGVYMVSAVE----------NNLKLKCDMTLKLAGGAVLKAIPNDATHYAILTISGVSNVWVTGGTLEGERSEH-------RGKLGEWGMGIRIDDAKNITIAGLSSKKMWGDGFYV---------------QEAEDVRFCGVDANRRQGLSIIDANGLLVLNSTFKNTRG--TRPGAGIDLE-PDKDAQQITH---VRIENSKFFDNGGGIMVAGKKARVS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_56255
+----------------------------------------NENN--VVIIPKGTYRVT--------------GLKLKSNFSLLFEEGAELELIANNKERYEILSLAGIKNVKIYNPVLIGD-------IRKRNSLKGEWGFGIDIRGSREIDIYSPFIKDCLGDGIIIS---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1I0S8N9_9BACT
+------------------------------------------------------------------------------------------------------------------------------FATIEGDRSTHQWGMGIAIRAAKNVNIYAPRISKCWGDGIYVG--------GLKGVTSSNINIYNAMLDYNRRNGMSITSVSGLKLVAPVISNTYGQT--PMSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/test/unit/data/small_bfd.mode5.txt b/test/unit/data/small_bfd.mode5.txt
new file mode 100644
index 00000000..9fe7ab29
--- /dev/null
+++ b/test/unit/data/small_bfd.mode5.txt
@@ -0,0 +1,240 @@
+>O31912
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A163VT74_9BACL
+-----------IDPAKWGISTDGTNSRATTDGLNAALADAKSKGFGEVYLPKGKYLIDAVCKTN-HSPEIGGGIRVPSNLKLTLDSEAELKVEPNGSYGYSCIFLDNVHNVTITGGIVTGDRNEHDYS--NKTKPTHEWGFGINVRGGTNITIDNVRIKDCSGDCIYVNAIGMINYGTVPYTPPQKVMIQNCTLDGSRRNNISISACDGVVIRNNLILNAGIQTdagpgfkskIGPGFGIDIEGYGEGDIDYETPLNIVIQGNQFRGNRVYSVGNFNGYGVVIEGNFADNTLSYGNGTDTVIANNVLIRT-DRQRTGIDGQGVSQGLEANHVTIMGNIVKGFGSGMDIRGKDVVVTGNALSHlgEAGVGIAAFAAENVWIANNSVHRTKGTPYRIASCKDVQLVNNKAHGSDKT-AIEANASSQVILRGNVVRDCSGGIkvtnissEASNSEVVvesnHIDLTEY--KGKtAYAISFDSKSEVTLKGNRIPGPRNTAIYGEGGIgKRAKIADNEIADANSFTAmIQIVGGAKHEIVGNNVTFNKSSNGGVGIYLKDAKDSIVAKNTVYSNSEYALTHSIATKESTGTKVLNN-------------------
+>A0A090ZKM7_PAEMA
+---------YVIDPAQWGIKTDGTEAVKTTEGLNKAIAHAKSAGYNEAFIPKGTYLIQGVGTTFPNTPEKGGGIVVPSHMKLTLDHEAELKVQPNAERGYSCIYLRKVQNVTISGGIITGDLDQHDFSKL--PKSTYEWGFGIYVHGGKNITIENMKIRKCIGDCIFLGSVGLLGVDPDYDKPEK-VAIRNCSLDGARRNNISITAADGVFVENNVITNAG--TVkgtKPWAGIDIEGYGEGAIDYEEPRRVVVRGNVFRGNAEVSVLNFNGYGVIIEGNHADNTFSYGNGTDTVISNNVMVRTDGSK-VAIAAQQVSNGYDGNNVTIVGNIIKGFSSGIDARGKDVVVTGNTVShlgNTGGTGIGVWDAENVLVADNAVHRCAGLPYKVDNSNDVQFLNNKAL-HSERFGLELDKSTNVVLRGNSFGQCNGGIsiknWGTKGTSVFAEGNYIdcaSYTGKqtnNYAISFDKNSDVTLKENYIFGSRSVAIYGESSAGKIvKIADNEISDITGNSAIQIKGGQRAEIVGNRITFKRKDDAAYGISLaDNAEDAIIAQNTIYSNNGKSIPNAIVTESSKRTKVLNNLLINGKMLLNKDDTNI---
+>C2WEL3_BACCE
+---------YLIELSRWGI--INDGSKETEKEINNALQWAYDNGINRCILSSGTYLINAVGPPNDLQ---AGGIKIPDNMTLDLWHDTVLKVKANDSYSYSCIYLYNKNNIKIRGGTIQGDRYHHDFSTAPTGKLTHEWGRGINIIGCSNITIDNMNIKECTGDAIDVLSIGLMN--TQVYIPSSNITIRNCTLDKSRRNNLSLEGCDGVLVENNVITNAGiDDGTAPRFGIDIEGYGEGATDYVVPLNIVIKNNKFEGNVTTSICNFNGYNVIIEGNISDNTISYAYGTQTIIS-NNIFKRVDLTTKAISSIGTAQGLDFNNTTITGNIITGFDTALDIRGKNVTVSSNIIYDVK-IGISLFQAESILVQGNLIKKATFGKaIIINTCTNIKCTENQLK-DIGMLCIELNNSSAVTINQNDIFNSKQGIRISKSNAVlqgnSIDLNTF--NSPSYNIDFDATSNVLIINNLLKNCSSFAInlsNGSASSKS-RIIKNIIENFTAISAINLSGG-RHELIDNILIANKNIAGGYGINLHSCNQSTVLRNHIFSSSIYNLSTPIKTNTSTNTKIIEN-------------------
+>A0A238U6X6_9FLAO
+-------------------------------------------------------------------------ILLPSNFHLSLHEETVFRVQPNAFPWYSLMTIDKKENVKISGGNFIGDRYEHDYvPFFDrhgLKRSTHEWGVLLLVRGSENINIDNITLKSSIADGLITGSEGHRIYPETVW--NKKVSLTNSIVSDNRRNNISITDGEDILIEGNEILDAGiGETlkdndgntiyssagVAPRFGLDVEpfvGYDdfsfESRKTYEWVENVIIRNNIFKGNEAGSIIVYTGDNVLIDGNFSDHVIAQN-----NTSGSKIINNTlEARDDVRGRIGISTSDyrkfidfdggtlkqyaTGN--DVKNNTIRNFFGGYNIRGNNAEVSGNTVEGATVCLL------------------------INKAENIKVHDNTyTSGAIASKAIRLTDyANNIEIYNEKFT-LSNGFYLE-SIDFNMPNDDFHLN--------------------------------------------------------------------------------------------------------------------------------------------
+>LauGreSBDMM110SN_4_FD.fasta_scaffold226965_1
+-------------------------------------------------------------------------IHLPSDFHFKMSKSTFLRVQPNFWPRGVLLSVYEQKNTLVSGGNLIGDRYTHNYAPIKDElgiaRDTHEWPVLLSIAGCKDVIFEKIYMTDSTGDAcVTGATNGSRDIGGADKKFNQNVIIRGCVMNASRRNNISITDGEDIFITNCIIQNGGnGDTVkdasgnkivtsagtAPRAGIDIEpfrGYNPDGsfRNFEIVKRVTISGCTFKNNRVASIIDYSGINTTIKNNTSDHGFFASFSTGTKFLYNTFKASAINKDKVAIVTGnwiINNTQLSKNNEVTGNKIEGFRVGITTQGDEGNVSNNTI-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_4058357
+-------------------------------------------------------------------------IKVPSNTHLLMSDNTFIRVQPSNNPFSRLLMTYKAQNVLIEGGNLVGDRYLHDYSnvtdEIGVSRATHGYGSLINIAGSQHVTVDNVNIYEGEGDGVLIQISAIRNKDGSIKAgemESSNVVIKNSLIDKCRRNNFSIIDANGVLIENNVISNAGGEhesgqayaGTAPEVGIDLEAYRERRSdgslyEYERVTNVTIRNNEFVGNDVADVIVYTASFVDIIGNTFDNRVGVHAGHDVKIANNEF--TAGERittqiAVSFDNFIVNETEhlTYN-IDVTGNTISGYDTAMKVGTQNVTVSENKIYDFVTGINITDI-ENAQISNNTLE-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1V5WUJ2_9DELT
+---------YVVDTDKWNIPTDGSDPERTSAGLSEALAWAVDNGFGTVRLPAGAYVVG-----REINSMFIEGVVVPGPLRLDFEPGAIIQMKPNDHPFYCILDIADASDVWIRGGTVLGDRESHQY----VGESTHEFGTAVCVgsrGGSERILIENMSLAEATGDGITI-----NDAPG----SSRDITIRGNDIHHHRRQGISIISGSAIVIEDNEIHHIAG--TAPQFGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A090II36_9GAMM
+--LLNSSIhiggdvhlsnaNFVFDNQRWGVvegIVNNEQAKENTRLFQYALNQAHNVHANVFRINKfdASFWVGNYKKFN--STEL-SGITLPSNIKLSMRHDTILRTQANGYARYALLGLYNADNVTIEGGVLIGDRDTHDYK--DPQSPKPYWGHLMKIGGSRNVTIKGVTFKNATADGLSIHSLGTYKRTGSIET--KNILVTDCLFDNNRRLGTAITSGSEIIVEHNTYLNSGqpseaSESVSPAWAIDIEGGYKDHEYLERPYNITIRNNIERNSYRGAFIGAIGDGITIENNNTENTIALG-SVFNSKAFNNTITRDLNKEY-LNPNGLSVAYDGEKMFYPTEEVVGnnevynnklIRARMYISGSGNSIFNNSISN-SLTGITIQKAKNAEIYNNSVHSNveNSIGLSARDSiNNVNVYDN--DFNIEGLAIRFISINE-KLGHENFS---------------MYLNNNRFTSSGY----NKAASVSRSRNVYFNENNFSNIGFI-MYtsdNIQLIGNRV-ETKTRIGLQIEEGNEQIKLHDNLVIHPEKKK---CIRNLSEQIPDIKNNV--------------------------------------------
+>SRR5690625_80756
+---------YELELARWNVSNNGTRPHETTKGINEALNWAKENGYTSLLIPDGTYSIAKGNAENDRHAR----INMLSDMTFLMSNNTILQKEPNGFEEYSVLHVGAgVKNVVIQGGTLIGDREDHNYSgkSGDWSSGTHEWGHGISIVGGENITVDGVKIKDFTGDGIYI----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_9554453
+---------YLVELDRWGISADGTNAEATTDGINEAIRWAQGEGYGRVRLPAGTYLIG-----KRLYDHYTGGIELVDDVALMMDDETVLQIVPNDTWAYCGIAMSGVRNAGVYGGTIRGDRDEHTYG----GSMTHEDGHCICIgHESELVEIDGVTMEDPTGDGVAIVAEGGDG------SSCKHITIKNSEIARGRRQGISIVGGTNVWIENNEIHHIEG--TAPQFGIDIESLNFTSR------DIVIRNNRFHHN-RGGDFENADGKnVWFEENHLD------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>APAga8741243855_1050100.scaffolds.fasta_scaffold124648_1
+---------YTIDNEQFGIYSNNTHARTTTDGINEALNWAKSHGYTKVRFAAGTYLIQC--TWNNRYCAPDDGILVPSGMTLDLG-TATFRMEANNYPAYTIFGIVNKSNVTITGGTLIGDLGSHTYSSV-SGSSSHEWGFGICISASKNVVIDDVTIKNMTGDGVILeGSYAALSNGGRV---CSNIKVTDCTISNCRRQGISVIGAtDSELARNRIYGIKGTD---PQYGIDVEtefDYVVDDLKIHH---NNISDC-----SGGAINCNKGENYDVYSNTVtgDNIIA--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2G5GBI8_9FLAO
+------------------------------------------------------FVIDKLDAYFKIDGPLSEGapvdlaIQIPSNFTFRMSENTHLRVQPNATDKCTLLSVYLnSDNAVIEGGNLYGDRDEHDYSDGIND---HGWGHLFTSRGSTNVTVRNVTMIDAAGDALKLEGEGHAVNPD--YAPTRNFLATGCKFIRSRRNNLSITAADGVVIEDCDFIDAGIHTdksqgTIPGFALDIEALKPN----ELSENIIIRNNRETGSRRGGFLVAIGDKVTFEGNVINSAINLQSARNCIVRNNIVTAQSDiAKEYGAGII-TGRSDRGNLVysnTIYNNTVNGFSTGISISNFDMKVYGNTINNCnrgmsigpvqnseiyentiiSNVDKSAGISMGASLNNVVVRNNDVNVMRygavFANVNNTDESGNytltfKGNNIVSGSSTPINSSHGIELIENTFNNAYEFYNCSNLNII------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A167HAM4_9BURK
+---------------RWGVASNASNATATTDGMQAAIDWASSQGIGQFRVPAGEYLLGKIQTYN-----YAGGIKLPSNMALVLEPGAVLRMVPNDRWNYCVVTINGKKNVSVSGGTIVGDRYNHTYTPSSSGGTAHDEGHAICIEGSSQyVEVQGVYITQANGDGILIV--------GKAPSTPQDITITGNNFDTNRRQGISIVGGARVLIEGNQIHHTKG--TSPQFGIDIEPLGGylvrdviiRGNNFHHNRGGDVVNTRgfniliegnTMHQGEASTTGGDDGRT-----YIDGPIVFWPEADQTIRNNNI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1I1IH73_9FLAO
+-------------------------------------------------------------------------INVPSDFHLIMTDNTHLRQQPNANKRATLLAAYLISNTIIEGGNLHGDRDTHDYSDTSTSQ---EWGHCIRVGASKNVIIKNMNIYDAGGDGIDIHAYGHAYNSHYTYTENLLITNNK--IYRSRRNGISITDGRNIVIEDNEFIDSGVSTslsggVAPGWAIDVEAVRNSGVIFEIAEDILIKNNVERGSKYGGFIIHTGDRVTIDGNTMENSIAYAGTIGSVIKNNNLKSNSETALRGQTTGIIAQNKASSKdNSVYGNTVYGYPIGIKVGDTNLNVYNN---NILECAVG---------------------ISLNTSKDSRIYGNTIKSTT---------ANSRGISNHThdyISNLiIGSGLDENNESAKSNVIDVVgnaIVFNGIKEIENSDTHSIIIKNNIIE--NGANLWLIDINNFEMHDNVI-----------------------------------------------------------------------------------------------
+>A0A238U509_9FLAO
+--LLNNSLTIQGDiqltkneFDfipsKWGIvEGVTTNEISRT---NRDIL---ENNMTFIKsLGASIFKIDKMDAfFNVDEPDIlpsEAAINVPSDFTLKMTNNTHLRMQPNAAIRPTLLATFTASNVTIDGGVLHGDRDSHDYTTINS---THEWGHLLRITGTKNSVFKNIRFEDATGDAIDVHAYGHSFDPH--YTYCDNVLITNNIMLRSRRNHISITDGRNITVEKNDFIDASIHTnkstgIAPGFAIDVEAV-----RHGNPRGISeIAEDIFIKNNTengsrvGAVTVHTGDRVTIEGNKFENSISYSTSIGTIIRNNEIiattyknINNG----TAIVAGRADRYDDNYNGKVYGNTIENYAIGMTVSNKDLEVYANKITN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0P0CI41_9FLAO
+-----------------------------------------EGSFELVKsLGVSTFIIDAMDAYFKVDDENFKGyaytyaINPPSNFTLKMSENTHLRTQPTNFSNYALISVRDVENVVIDGGNLYGERDEHDYS----SGGSHEFGMCLTVSGSKDVTIKNMTITDALGDGIIIDNIG-HTYDSF-YTYTDNLLIQNNKIIRSRRNGISIVEGKNIVIDGNELVDTGITTskssgAAPMWAIDIEPVWENGIKYQIVEYVTIKNNIERGSEKGGFINARGWYITYENNTMENTIAIGETVGSIVRNNIFKNPGKNSNVAIaagmnDPLGYGN-ERNYDNEVYGNTITGFPKGIELQDPGIDLHHNTM-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>J8DZ85_BACCE
+--MIEKVNIYVIELDKWNIKKDGTDAVNTTKGINKALLWAKENDYDVCKLPAGNYLVDK-----------DSNIEMVSDMTLDLF-GCTIRKETNGYQGYSIVRIFRQKNATILGGTIEGDKDTHDYSTIP---GTHEWGIGIDVSGlNRNIKIDSVKIKNTTGYGVRTGTeYGHLSW---VYTTDlESGTfsndgVLKADVNFTRSNkywriteypQIQENGYFSIMGNGYGFygsTKDGGEVNLDRVPITIYFFDESNKFLGKITKRTFDNIYYSSFPKGT----SKFKIGFRFNYNNiNALSMTIRSMTYTKGINVIN---TDIYGCRALGIAITGAQNMLV---DNCEIYGIGGINPGYAIDIED-----------GYNINQNIIIRNNYIHDNNNGAIVVVSARNVLLESNKFYG-----SVFLGGSRGENYLSR--HNLYncsfgtGSTNAGGGDAATITFrDDYMLEGQLYmegNAFYDNvcfDNMTFVLQSDTF----------------------------------------------------------------------------------------------------------------------
+>X4ZGB9_9BACL
+---------YLIELARWGIYNDGTHPVETVKGINNALVWARQKGITATTLPAGTYLIDKASRIN-----------MVGDMLFDLPMDAVLQKETNGKERYDVMYVGYgANNVTLRGGTYLGDKLTHDYSQRDPyNTGTHEGGYGIFVEGAKNTTIDGVKAMNFTGDGLVLGGFGTM----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1A5YEI2_9BACL
+---------HMIDLKRWGISSNGTKPVQTTQGINKALQWAAKSKITAVTLPPGTYLIDK----NSR-------INMVGNMLFQLSDDTILKKQENGKEHYELMFIGYgANNVTLRGGTYLGDKDSHDYSKKDNPHTpgTHERGYGITVLGANNITIEGVKGTHFTGDGLIIGAH-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2B8JB68_BACME
+--------------EKWTIHNDGTYPIETTSGFNNALAWASAQGIHTFKVPAGIYLIK-----KGVDYDATARINMVSDMTFIADNKAIFQKETNGLTGYSVMYIGpQVKNAIIKGGVYKGEKDTHDYSI----SSTHEWGYGVLVEGGENIIVDDIEAYNFTGDGlligntirkgtyinssilesggldengnptnetgrirtvgrtqtnfddaiykelnsfyLWVPTgltknqydvyfydkdgkllerklnvnmwKGEVNIPkgadyfktvlyadstsgASVYryaiDNSKSVTVKNSKMHDNRRQGITVGGGYGVLLENNEIYNIRG--IAPQSGIDVEqGYGINGnvtirnnNVHDNVYGVILYDGIGATVEENQIKNHSYPGLVVQEEYKDALVQNNYfeNSGMSIK----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1M6AGX2_9FLAO
+-------------------------------------------------------------TTNQNFYPSREAINVPSDFTLRMTDNTNLRVQPNSRKNYVLLAVRDASNVRVEGGNLIGDRLEHD---DNSQPGPHAFGFVLMIHGGSNVDLVGVRTILGTGDGIDVNSIGFTFEAG--YIPSNNIRITNCIMDSNRRNNMSITDGFNIVVDGCQFLNAGIDMPGspgmaPGVAMDVEAFrgkddAGNFILYERAYDLTFRN-NFEKGSKfGSFVVAIGEDVTIENNTTEDGIAIGAGHGIKIIGNTLIAAADDNiGAGITTGHPNSTDTYDNV-IANNRIIGHNIGIAAYQRDMKIYGNVIE------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>GraSoiStandDraft_43_1057313.scaffolds.fasta_scaffold3393195_1
+-----------IDNAYWGIVTETNTEqigIANMENINRAIKTAHENGIYKIKLAKATYWFDA--TSDKTTPSIG----LLSNMQFNL-XXAXLRVMPNNLTHHYFIYIESAENVKIFNGTITGDRYEHGY--VPATYPTHEWCHGLRVGSNSSNYCKNIEIYDLVVQE--------FTGDGINVSWSKNVTIRNTEVSNARRNGITIgSNTDETYIYDNYIHDTHG--VSPACGIDLEKAAGDGPKNIVIRNNRIYDCINPETGaeQGQAMAISGGsyQVTVRDNDIRGVIGFAYAEKILIENNRI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A229GVH8_9GAMM
+---------------------------DDTAAIQKAIDAVAAKGGGIVEIPAGTYMINGAATsvLGPGDVPRTSGLQVKSNVIIRMADDTVMQVIPNGEKHYDIFNIYNAENVAIMGGTLRGDRHSH---LNDQG----EWGSGIKIASAKNVVIEKVIAREFWGDAVHISDSG-----SLPRTPSQNVTIYQLAADGNRRQGISITSADKVLIEDSAFKNTGGQgGTPPMAGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A098MBD8_9BACL
+---------HLIELSRWGIYNDGTHPVETTKGINNALTWAYQQGITATTLTPGTYLIDKASQINM----------VP-NMLFDLTMEVVLQKETNDKESYQIVSLDYGDnNVTLRGGTYIGDRLTHDYSKKDhvGSAGTHEFGYGIIARGVKNLVIDRVKTTHFTGDGIILAGHGTM----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2A2AT09_9BURK
+-----------------------------------------------VWIPAGTYMIDaTVNACGGWGQE-RCGLQMRSGVTVHMSQQAVLKAMPNGSRHYNIFHFNDVENAHVLGGQLQGERYAH---RIPTDGRLGEWGAGLVMRGARHAAIENVTAREFWGDGF--------------YVGGSSQNVKFCAVvaDKNRRQGMSITDVDTIVVQDSVFKNTHG--TPPQDGIDIEPWGqENEPIREHVKNVTIRRSQFINNagrGIGMVTTHPGqiENVVLEGNtFIDNSIGLGLgnrSWKTRITGNRIIN----SQY--LNIGLGPLAT--FITVTDNAVTG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_2407419
+-----------------------------------AAIQAAINSLPsaggTVTIPAGTYLIDTSKKIN-----------LKSNMLLKLDPNAILKAKSCSLIRHYLVYVNGKTNVEIAGGQLVGDRDGHNY----VGSSTHEWGHGIQILGSTKVTVRDLRVSKCTGDGVCIGG------------GASDVVIGNIIATNNRRQGLSITNCTNIKVYDSEFSYSKG--TSPECGIDIEpddGHSlstvliqncrmNNNGKYgmniwKRVSGVTITQCTLERN--GSLGLGTNGCSGIK--FTNNIVRYNSATGV-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1719318_174446
+---------YKLNLEDWDIPNNGHEPRKTTENLQKAIDWAHGNAYTKVLLPRGHFLLGIeaaakypwgwTNGKRKEDNFSMRGLSMHSNTEFILDSAATLEMVSNDKVMYCIICIEDVTDVIIRGGTLKGDRETHTYTP-HHNRTTHEWGHGILISDRvHRILVTNMEIKDVTGDGVYVKSEKK--------SIGSDIIIKNNDIHNARRQGVSIVGGLRVKIEDNEIHHIKG--TSPQFGVDIEG------PWTVTKDVIIHRNNFHDNRGGDVVNFDGKNVFITENKMIESDSYSYT----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>APHig6443718053_1056840.scaffolds.fasta_scaffold2008830_1
+-------IKYYTP-QQFGAVANDTG--DDTVAFNRALqAAASSSSTDTVFVPAGTYMIKADGG--------DGGVQVLSKTKLKMDPGAVLQVITNAERGYNCVRTNGVTDAEISGGTICGDRTTHTGT-------SGEWGHGIGIYDSTDVTISNVVVKNCWGDGVYI---GTAN-DNSTTAKSRQISLSGVTTDNNRRNGLSVVAADGVTVDGCLFVNTNG--TDPQAGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_7665223
+---------------------------DVTSQLQTVLTNIAKNGGGIVYLPKGNYMIKAtssdpswTNPQSLLTPAKLEGLQVGSNTTILLDKDASLSVIPNNFWNYLVLNIQGADNVNILGGTLNGDRLSHDMSNPNwtwnngkgfNSPYYGEWGNGLSIQSSNNTLVSGVKFKNFWGDGISLFPDKDQAEAGAL-SQAKNVHITGCTFDYNRRQGISVGHANNVEIDHSLFENT--DGTGPAAGIDLE---PGGGSTEQVTNVKIHDNVFLNNNNAGLTAYAAPKSKV--------------SDVHVYNNTFINNG-------------AWMPG---QITFNN-----------AEYIEIDHNKFDNDD--ASRFHSSWIVNTANDNIHDN-----YGRNSSirIAKEAHGEGKVTNNYVSSIMIENTGYDVANNHLPN-------------EISSTDLGTMGANWNYQNDVDYPGLATNEKVtfhdFNSRGKALNVTANPDNTVLNQSDPSNCQADISFDIDG----------------------------------------------------------------------------------
+>SRR5699024_10005537
+-------------------NAKGDGVTDDTNSINEAIDYAVENNINTVYFPSGIYMIkaDAEEIIPNGSK---GGIHLKSNITLKLDDNAILQAISNSAEGYNIIRAKESNNIKVIGGTIKGERSNHSGS-------EGEWGHGIHLKGCSNVYIQS-NIIDCWGDGIYVG--------GDVSTddskPTKNLIDENTVCDNNRRQGISIVSGKHIRLLNSDFINTNG-TL-PESGIDIE------PSHDRHIvrDVKVIDCNFNNNaGTGFLIDGKSG--SVEDIYVNGI----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5207342_2131982
+---------------------------DDTRAFQDAIDAAKGG---IVIVPAGDYLIDPLHS-----------VRVRSGTQLRMDRNARLRAIPNAAPRAYVLLLQGVEDITISGGQILGDRKEH----LGT---TGEWGHGIAIYGASNVKVRDVRISGCWGDGISIGS--TKAGKGGVMRPSTDIEIANVASLGNRRQGLSIGRSRRVYVHDCEFSDTGG--TPPSAGIDVE--PDAG---DIAQDVRIERCILRRNrGPGiqvwkRATSVAIRDCTIEDNRNAGVLAVG-AIDLAIERNRIRGNG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_3757948
+-------------------------------------IQAAINSLPstggTVFVPAGTYLVDAVRS-----------VKLRSQMHLKLDPGAKLVAKPTSSESYNVVFADVAHDVEISGGQIIGERHQHKGTV-------GEGGHCIRIRGCERVTVRDIRLSDGWGDGITV---GPRPNRRKRFTYSQDVAIANIICDGNRRNGLSIGNVIGIKVYDCEFNNTNG--TAPQCGIDV----EPSPDFDgsgHCDDVHIENCRMSGNGAygMNVWKNTSNlvitKNTIEGNKTCGLVTRG-MTSSSITGNTI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>R6FQI5_9CLOT
+---------YGVDIQKFNINNNGLNPIETSKGINDALNYAAKNKYDKITFPKGEYCI------SEENP-----ITMVSNLIVDLN-GATFKINDNGLQHYTVIDFSNCSNSQLINGIILGDRETHDYKTIE---GSHEWTCGIVFNNCDNCILDNVTISSFPG-------YGISSSLGENLS-DLIIGVTKENLSIGNINDKGkLNNKKGTIrtIDPLNISNVGGEfELGYNKGYMGYPYMQSKEYLSYFYDenmkfiSKVDNCKQYK------------KVLIPDNakYVHFVFKQDY-----------VPERGDTDFNGTTVFLTNYSSPNNITIKNCLIEKNKsLGMGIcGGYNWNIENNMFKenggGAPGYAIdledGWEYMDSFLFKNNKFigNNNDIVSCAGDN---IIFENNSFTSTVYMWG----RTTNYKFLNNSFSNIAMNINYEYSTDTECSGNTYnncriAITSK------NKDAEFNINNENIIDthvntmPENVSIIDskitADNIDNIRIYGN-FKDCH----ISKVTGSLVNFRGEKCKINNSN-----------------------------------------------------------------
+>SRR4249919_2030177
+-------------------------------------------------VPAGRYLIDAVKS-----------VKLPSNRKLKMHPDAILVAKANNAEGYNVLLVERVDNVQIVGGQIVGERDKH----IGT---TGEGGMGIRFRGATNSSVTDTIVSNFWGDGI-VAG----PYKGSKYIPSTDITLKNVTMSGNRRNGLSVGNVVRFLAEDCKVLDNGNDPDGtgpivggtsPFCGVDVE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1S1V829_9FIRM
+---------YYAD------AAFTKPATDATQAINSAVKHASQNGIQKVVIPSGNYLIKAEGvsaTGIEGDYAKTGGILLQSNMTLEMSSNAVLVTNTVNKPGYSLITVNNKSNVKIVGGKLVGDKDTH-------PANTHNACYGISiINGSKNIYVDGTEITKMEDDGIMITDYAIDQSGG---TRSSDIEIRNVKSHNNGRQGLTI--ATGSNIKILNSEFSNQTKHEPKSGIDIE-----IESYDHvgVKNVEISGNKFEGNAFSGVlfsnmfndrpnsmsenikingntingSRHgilAEGKSNGLDMSNNNITVNNYnvgqssvavgtlsaeSSGVVISGNNIISD-DSKAH--TSMGVYSTTPG--VSINGNNLVGQNVGMMLSGGGEQIVGNKIskvlatgihisgsnqnisENEISVSGAAHLssdsyhnviyaayAENLAIKNNNFHDMKSYGINlaegVRNT---EVSGNTMKNIgTEAFPNKnsflhiASENTGINVTGNTFDrGAYPTLYLGISYANSVKgANSFTnneiigFSSYGYGM--------------------------------------------------------------------------------------------------------------------------------------
+>A0A1M5UZK5_9CLOT
+---------YTIELDKFGIKNDATFAVETSKGINDALQYAKEKGYEKIVFPKGEYLISELNPV------------VIDLKNVVIDlNQATFQINTNGLEKYSIIQIvDGAENIRLTNGIIRGDKDTHDYKTIKT---PHEWGCGIVFKGGKDLEMDNITVTNVTGYGIYTESGTNSNRFDAVYT--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5687768_13918870
+--------------------------------------------------------------------------------------------------------------VSIRGGKIVGERGAHHGT-------TGEWGMGVRLAGCHDVRIQGVQITDCWGDGIYVGANGVGN-------ESRRIKITECILRNNRRQGLSITGCIGALIRDCEFTDTNG-TL-PASGIDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A250E5Q6_9FLAO
+---------------------------DDTEAIQNAINEASKKGGGVVYIPEGTYLIDAKQSLVIRS---NVTLQLAANAILEAKANTILEAKANTSERYDILYIKNVENVKVVGGTIKGDRNIH-------IGNRGEWGMGIGIYDGKNIVIENVSVRDCWGDGIYI---------GKNRNRSENIILEKVKSVNNRRQGVSITAAHKVTINHCVFSQTNG--IPPQAGVDIE-----PNAADTVSNVVIKNSIFDSNENSGILIYTGAERS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_21041421
+--------------------ADNTGSVSTQSAINAAIALQNARGGGVVYVPRGTYLIDT-------NYLTGGSVRVLSNVTLHLDPGAVLQAVPTSNGQGAIVWAYNAENIIIQGGYIRGERDGH----IGTDQP--DGNHGISIFSCDNVTVKNVRVSHCWGDGMYIRNDTGGNNTG--DTLSTQIRVLDSSFFNNRRTGLACVAVDGLTISKCYF--YGNTGANPYAGLNLEPNSDGWVR-----NCVVSDC--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1H9W652_BUTFI
+---------------------------------------ASNGGLNTIYLPAGVYNITDIGNYDH-------GIELKSNVNLIMDKNAVLKVSGMPYGDYEIFSMRYLSNVTIAGGQLVGERYSHSgyYG---------ESGHGIAMHGCSNITITNMCISANWGDGIYFGTQAVWLGSGQGYFGNTNVTISGCDIFDNRRNSISFTDADYITVDRCNLRDSHG--TAPQCCVYFEPNGDSSDK--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR2546423_4745973
+-----------INVRDWG--ALGDGISDDTPAFAAALATLADRG-GTLSVPDGDYRIDPLKS-----------VRLTDNVALNLSRDAILRAIPVTARNSAVVLVERARNVRIIGGTIIGERDGH----LGVGG---EGGMGIWVSASSNVRIERVTALDCWGDGFYIAgwsGRGSYDANSLHESHSDNVTVSRCIARNNRRQGLSVVGCIGGLIERCGFTDTNG--TAPQSGIDIEPQG----------NWTVSNVTV----RNCVTARNAGWGIL---VCGNDIYNASVSDILIEGNR-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6185503_5510564
+-----------------------------------------------VDVPAGRYRIDPVRSIHLADSiamEMASGAVLAA-LPVAQGNSAVIRL--DGIQGAS-----------IRGGMIIGERDGH----LGT---AGEWGMGIQIMGGSTISVEGVRIEGCWGDGIYVG--------GRSGVEATHITIRRCVVTNNRRQGMSMTGCRDSLVEGCTFASTHG--TAPQAGIDLEpnggfvvegvtirgctvegnhGYGivLSGGREQHVQTITLDDNRVADNG-----FHGIGVVS--------------SVDCSVRGNTVEHNG---RDGVQIAGSSRVRlTGNTIRDNSRRTAGVWDNVIV--QSLSTDNTVANN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1E7DPH2_9BACI
+-----------INITDYGANADDSK--DDTSSIQAAIDAAAGKN-GIVLIPAGTFLINT-------DPET-GSLNVKDNIEINMDEKTILKSIPNGLPIYRMLTIYNRENVKITGGTLIGDRYKHEGT-------EGEFGHGIYIGGnSSEITISNVRAQDFWGDGFFVEGNASQeTYP-------SSITIDNVESHNNRRQGISITAGKQIVVKNSIFSGTNG--TPPAAGIDLE--------RDPPYSLPLEEVELLNN-----------EVFNNEGY---GISFIYASNSSAQKNIVKNnkKGGIYIGGGVEQGIAKNNT-----VDDNFISENGLGIFVNfSTQNNISNNVIEKSKKDGIVliNHVGQN-RLVKNLVRDNQGNGLYIwgglHDQSGIVVQQNKiSKNSKAGIAVlNVLDATITD--NDLLDNAGAGLHREEAKESTIERN-------------------------------------------------------------------------------------------------------------------------------------------------
+>F3B2U2_9FIRM
+---------------------------DDTAAIQRAIDAVSAAGGGIVDIPAGNYMI---NTLHQTGHSYeRAGLVLKSNIIVRMANGAVLRAIPNGERSYQIFSITHVDNVHIMGGKLIGDRDTHIGNLGQT-------GYGVRITDATNVVIEDLYAGEFWGDGVFLG------------EDSRNITLYRVICDHNRRQGMSIVGGHNVKILESEFKRS--DGTPPKSGIDIEPEG------DHPIvsGVEIRNCLFEGSSTGFVVSNQySNSVAENIIFADNI----------VRGNKT---------AVNLVGIQSGEvTGNTIyhdqSITEN------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A177L0L1_9BACI
+--------------------------IDDTDRIQKTIDFVNKKGGGVVTFPKGIYLIDA---------EI--SLKLKDNITLKFEKGAILKALPNNAESYEIVKIHDVENVSLLGDiTIIGERKEH-------IGKTGEWGFGISIRGAENITIENPFIKDCWGDGIYIGATTKKKY-------SKRVTIINPLIENNRRQGISVISAVDLTIISPKLLNTNG--TSPQGGIDFEPNSEN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A150W909_9BACL
+--------------------ATGNGEVDDTIAIQNAIDFAYSNGNKTVFFSKGIYLVDSSTSL-----------VVKDGIVLKFENEAILKAIPNALERSEVIRIHDVKNVKILGyPEIIGERDEHLGS-------TGEWGFGVSIRGAENIYIENAKISNFWGDGIYIGSTAKKNY-------NINIEINNVELTNNRRQGISIISVENLLIKDATITNTNG--TSPQCGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1G2XYR5_9BACT
+--------------------------------------------------PSAVYNIDADGTGDQ-----SAGLKLPSDVNVAFEEGSKLKVIPNSSTVYSVITITGKNNISLSGACIEGDRNFHTGT-------TGEWGFGISISNSQNITIKDVNVYDCWGDGIYIC------------SVSDRVTVRDSIFNHNRRNGCSIISAKNVLFENCVFSNS--DGTSPYKGVDIEPNYEsdilqnivfnNCRSYNnlakgfspafdgaliNPVSITFSNCSSDGDGTGfgidAGPRNTLGTITFRDCTSTNAVENGFSciaanINTVIDGLYIVNPG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6478735_8854003
+-----------VDVREFG--AKGDGRADDTDAFEEAIEALPAGG--ILDVPDGDYMIDTLRSIRLRD---GIHLRLARNARLIAQPNAA----PRSY----VILLRNVRDIRITGGAIVGDRDRH----LGLDG---EWGHGIAIYSVRNLVISGIHISKCWGDGMSIG--GKSAQKGQPATPSMDIEIANVTSVGNRRQGLSIGRSRRVWVHDSEFSGTGG--TPPQAGIDVEpdkgdivqgvriercvirgNRGPGIQVWKDTHDVSISDCTIEDNRNAGILAVDATDVTIRDNRIRDNTQVGIalrkgTRQVSISGN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1C7EEP3_9BACL
+--------------------SYGNDKMDDTQFIQNAIDFQSSKGGGVVYFNKGEYLIDSTKSITLRD-----------NITLEFEQGAILKAIPNSAERYEIVKIHNVKNVNITGQvSIVGDRSEHTSSL-------GEWGVGISIRGAQDINIENVSISDSWGDGIYIGNTSKKNY-------SENIKINNSNFDNNRRQGITVVSVKKLEIINATITNTNG--ISPQSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1I2HG07_9BACL
+-----------------------------------ARINAAINSLPasggTVYIPEGTYMI---NTGNPYNPVTNATcISLKNNITIKMTENTVLKAITNAYNNYAIFLVRAVSNVTIEGGILQGERYTH------TGPTAGQVGVGVWLEGATNVTIRDVTCKEFWGDGIYTLYHSTLG-------NTKKVTVENVSFIDNRRQGISICANENFRVIGCSFEttqgtdPAAGIDIEPELGgtvrdVTITGNVFKGNKIGiqalGDASATITGNVFEGNTMwGIYLASSSRYYSVTGNIVYASGNYGIyvntSTDNVISGNVVYNNG--------SHGIYLLNNADRNVITDNKVYGNS------GEGI----NVYKSFDNII-----------------------------NDNNVTNNKGRG----IFIAVSTDNSING-NTSSSNALSGIYLWNSKYNLVDSNRCSKNGQ-HGIFVKGDAANDSLSNSI--------------SNNQCKENSQTTNQGYQNIFLSSGAQGANTINNVQGNMCRAGGlankpqYGILIDaNTSETLLKNNDTRGGGAK--------------------------------------
+>M2U1I2_9SPHN
+--------------------------------------------------------LDVVSPTNGRR-----GLVIPSGSHWVMHPEMRIRALPNASSHYEILNILDEEDIVIegNGARLIGER--------DTHRGAEgEWGFGLSVRGARNVLVENLIAEDCWGDGFYIGS-GRRKY-------SQDILFRNTKAIRARRNGLSLISVRGFLSEDHESAHTFGSA--PQWGVDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690349_1434838
+--------------DVTSMGALGNGVHDDTAAFQSA-IDALPADGGVIDVPPGTYMIDATHTsCPGRGTALQCGLILRSHVALSMDVGAVLRVIPNDQERYYAIYVRGLSDVEIVGGRLVGDRTTH----LGT---TGEHGYGIAIAGSSNVRVRWTEVSNFWGDGFIVSRTGGDTNP----TYSRYVTLDHVKSSNNRRQGLtVAGGVQYLLVQYSTFRDSNG--TAPEAGVDFE--------PDEPTVAPVSDIRLYDN---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_575702
+----------------------------------------------------GTYIING--ELEGHTYESVGGIILHDNIILQFAEGAILKVMPSESEFYSDITLKDCNNVSVLGATIYGDRSEH-------RGVTGEWGHGVKVIRGENINIKNVRVSDCWGD-------------GVYFRDTKNVTVEYVISDNNRRQGMSIVGGENIYVRSSVFKNTNG--TQPETGVDI----EPNHDYQVVKNISFNDCSFHDNVSKGLMLFTNGGT-----FEDIVVN-----NCSFSGN-----------GAESFRVSGRGNHCNIKITNSTLEHMALGTSA---------THVLNAS--------ADNVIITNNYID-----KIVLNNTSNSIISKN-----IIIENIVLVDSNtNIRIENNIFNDasdidrirlLYDEVYDDASKYIYITNN--TISGGKRGVF--VQSTEFLSLYSTINIKNNMFIGLTE----------------------------------------------------------------------------------------------------------
+>SRR3546814_95907
+-------------------------------------IYALPSTGGTVVVPDGTYMIDAVRK-----------VRLRSRMHLKLSSGAKLVAKTNSSPRYYVLDDGNASDLEISGGQIIGDRHRHTGT-------TGQWGQGIMIRGCRRVTIRDMRISDCWGDGMSISSI-RLNGRYDPWTPSNDVVIANVVSTGNRRMGLTLGGTRNIRVHGCEFSNTRG--IEPGCGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>R6GIV0_9FIRM
+-------------------------------------------------------------------------LTVHSGQRLLFD-AATFQLTANGYDFYAVLNIHNVNNVTVEGGlTIIGDRESHTAT-------TGESGHGIRIVNSHNVHVSDVDIRYTWGDGVCVGGNGTM------AEISQNVTLERIRTYKCSRNGLSIIEADGVVVRDCDFTYT--DRTAPQYGIDVE------PNLGTATNITIENVRMLNNGIGGFALYTT-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A088F0B6_9SPHI
+-----------------------------------------------------------------------GGVALSSNTIVYGNNAKITAFADYNQPAYNIFRIENIENVIVKDLELIGDRNSHTGTL-------GEWGYGIAVLGSRNILLNNVVSKNMWGDGVNIQMLN-ANQAGVTQdTHCSNVTLENCIFSNNRRQGLSIEDGSTIRVSGCTFDKSNGKA--PQCGIDIEPI-VAGRAFVD--GVTIEDCMFSDNeNSGILMESLNGPISnvtiqncffhHKKAKISNAVYIGINTSRNNLNTKIL--GNTFDKSLDrslyiTGGMYMAISGNYIakefivNSTDTNLPEFYTDNLV------IDNNTL--LSGLTLESGVRK-VTISNNKIESpirPNTSSIGIFNKSQRLIANNNefNNCETGIHSYNTTTTSAI-INENIFKNINIGVVAQLNS--KIISNQFINTGinktSGYG---------------------------------------------------------------------------------------------------------------------------------------
+>SRR5512133_1390
+-----------------------------------------------VSVPDGTYMINALTS-----------VLLKSNMTFSMSSGAVLKAITNSSSNYSILFANGVNHVNIIGGTIQGERTTHTGT-------GGEWGFGVRITGSQQIVVEKVLAKDCWGDGFYVSA-------------SASITLCNVTADHNRRQGLTITSVDGMVVRNSTFKNTQG-TL-PEDGIDIEpNAGET------VNNVLITGCTFTSNSGFGV------EIGVPISYTGQAWIKGVVVDgNTVTGSGVNTLSTSPRAGIEASDIPS--AGNK--ITNNYCANNGLGILLRngSNGMTISGNTVTQNTTDGIQVYSTDGNTITGNTATNNLGRGIYSTSNTNISISNNTVSG-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1X6W0S9_CHLAO
+---------YLIDVNEWGISNDGTNPLETTQGINNALQWAYQNGYSYVKLPEGVYTVSKGSASKDYSENACILLQNDTTLDLY---GCVIQKEANGWDYYAAISIVEKRNVTILGGKIVGDHLAHDYATL--ANSIHEGCIGIIVeRGSRNITLNGVEV---------------MNFPG------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1035438_889792
+-----------------------------------------------VMVPDGTYMVNAV-------AQNAAGIRLGSKMTMKLSSGAVLKAIPNASGNYAILAVSFASHVTIVGGTLLGERGSH----TGTDG---EWGMGLSINNSAHVVVQDVTAKECWGDGFYVT------------SLSSDVTLCGVVADHNRRQGLSVTSVEGLVVRNSTFKNSVG--TAPECGIDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>WorMetHERISLAND2_1045183.scaffolds.fasta_scaffold180453_1
+---------YYLDPVVAGITegvVSDTIALANTVAINTALETAKTEGNTTFVVPTMDAYFDTGGNGNSREEEVSGAIQIPDNMHFKMGAGTVLRRQPNDkhhssllsviykpptstNRGYGSL---LGENVEISGGTLIGDINDHTyyvgatitspattttasiriqreyvptvyeipvtisnvttnateiasyintnlndmeatvdgatvwitpnqglYVLMDDDNTdlsniemvytpdyTFEFGFGISLYGAHNTYIHDITIRNFHGDAIFIDKTGLRNIDATLpsnFRTCENVLIQRAYMQNNRRQAISVVDCNgyednvalptpggagsrvGVIIDNCDIVDTGRDIYHlPAYGIDLECYRQLGAEYARVENVIIKNSRFSGNRKGDLNLYNSQYVQVFNNEFTYKIGHVASNNVSIHDNTFTYDPIVYPENTDnSVAISlfsyiaqdgITELVYDFDIYSNTISGYTFGIIVSGDRFNVYSNNISN-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_498154
+-------------------------------------------DFGSIVFPSGTYMVDG---NDPAGPGGRQGVRVPSNRAISWLDGAEVRVIPNSNTGYNAFLVDQVENVLFLNPRIKGDRDEH-------TGVAGEFGMGIEIRSAENIVLRDPYIYNCWGDGIYI---GQVSEAA---GPCKDIYIERGKVDNNRRQGMSVISVDGLFVDNTQFTNTNG--TPPQAGVDFE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0Q9EPM5_9GAMM
+----------------------------------QAVIDALPADGGTVYVPAGNYIIDPTRNLRLR-----------SNMHLQLADGAKLLAKRNSADRAYVLMAYKVSDVEISGGQIVGDRDNH----LGT---TGEWGHGVMVRGSSRVTIRDIRISRCWGDGISVGGAIVTGLPTVI---SQSVVIANVASTGNRRQGLSIGRSSEIKVYDSEFSDNVG--IAPGCGIDVEpdandlgttttvhienclitGNQGNGiQVYKRVKGITIKRCTIEYNgGYGILTiAPVSGYIAlnrIAHNYLMGVMLRSATTSYQVSGN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2G6EWH0_9GAMM
+-----------IDVTDAGYDAKGDGTTNDTTAIQKAIDAVADAGGGVVWIPKGRYMIDTEARLKMR-----------SNVTVQMTDDTVLEAIPNGAGSYSIFRFYNVENAHLLGGTLVGDRDSH----LGT---SGEWGTGVNISSSSNIRVENIVTKDFWGDGFYIGENGSLD-------KSENIVLYNVVGDNNRRQGLTIVNGDNIKIIDSTFQNTHG--TAPAAGICIEPNDNN-----LVSNVEILNCKTINNDGDGIGLYE--RVNAINNEIEN---------VRVDGNEIIgNSGGIIVSG--SV-TDSTITNNFINTmeTDSSEPGIRL-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_10317103
+----------------------------------------------------------------------GASIRLHSNSQIVIAPGAMLRAIPNNLNNHALFYCYDAENVYVTGGTLLGDRDDH------TDAEDGvNAGMGWRISASSRVTVERQRILDFWGDGIYV-RNGTVETED-YDTLSTQVEIRQVECNNNRRTGIAAAGVEGLTVWKCWLRNTNGANpfAGANFEPNIDGYvrnvqvqnslaeGNAGAGFQtSGHDVTFDACTGRGNGtNGFRILNTTG----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>S3Y1Z0_9ACTN
+---------------------------DDTAAIQRAINQASDAGGGTVNIPGGTYMInpiavDSVHGLMMRN-----------NVTLKLADDAVLKALPTNTTHYSLISFVKVENANLVGGTLIGERYQH-------TGQGGEWGHGVNIQSSQKVTVQDVTSKDFWGDGFYIGQAWQV-------WDARSNQVALCNVTsvNNRRQGLSIVDGTNIRVLNSTFSRTNG--IAPQAGLDIE--PENGNLVEN---VEVRDSVFSENlGDGI------------------VLTWGEQNDASIKG---------------------------VRLESNQVLDNESGIMLhRAIGCQVINNTIRNAGN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_4714463
+-----------------------------------AIDYAVEKSIDLVWVPKGVYMIDAAGVNGEK------GLRLRSGITLKLHEEAVLKAMPNNVANYSILRVYDSANVKITGGSILGEKNEHTGT-------GGEWGMGIDIQSSNNIEISNVKVKECRGD--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1041385_954775
+----------------WG--ALGRSSPDQTKDDTQALQAALDSGARKVTIPNGHFMIDAARVQPGRTK---AGLNLPSNIELIMGTETFLHARNNSSISYNILVGWKVSNVIIRGGVLVGDN-------VTNSRRpdSNPSGFGLALFGAKNVWVYGLTSQEMFADGFFVCYD---DEPGS-HDECENVHLMDCRAYKNYRQGASVIGAKNSSIEGGQYRQTGGSP--PQDGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5581483_5383682
+--------------------AMGNGSMDDTKAIQAAIDALPESGGTII-VPNGTYMIDALK-----------GISLRSHDRLSLASGAALKAIGNSERRSWVVKVWNVNNVEIVGGGVIGERYSH------RGTSGGEWGYGINISSSDKVYVHDITIQDCWGDGLLIGALG--SGKGMV--EATNITLNRVKSKNNRRQGMSITPANRVYVVNSSFTGTHG--TAPESGIDIE---PRSQGWASQVRLENTDLS-NNNGNGlevhhNVDALTLYKVTAKNN---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1G7HPV6_9FLAO
+------------------------------------------------------------------------GLRIRSNSKLYFQKESLLKLKSSAKVLYAILNIAKVENVSIYSPTIEGDRYRR----VNPEDKKGEWGMGIWIQESKNISVFNAKVTHCWGDGIYIGG-------GRDIVPNDSIYIHRPIIDENRRNGISITSGKNIRIIEPVVSNSRGKS--PESGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1G2Y1Y7_9BACT
+-----------------------------------------------IRFPAGTYAIDGFDeTIDKdGNVTVYGGLKPASDTTLIFDIGAKLKAIPNDKIGYSILKIEGKNNVKIYGPTIEGERDSHTGT-------TGEYGMGIMLEGATNIVIKDANVYNCWGDGLLIGVHWT--------KPSDQIYVENSTFNNNRRLGCAVTNGTNILFKKCTFLNSNG--TAPQAGVDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1035438_766262
+----------------------------------QACINAVAGTGGTVVVPDGTYMI------NATHGSGVWGLMMGSNMTFAMTSGATLKAITNSSTDYGILCSNGASNFTITGGNIVGERSTHTGS-------GGEAGMGIYLNAS-NVTVSGVNVSECWGDGIYIC------------DASSNITITNCISNHNRRQGLSITAGNTFLISGCTFSNTTG--TDPQCGIDIEPNGSVPVTGVH-----ITNCQIFGNAGGGVQQGNVGNV---------------ASGTLLENCNIYSNGGG---GYNDGGIRFVETHDNI-IRNNNIHNNLNGgiMLDTNAGIGCPNttltgNTVANNSGWGIYANLCNGSAITGNTI--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_3394488
+----------------------------------------------IVDVPAGTYMIDAETSILMRD-----------NTHLRLATGATLKAIPTSSAVYNVILCELVDSVEISGGAILGERDAHTGT-------GGEQGHGIRSRGATNVYIHDIHISKCWGDGI-DAGPDKSDSHNYVYT--ENLTIDNVVCTQNRRNGLSIGNVNTARVTDSEFSYTNG--TSPQCGIDVEPDGDADGDGDCS-DIVIDNCRLNNNAVYGINLYQRARgVTISN--C--VIEYNSSCGIVSNG---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR4249919_325582
+-------------------------------------------------VPAGKYLINPVRVASGTS---FYGLLVGAGKRLEMDPNAVLVLKPNSAPRYCGVRI---DGGYMQGGQVLGDRLSHNYS----SGGTHEWGYGVQLRGTDSKAV-GVKVSQCTGDGF-----GMSGI---------RPVIENCISTQNRRQGVSLFGSDGLRISGCEFSNTGAlngqAGTNPRCGVDFE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1E8BK68_BACMY
+---------YFLELERWNVKNDGTDANNTSKGINNALLWASQQGFIEVVLPMGIYLID------ENTP-----IEPQSFMTLNLG-GATLKIRDNGLVKYAIVrYQRNQKFSRITNGRIEGDKDTHDYTTIP---HTHEWGYGIEVgnttpiEGSniSYISIDNMEILNCTGDGI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5512142_681238
+-----------------------------------------------VYVPRGTYLV-----LADGYRDGGrGGLAPRSRTRVVLAPDAVLQARPTGSSDYVVVRIERVSGVTVEGGTIRGERHEH------TGRGG-EWGFGIGIFGASDVVVQDVTIRDCWGDGLFIEE----AQPDFSVMP-RNISIRRVVSANNRRQGMSVPG--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>D7W8T5_9FLAO
+-------------------------------------------------------------------PLMTSGIFAQSNSQIYFQKNSSLILKPTADVRYQIISLHAVENVKIYNPTLIGDRDRHLGS-------KGEWGFGIDIRGSRNIEIYNANISDCWGDGI-VLVKTMRNMRSGVakenIFPTENINIIGGFINNVRRNGITIAGGKDIIIKNLLIANING--TNPMAGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_487370
+------------------------------------------------------------------------GIVLSSNTNIYFDVNSKLILKQSSKESYSMLKIYNVENVNLFNVHLVGDRYQHIGS-------EGEWGMGIRIQNAKNINIYNSTIRDMWGDGIYITSFG--------NTSNQNILIQSSWIDNTRRNGISIISGEDINIDYVKISNTNG--TAPASGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>H6LBC8_ACEWD
+-------------------NAKGDGKTDDTSAIQNAL-----NKSDSVYIPDGTYMIN-----------VDQSLKPNSNQTITMNANAVLKAISSSRGEQYVITIDGVTNVSIIGGKIVGERNEH--QGLDG-----EWGMGINvVNGSSNIVIKDTTISDCWGDGIYLGGSPAVN----------TITIDGVTSDNNRRQGLSITNAKNVLINNSVFKNTNG--TAPEAGIDIEPnvnqaaedikimntqcYGNNQSGIDilgnngGIQRVEITDCTIKDNvGLGILLFEASGitfaNTSVTNNKDDGV----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6185312_3767693
+------------------VGAVGDGTTDDTWAFQKAIDSVAAQGGGTVYVPAGTYLIDADVSINMKD-----SVTLD-----MVDTTRVLMAKPTATVRNYVIKLNNISNSKVIAGKIVGDRYQH----LGT---TGEWGMGMGINGSTNITVTGTNIIDCWGYGITISSYNCV---------LKNVI---CD--NNRRQGLTIGSSDSLIVDSCTCTHTNG--TAPQDGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0D5BSE2_ELIMR
+------------------------------------------------------------------------GLVLNNNQVLLFQEKSVLKLNPTTQKEYSVLGLSNVNNVKIFFANIEGDKYQHLTNV-------GEWGFGIGIFSSNNISIYSPYIKQTWGDGIYIGQ--------IKNIPSTNIQVYNAVIDDVRRNGMSITSAKNIDVVNAYISNTNG--TSPESGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_13262863
+------------------------------------------------------------------------GLKLRDNSKVLFQQNSVLILKPSSKSQYSIILMDGVSNVKVYFPKIKGDRVGHKGT-------KGQWGMGIWINNSQNILVHNPYITNCWGDGIYLG--NVNNRP-----PNKDIQIIDGMLDNNRRNGISIISGRNVEINGTFISNTNGHN--PQSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1035438_2623855
+------------------------------------------------------------------------GIRFGNNMTLRLDSGAILQALSTSSSSYRILLLSGVQNINIIGGTIIGNR--NNNTITDSV----EDGMGIQIANSQHVVIEGVTVQDCWCDGVYVS------------DGSGDVTLNGVVAKNNRRCGSAIVSVSGMVVRGC--------TFQGTTGMMENGLWANGTGVDVEPNLgeTVQNIQFLGN---TFTQNATGGLGIGPSNAN--MATTFVINCVIDGNTVSSNGDAVK---GTFGIVASSTGGH-QILNNTVtNNYGVGIYLYGdaSNILIQGNTVSGTS---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2A8TS41_9BACI
+-------------------------------------------------IPDGTYMI---------NADI--SLKPNSNQILSLSKKAKLKAKPNSDASYQIINIIEKENVIIEGGYIEGERDEH----VGVNG---EAGMGISiVRNSKNITIRNTHISKCWADGIYIGG----------YLPCYNINIYNVTCDNNRRQGMSVVNVDTLTVRDSFFTNTAG-TL-PEAGIDIE--PEN---YSTVKNVTIDNvvCTGNRSGLDVFgWAKTISNVQVLNSSMINNREYGlsiaFTTDILV-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5687768_6663082
+-----------------------------------------------VYVPAGTYLVDATRT-----------IRLRSRMHLKLDPGAKLLAKATSADRYYVVNAYKVHDVEISGGQIVGERDRHIGS-------SGQWGHCIGVRGCKRVTVRDIRLSKGWGDGISIGAAN-----GTTTVLSDDVAVANIVSTGNRRQGMTIGRCRNVKVYDSEFSYTSG--IKPGCGIDIE---------PDPFgtivcdTIRIQNCWIHHNaGNGVQVYKTVKNVTIK-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_2031064
+-----------------------------------------------------------------------------SNSYIKFHPDAVIKVNPNNYGDYDRKYgviiIYMKDNIVIKNPRIVGDKHEkpKNYKKIDSE----EWAAGIQIeRKSNNIKILNPHITAMWGDGISdSAGRKSMGEP-------DNILISNCFIYDNGRNGYSITASSNTKVFGGIISKT--DRTEPISGIDVE-----PAQYSRDVSgLNIKDVKF-TNGRGLILFKASQGAVIED----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5688500_1121635
+---------------------------------------------------------------------------------------------------------------IVGPGRITGARMVHRGS-------SGEWGMGISAWNSTNFRITGVEIADCWGDGIYVGSAGNGYCDGFLI---EGVKVRNC-----RRNGISVVAGRNGEIRNLDIAKI--DGIAPRGGIDLEPNSSNAPNRN----IRMSNGRIRDVAVGIYVTVANQRVSISgmDIEAENsgIIVSDNSVDVRIENNPNIKSlIGGKEGGAFRTVVTRPETIRGLLIRNNQLSGggaFVIDIFGQGyQGLVISGNRISatNAGTQGIA----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_32025263
+------------------------------------------------------------------------GLKVKSNSVLEFQENSLLKLKASDKHTYNILEIHSVQKVKILNVKIKGD--------LDTHiGKDGEHGMGISIRSSKDVEVVNAKIEDCWGDGIYIGRLNRYDRNGM-FEPSENIIIRDAYVNRNRRNAISITAGRNNLIDKLDANKTKG--TFPIIGIEIK----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5579883_944156
+-------------------------------------------------------------------------IQLRGRQEIIFEPGVVMLAKKGEFRGTGDSLLSIVgqSNLVLRGYGAILRMHKPDYQA--EPYKKGEWRMGIAIRGCKNVLIEGLRVESTGGDGFYVDGGADRGW-------SEDITIRNCTAYDNHRQGLSVISAMNLAVENCVFASTRG--TPPEAGIDLEPDTEENRLVN----CLIRNTVFQNNNGHQVLIHlkplsrKSMPVSIRFENC-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1T3DZL3_9FLAO
+---IKKDGSYYERQFEGGINPAWYGEL-TEKSINKALHIASVLN-------------KDVELMNDYKIDCSGidtGVKLLNNSVLRFSNNARLLAIPSSSGNYRMLSIDKVKNVKVYNPVIIGERSAH----LST---TGEWGYGINITNSQNVEIHNAVVKDTWGDGIYIGG-DYFDKTQTISTLTDNVLIYNPYIDNVRRNGISICSVGKVRVYNAVIKNVNG--ANPQSGIDIEPEGDTG----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5699024_10516162
+-SLLDRIVLYVDDF-----GAVGDGVSDDTDAIQQALNVAGELRTSVIFTKGKTYMTDG-----------SKGILPPSYSTLIMTGSKL-EVIPNALDRYICLYVLIAEHVTIIDPDLKGDRSNHittpSTNNNNVDGFTGEWGFGLRIARSKNVNVYNCKTSDFWGDGVLIGTDGIENTP-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262249_48802186
+---------------------------DDTSAIQAAIDAVAEKRGGTVLVPNGTYMVSAVR---------DNRLSLKSNVTLRLANDAALKAIPNDSDHYSVLRIANVSNVAVIGGTFEGDRNEH-------SEKTGDWGMGIWIgKGAEHVTISGVTATKMWGDGFYI---------------QDANDVRLCSVvaENNRRQGLSIIQVNGLEIKNSTFKNTHG--TRPSAGIDIEPDNDE----QHVANVRIHDSKFLDNaGAGIAVVAKKSLVS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>ERR1700750_2813068
+-----------------------------------------------VEVAAGEYLID-----------VTKSVKLRSGVALVLDPDATLRAIPTDAGNSAVIRIHDATGVRVEGGSIVGERDKH----LGTNG---EWGMGLGARGSHDVLIQDVLISGCWGDGVYVGS--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR2546423_7159601
+--------------------ALGNGVVDDTAGINAAIRSLAGTGGSVL-IPAGVYLVD---------PTV--SVQMASNVSLLLDDSAILQAVPVAAKSYAVIAASGVHNVKISGGKIIGERQTHLAA-------TGEWGMGVRVMGSSNVQIERVE---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5680860_103890
+-----------------------------------------------VLVPNGVYMVQAV----------GESLALGSKMTLRLADKATLKVIPNGETRYYTLRIHEASDVTVIGGTLLGDRRAH-------KGKKGEWGMGLHIVRSSRVTIAGVTSTRMWGDGFYVA---------------DGTDIAFCSVAaiNNRRQGLSIISANRLLVTDSVFRDTRG--TRPSAGIDME-PNKASQRIAH---VRIERSKFIGNaGDGIVIQGYKGRVSnveIRNNLFD------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1Z4RLG8_9CHRO
+------------------------------------------------------------------------------NQKILFQPGVVLEAQPGAFKGkYESMVSVMADNVTLSGYGAEFKMRKADYANPSLYEKS-EWRHNIHVRGARNFIIEGLTLKDSGGDGI-LVEHGPNEPNQLPVSKYSSGTIRGINASDNYRQGISVVSAKDLLIENSTFQNTSG--TEPASGVDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2B2C9D0_9BACI
+---------YILELDVWSvsntVSDFNDKTLSTanSNGINNALTWASQRGYSEFMFPKGTYLIDE-------------NIPIqPKNFMTLNLNGSTLRIRNNGLPKYS--VICYRQNQIfsrVTNGIIQGDRYDHDYSN-PGELPTHEGGMGILFPNTTDpskgegtntlfTTIDNIEFLDLTGDGV-----SLFSSQGLVYattTPTKSYAI-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A2C2T0P3_BACME
+---------------------------------------------------------------------------------------------------------------------------------VDNERYTHEWGQGIEIAGSNHVEIKNIEICDCTGDAV---STGWLKYrtNSTDYTQNEmghHIWIHDCDIHHCRRQGITLASANDVCVYNNKIHHIGkaddnvtsdfRNGIPPMFAIDIESmVGESNIPYKQPYynkdglelnfRLYIFNNHIHDNQRGHFVNADGNHVTVENN---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5215813_7905647
+-----------------------------------------------VFVPKGVYVVDAV--AKKRRLTLG------SDMTLKLDNDAVLKAMPTDSRKYSILTVSGVSNVTIVGGTLEGERAQH----MGNDG---EAGMGIRiVGGAEHVTVSGVTSRKMWGDGFYVEDANDTKFCG--------------ETSDGnRRQGLSIIEADGVLVTDSVFSNTHG--TRPSAGIDLE--------PDHPSQqivnIRIQNSKFLNNaGPGIEIAGKKGLVT-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6185312_5921845
+----------------------------------------------------------------------------------------------------------------------VGERQNHVYSGIGTG--TDEWCFGIQILGVTGMTIRGTQISQCTGDGIDLGNFGS--------SISSDIVICDVISTQNRRQALSITGGDGIFVYDSEFSYTNG--TAPLDGIDIEPGGAGAS------NITIENCLIRGNtGCGiQLNAHWGDIINVNVKNC-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690625_4101829
+------------------------------------------------------------------------GLEIHGNSTVFFDEGSVIKALPTSNGNYSILSIKGVDNVKIYNANIFGERNEH-------QGDTGEWGMGIRIEDADNVLVVNLKVSDCWGDGIYL----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1H6XJ90_9FLAO
+------------------------------------------------------------------------GLNLRSNSVLVFQENSYIWLKASSKPNYGVINIKDIKNVTLINPRIVGDRDSH-------LNKIGEWGMGINILNSDYINIFNAIISKCWGDGIYIG--------NKINGFSSNININGGLIDNNRRNGISIVSGEVVVIKDITVSNTNG-TL-PMSGIDLEPNTNEDTLKDIKL-VNVNSFNNRENGyliyLGGLLGENKREVDISiescfDQYSNTVVSIpGLRNDYEKKVKKI------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5512133_257377
+-----------------------------------------------VTVPDGTYLVNALTS-----------IQLRSSMTLSLSGGAILKAIPNSSSSYTILRISGVSNVNVVGGTLLGDRSAHAGT-------SGEQGVGLRITGnAQHIAVVGVTSKECWGD-------------GFMVADASDVTLCNITADHNRRQGLSITGGNGIVVKNSSFINSQG-TI-PEDGLDIE--PNSGQIVSN---VLITACVFANNAGDGI---ENGVPVL-------FTGLAFIYNVVIDGNTMTGNGVGTLHAGPRSGIEVSNTSGHV-IKNNTIQstaGYGIYLRDGVAGTTVTHNTVtKNALN--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A110B3A3_9SPHI
+------------------------------------------------------------------------GLSLISNSTVIFRKYSKLVLQANGLPAYQILRIYNATNVNLYFPVVQGDR--------DLHSGNGQWGMGISISGSTKILVVNPKVSKCWGDGIYL---GRQN-----NAVDRNITIFYAELDNNRRNGLSITCADGVHLIRPIISNTAGQM--PMSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A229UP75_9BACL
+---IGSPVSYAIELDRWGIQNNGTDAETTTRGINDALVWAKSAGYNHVVLRGGTYLI-------QVDPN-GTAIYMPSGMHFEMHHDCILQLAGNSFPNYRMIEMKGIRYAKVSGGKMIGDKAFHQYEM-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262245_13989197
+-----------------------------------------------VVVPNGIYLIDAAGE---------NRIKLKSDMVLKLSDGATLKAIPTDAENYALLTIADASNVWVIGGTLEGERDRH-------KGKSGEWGMGIRIgEGAKYITIMGLTSRKMWGDGFYVRG---------------AEDVRLCGVtaDANRRQGLSIIEADGLLVQKSVFKNTRG--TRPSAGIDF----EPNRDSQEISNVRIENSKFLDNaGAGILVAGKKARIT-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5215831_1849565
+-----------------------------------------------VLIPAGTYMVNAVDS---------NRLSLKSNVTLKVANTAVVKAISNDSEHYSVLRIANVSNVAVIGGTLEGDRNQH-------LGKDGEWGMGIWIgEGAEHVTISGVTALKMWGDGFYI---------------QDANDVRLCSVvaENNRRQGLSIIQVDGLEIRNSTFKNTHG--TRPSAGIDIEPDNDE----QHVANVRIHDSQFIDNaGAGIAVVAKKSLVS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>OrbTnscriptome_3_FD_contig_123_161973_length_414_multi_3_in_0_out_1_1
+-------------------------------------------------------------------------VKLRSNINIVFEKGVVVladEASQKGNAKYPMFEVKNVSNVAFIGrGDKPGDVYIGKYRDNEERRRmCHDYgGSGFAIEGAQNVVIRNVKVAECSVDGISLSSLGRLN---------SNIYVQDVILDGNYRQACSICNADGLYFKNvAFLNTSGGD---PMCGIDLEPTYE----LEPNSNIYLFDCRFEGNVGGGLnfTSSSYYPVTLHAKRCD------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262245_2037218
+-------------------------------------------------VPNGVYMVSAVE----------NNLKLKSDMTLKLAGGAVLKAIPNDATHYAILTISGVSNVWVSGGTLEGERSEH-------RGKLGEWGMGIRIDDrAKNITIAGLSSKKMWGDGFYV---------------QEAEDVRFCGVtaDANRRQGLSIIDANGLLVLNSTFKNTRG--TRPGAGIDLE-PDKDAQQITH---VCIENSKFFDNAGGGIMVAGNKKARV------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A0D4DCI2_9CAUD
+--------------------------------FMVGYIYATSKNRPfVVDIP---IYVQSTRKQSGFYNQVHYAVVAQSNSILWFMPEGeLIQIGVD-EAAYSILSLYGADNFLIKNPKLRGDKY-------TKTGNTGESGFGLTVTGCSNGIIEYPNISECRGDGIYLGQEYFNNNASSLI--PKNIKIIKPTILDSYRNGLALSAGEDIYFDAPFIDIAKG--TAPEACIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5688572_15557399
+-----------------------------------AAIQAAINSLPstggVVSIPAGTYLVDTTKRINLR-----------SLMLLSLASGAVLKAKTSSVRRAYILNVNNVRDVEIAGGQLVGERDTHKYVSGTTD----EWNHGIAINGSARVTVRDIRISKC-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6266566_4873650
+-----------------------------------------------IHVPPGTYSVDAV----------SGSINLKSGITLDL-TQATLVANPNNQIFSIIMRVSDCENVTILGGTIRGERTTH---LGSTAAFMGGGGGGVAIWRSKNIKIQGMKISDCFCDGLLVWHSGQVEIanviadhnrrQGMSLVDSHDVHIHNSQFTHcggtppgdgiDIENDLETETCANILVEHC-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>G2KPW0_MICAA
+---------------------------------------------------------------------------------------------------------------------------------------------GIEVQGGKTVTVSGNNMDDVRGNGIQIsSSQGAVNlldnvvsdirlHGIVVNTAPGAVVVDGNRVTDAGEFGIYTNGSKNVVVSDNRVS-------GGKNGIVVQNAAAS-AKIENNVVSGASDAGRVASGYqtaiGILVKDSAGAVSVTDNRSNANTGDGiriLNTDGAVVSGNITNDNGDK-------GIIINRSDNAV-VDDNRSNGNATGIWVElSNGVDLTNNVIRHSKVDGIHLRDSDNTLVQGNQIlsNDRNGIFVERSDSADIFRNTITGSGGYTGVKVEGSSNTDIGATDQT-SWVQTGFWPWQGHFVtTVRGNTITNFDNGVTVAGGNDNDV--VRNTISgVDYGVRLSGAT---NSDVLGNDLTG-NSIVGIEVVAGSHNAVIDNNTLDHFDT----GIVVNGSNNVDVTDNDLTDVGSGIVA-----------------------------------
+>SRR6266511_2426516
+-----------------------------------------------------------------------GGLVPRSNTHLHLAPDAVLKAKTTSASDYNVVRIERVSNVVVEGGTIAGERHRHAGS-------GGEWGYGIGIFGATNVTIRNV----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1Q6A375_9SPHI
+------------------------------------------------------------------------GLTLHTGQKVYFKKGSVLNLVPTAQPNYEMLRIHDVTNVSVYNVVIKGDKYSH---LV----KTGEWGMGISIRGASNINIYSAKIEQCWGDGMYIGTTPKQAF-------CENINLRYVNCNDNRRNGISVISARNVTILGPVLTNTSG--TQPMCGLDLE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690554_4058803
+------------------------------------------------------------------------GLNIISNQILNFSQNSKLIMKTNAEERYGILNIKYVKNVIVNNPNLIGDKEKH-------LGNRGEWGMGINIWASKDVTINNPRISETWGDGIYIGEPPVQE-------------KQKKKLKSYANHNIAIN---GGVIDDC-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR6516164_3930632
+-----------------------------------------------VLVPNGTYMVNAVGDAR---------LFIESNVILKLANDAVLKAIPNDSKKYSVLRISNASNVAVIGGTIEGERYGHSGNV-------GEWGMGIWIgEGAEHVTISGVTAAKMWGDGFYI----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5262245_45879959
+-------------------------------------------------VPNGVYMVSAVE----------NNLKLKCDMTLKLAGGAVLKAIPNDATHYAILTISGVSNVWVTGGTLEGERSEH-------RGKLGEWGMGIRIDDrAKNITIAGLSSKKMWGDGFYV---------------QEAEDVRFCGVtaDANRRQGLSIIDANGLLVLNSTFKNTRG--TRPGAGIDLE-PDKDAQQITH---VRIENSKFFDNaGGGIMVAGKKARVS-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>SRR5690606_56255
+----------------------------------------NENN--VVIIPKGTYRVT--------------GLKLKSNFSLLFEEGAELELIANNKERYEILSLAGIKNVKIYNPVLIGD-------IRKRNSLKGEWGFGIDIRGSREIDIYSPFIKDCLGDGIIIS---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+>A0A1I0S8N9_9BACT
+------------------------------------------------------------------------------------------------------------------------------FATIEGDRSTHkgaagQWGMGIAIRAAKNVNIYAPRISKCWGDGIYVG--------GLKGVTSSNINIYNAMLDYNRRNGMSITSVSGLKLVAPVISNTYGQT--PMSGIDIE----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/test/unit/data/uniprot.mode2.txt b/test/unit/data/uniprot.mode2.txt
new file mode 100644
index 00000000..17b94b62
--- /dev/null
+++ b/test/unit/data/uniprot.mode2.txt
@@ -0,0 +1,120 @@
+>O31912
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A6H0H3G5|A0A6H0H3G5_BACIU Right-handed parallel beta-helix repeat-containing protein OS=Bacillus subtilis subsp. subtilis str. SMY OX=535024 GN=HCN55_11075 PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A162RH73|A0A162RH73_BACIU Uncharacterized protein OS=Bacillus subtilis OX=1423 GN=B4417_1688 PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A6M4JNF4|A0A6M4JNF4_BACSU Right-handed parallel beta-helix repeat-containing protein OS=Bacillus subtilis (strain 168) OX=224308 GN=HIR78_12405 PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|O64135|O64135_BPSPB YorA protein OS=Bacillus phage SPbeta OX=66797 GN=yorA PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>sp|O31912|YORA_BACSU SPbeta prophage-derived uncharacterized protein YorA OS=Bacillus subtilis (strain 168) OX=224308 GN=yorA PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A857HHC0|A0A857HHC0_BACIU Prophage-derived uncharacterized protein OS=Bacillus subtilis OX=1423 GN=Bateq7PJ16_2250 PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVKGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A410R1H8|A0A410R1H8_9BACI Right-handed parallel beta-helix repeat-containing protein OS=Bacillus sp. WR11 OX=2448811 GN=D9C22_10995 PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFSIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNTELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGVSSTETSNRIQITDNNIQGFKIGMMIRGKGVSVDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSTYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGTRVLSHPYATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A7G5CIE1|A0A7G5CIE1_9CAUD NosD domain-containing protein OS=Bacillus phage vB_BsuS-Goe12 OX=2586960 GN=hypothetical PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNLNPIETTKGFNEALIYASENNFPIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGFSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVCNNKGKGTTSTYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYFNGTKKVRLIRNDVQGIGTRVLSHPYATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A7G5CIX1|A0A7G5CIX1_9CAUD NosD domain-containing protein OS=Bacillus phage vB_BsuS-Goe13 OX=2586961 GN=hypothetical PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNLNPIETTKGFNEALIYASENNFPIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGFSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVCNNKGKGTTSTYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYFNGTKKVRLIRNDVQGIGTRVLSHPYATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|G4EVD8|G4EVD8_BACIU Beta_helix domain-containing protein OS=Bacillus subtilis subsp. subtilis str. SC-8 OX=1089443 GN=BSSC8_22190 PE=4 SV=1
+MTLLNKSIRYYVDFDQWGINAFNLNPIETTKGFNEALIYASENNFPIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGFSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVCNNKGKGTTSTYAIKVMDSNDVTFINNKFSNLYGGLYCERSQSIRIKQNDFLLSGKGYGIYWDKDSKVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGSRILSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>tr|A0A7G5CHW7|A0A7G5CHW7_9CAUD Beta_helix domain-containing protein OS=Bacillus phage vB_BsuS-Goe11 OX=2586959 GN=hypothetical PE=4 SV=1
+MILLNKSMRYYVDFDQWGINAFNSNPNETTKGFNEALIYASKNNFPIVEIPKGNFIIDSVNTLNQRNPEVGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGHIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVKISDCIGDNIWIAAHGMMNYPGMAYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGVSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSTYAIKVMDSNDVTFINNKFSNLYGGLYCERSQSIRIKKNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIVFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGSRILSHPFATFNASSTTLIHNTYDSGTPRLALDDTLIDYK
+>tr|A0A837Y204|A0A837Y204_BACAT Uncharacterized protein OS=Bacillus atrophaeus OX=1452 GN=B4144_1968 PE=4 SV=1
+MNMIDKSLRVHVDFEQWGINPEGLNPIETTKGFNDALQSAASNFYSVVEVPKGNYLIDAVNT-SKRLPEFGGGIKIPSNIELILHPEAVFRVNPNGYQGYSCFYIGQAENVTIRGGRIIGDRYEHDYSKINTIQKTHEWGYGIHVHGSRNVLIENVSVSDCIGDNIWIAADGMMN-TDVTYTPSRSVTVRKCRLKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGFAEKGIKYDHPYELTIADCRFKKNGRGSITAHTSGKVIIKDNYCDNVISYGFSTDVSIKGNKIINEGEPKEYGIDSIGVSSTETGNRAKITGNTVRGFKIGIMVRGRGVTAKNNTIGNSSNCAIATHTAEEVFIAKNKIENSNCIQIQVRNSSDVKVNGNTGKGTTSSYALKVIDSKDVTLTGNEFSNIYGGLYCERSQAVRVKSNDFLMRGTGYGIYWDKSSEVFLTRNEIYEPRNIAITGTADIYNIRISENQIYNCKALVAIHLLGGSDHMLRGNEIMFNREADQGYGIYLESTKKVRLIRNDVQGIGDRVLSHPYATFKSSNTTLIHNTYNSGTLRLAVDDIVI---
+>tr|A0A150FBD2|A0A150FBD2_9BACI Beta_helix domain-containing protein OS=Bacillus nakamurai OX=1793963 GN=AXI58_10415 PE=4 SV=1
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGFNRALEYASSNSFFRVYVPKGKYLIDAVNT-TKRLPEFGGGIYVPSNIELILHPEAVFHVLPNDYQGYSCFYVGQASNVTIRGGQIIGDRYEHDYSKINSTQETHEWGYGIHIHGSKNVLIENVSISDCIGDNIWIAAYGMMNTSG-TYTPSRNVTVRKCTLKRGRRNNLATNGCEGFLVDDCDIEEAGGDTIGPQLGIDLEGFGEKGIKYDHPYKLTVRNCRFKNNGRGSITAHTSGKVIIDGNYCDNVISYGYSTDVSIKNNKIINEGSVKTYGIDSVGVSTTESGNRVQIDGNTVSGFEVGICARGKGVTISNNTLERIKACPISTHQAEDVLITDNRMENSDCIQVQVRNSNDVRVVNNKGKGTTTAYASKIMDSTRVSLINNEFVNVYGGVYCERSQSVRLKGNDLILSGSGHGIFWDKDSSVSLHRNEIHEPKNVAIKGTPEKYSCQISENQIYFCKSLIAIHLVGGSEHILKDNEIMFNRSSDQGYGVYLENTNKARLVRNDVHGIGGKLLSHPYCTEKAKNTTLIHNTYNSGTLKTAEGDTIV---
+>tr|A0A109WGG2|A0A109WGG2_9BACI Uncharacterized protein OS=Bacillus sp. SDLI1 OX=1774743 GN=AUL54_20265 PE=4 SV=1
+---MRQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKISAIQKTHEWGYGIHVHGSSNVLIENVQVSDCIGDNIWIAAEGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGEVNLEGNYSDNVISYGYSTDVSVKDNKIINKGKSKKYGIDSVGVSSTESGNRVQIIGNTVRGFEIGICVRGKGVHVADNILENITACPIATHEAEDVFISNNHIENSDCIQVQVRNSKDVRVTNNKGGNTTSAYAIKIMDSNRVSFAINEFANVHGGVYCERSQSVRLKLNDLFLSGSGYGIFWDKDSEVYFNGNEIHNPRNVAIKGTSEKYSCQISENQIYFCKSLIAIHLAGGSEHMLNNNEIMFNRSTDQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>tr|A0A8A5UUR4|A0A8A5UUR4_BACAM Right-handed parallel beta-helix repeat-containing protein OS=Bacillus amyloliquefaciens OX=1390 GN=J4048_10725 PE=4 SV=1
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNITVRKCALLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGEVNLEGNYSDNVISYGYSTDVSVKDNKIINKGNSKKYGIDSVGVSSTESGNRVQISGNTVRGFEIGICVRGKGIDVTDNILENISACPIATHEAEDVFISNNHIENSDCIQVQVRNSKDVRVTNNKGGNTTSAYAIKIMDSNRVSFAINEFANVHGGVYCERSQLVRLKLNDLFLGGSGYGIFWDKDSEVYFNGNEIHNPRNVAIKGTSEKYSCQISKNQIYFCKSLIAIHLTGGSEHMLNNNEIMFNRSTDQGYGVYLENTNKVRLVRNDTRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>tr|A0A4R2A540|A0A4R2A540_9BACI Parallel beta helix pectate lyase-like protein OS=Bacillus sp. BK100 OX=2512181 GN=EV570_101171 PE=4 SV=1
+---MQQPLYYSVDALDWGIDDKGSNAIETTEGINRALKYASSKSFYKVHIPKGTYLIDAVNT-SRRLPEFGGGINIPSNIELILHPEAVFKVLPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKVTSIKRTHEWGYGIHIHGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGQVIIEGNYSDNVISYGFSTDVSIKNNKIINDAETKKYGIDSVGVSSTESGNRVQIEGNTVRGFEIGICARGKGVLISNNTLEGIKTCPIATHQAEDVLITDNRIENSDCIQVQVRNSNDVRVVNNKGKGTISAYAVKIMDSTRISLINNEFVNVYGGIYCERSQSVRLKGNDLLLNGSGYGIFWDKDSSVSLQRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKALIAIQLTGGSEHMLKDNEIMFNRSTDQGYGVYLENTDKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>tr|A0A853LAC0|A0A853LAC0_9BACI SPBc2 prophage-derived uncharacterized protein YorA OS=Bacillus siamensis OX=659243 GN=SRCM100169_02074 PE=4 SV=1
+---MQQPLFYFVDAQDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGTYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIKEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIDGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGIDSVGVSSTESGNRVQIDGNTISGFEVGICVRGQGGTVSNNTLEKIKACPIATHQAEDVLITDNRIENSDCIQVQVRNSNDIRVVNNKGKGTTSAYAAKIMDSTRISLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPDKYSCQISENQIYLCKSLIAVQLTGGSEHILKDNEIMFNRSADQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIYNTYDSGTLKTAEGDIVV---
+>tr|S6FH05|S6FH05_9BACI Putative capsid component phage SPbeta OS=Bacillus velezensis UCMB5033 OX=1338518 GN=yorA PE=4 SV=1
+---MQQPLYYSVDALDWGIDDKGSNAIETTEGINRALKYASSKSFYKVHIPKGTYLIDAVNT-SRRLPEFGGGINVPSNIELVLHPEAIFKVLPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKVTSIKRTHEWGYGIHIHGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGQVIIEGNYSDNVISYGFSTDVSIKNNKIINDAEVKKYGIDSVGVSSTESGNRVQIEGNTVRGFEVGICARGKGVSISNNTLEGIKACPIATHQAEDVLITDNRIENSDCIQVQVRNSNDVRVVNNKGKGTISAYAVKIMDSTRISLINNEFVNVYGGIYCERSQSVRLKGNDLLLNGSGYGIFWDKDSSVSLQRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKALIAIQLTGGSEHILKDNEIMFNRSTDQGYGVYLENTDKVRLVRNDARGIGGKLLSHPYCTDKAKNTTLIHNTFDSGTLKTAEGDIVV---
+>tr|A0A6H3B795|A0A6H3B795_9BACI Uncharacterized protein OS=Bacillus velezensis OX=492670 GN=CHR37_05085 PE=4 SV=1
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGVDSVGVSSTESGNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLITDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSTRISLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKSLIAIQLTGGSEHILKDNEIMFNRSVDQGYGVYLENTDKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>tr|A0A7U4HXJ2|A0A7U4HXJ2_BACIU Uncharacterized protein OS=Bacillus subtilis OX=1423 GN=KS08_10530 PE=4 SV=1
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYACSKSFYKVYVPKGIYLIDAVNT-SKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINEKEIKTYGIDSVGVSSTESGNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLFTDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSSRVSLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPDKYSCQISENQIYFCKSLIAIQLTGGSEHILKDNEIMFNRSADQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIYNTYDSGTLKTAEGDIVV---
+>tr|I2C5Q7|I2C5Q7_BACAM Uncharacterized protein OS=Bacillus amyloliquefaciens Y2 OX=1126211 GN=MUS_2014 PE=4 SV=1
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGGTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGVDSVGVSSTESGNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLITDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSTRISLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKSLIAIQLTGGSEHILKDNEIMFNRSVDQGYGVYLENTDKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>tr|A0A4V7TQN6|A0A4V7TQN6_BACAM Uncharacterized protein OS=Bacillus amyloliquefaciens OX=1390 GN=D2M30_2250 PE=4 SV=1
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGVYLIDAVNTA-KRLPEFGGGINVPSNIELILHPEAIFKVQPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKINAIQKTHEWGYGIHIHGSNNILIDGVHVSDCIGDNIWIAADGMMNTSG-VYTPSSSATVQKCTLLRGRRNNMATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGIDSVGVSSTESSNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLISDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSSRVSLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKSLIAIQLTGGSEHMLKDNEIMFNRSADQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIYNTYDSGTLKTAEGDIVV---
+>tr|A0A8B2V7S0|A0A8B2V7S0_BACAM Uncharacterized protein OS=Bacillus amyloliquefaciens OX=1390 GN=C3733_08035 PE=4 SV=1
+---------YFVDALNWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDSVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVLPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKINAIQKTHEWGYGIHVHGSSNVLIDGVHVSDCIGDNIWIAADGMMNTSGK-YTPSRSVTVQKCTLKRGRRNNLATSGCNGLLVDDCDIEEAGGDTIGPQLGIDLEGYGEDGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSDKVIIEGNYSDHVISYGYSTDVSIKNNKIINENQVKTYGIDSVGVSSTESGNRVQINGNTIRGFAIGVCVRGKGIDVTDNIFENITACPITTHEAEDVYISDNHIENSDCIQVQVRNSKDVRVTNNKGGNTTSSYAIKVMDSNRVSCAINEFANVNGGVYCERSQSVRLKGNDFFLNGSGYGIFWDKDSEMYMNRNEIHNPRNFAIKGTSEKYSCQISENQIYFCKSLIAIHLTGGSEHMLNNNEIMFNRSTDQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDVVV---
+>tr|A0A7T7ZAL2|A0A7T7ZAL2_9CAUD Tail spike OS=Bacillus phage 268TH004 OX=2801523 GN=13 PE=4 SV=1
+---------YELEIDRWGISSGGSNPIETTQGFNDAIQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIYIKNVFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLIRGRRNCLATNGCEGLLVDDCAIEDAGGEGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVESNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGIYWGVNSEVEAKGNTIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGVKLKNNSVEVTNDRGLTSSFYTEKSTDSLVVMNDYNKGVIKSHETDTV----
+>tr|A0A5J6T752|A0A5J6T752_9CAUD Tail spike OS=Bacillus phage 019DV004 OX=2601654 GN=11 PE=4 SV=1
+---------YELEIDRWGISSGGSNPIETTQGFNDAVQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTKTHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLVRGRRNCLATNGCEGLLVDDCAIEDAGGEGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVGNNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGTGMGIYWGINSEVEAKGNIIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKTHETDTV----
+>tr|A0A5J6T3Z8|A0A5J6T3Z8_9CAUD Tail spike OS=Bacillus phage 019DV002 OX=2601653 GN=11 PE=4 SV=1
+---------YELEIDRWGISSGGSNPIETTQGFNDAVQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTKTHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLVRGRRNCLATNGCEGLLVDDCAIEDAGGEGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVGNNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGTGMGIYWGINSEVEAKGNIIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKTHETDTV----
+>tr|A0A5J6T9J0|A0A5J6T9J0_9CAUD Tail spike OS=Bacillus phage 276BB001 OX=2601664 GN=12 PE=4 SV=1
+---------YELEIDRWGISSGGSNPIETTQGFNDAIQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TLYTPARDVTVSKCTLIRGRRNCLATNGCEGLLVDDCAIEDAGGEGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGALVESNTLENISAVAVQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGIYWGVNSEVEAKGNTIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKSHETDTV----
+>tr|A0A5J6T6D8|A0A5J6T6D8_9CAUD Tail spike OS=Bacillus phage 280BB001 OX=2601665 GN=12 PE=4 SV=1
+---------YELEIDRWGISSGGSNPIETTQGFNDAIQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TLYTPARDVTVSKCTLIRGRRNCLATNGCEGLLVDDCAIEDAGGEGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGALVESNTLENISAVAVQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGIYWGVNSEVEAKGNTIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKSHETDTV----
+>tr|A0A5P8PIC1|A0A5P8PIC1_9CAUD Tail spike OS=Bacillus phage 056SW001B OX=2601663 GN=11 PE=4 SV=1
+---------YELEIDRWGISSGGSNPIETTQGFNDAVQYAKSEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIHIKNAFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLVRGRRNCLATNGCEGLLVDDCAIEDAGGEGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKIIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVESNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGVYWGVNSEVEAKGNTIEVGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKSHETDTV----
+>tr|A0A5J6T5S7|A0A5J6T5S7_9CAUD Tail spike OS=Bacillus phage 031MP003 OX=2601657 GN=8 PE=4 SV=1
+---------YELECDRWGIFPDGTNPVETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYTGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNTYN----------------
+>tr|A0A5J6T527|A0A5J6T527_9CAUD Tail spike OS=Bacillus phage 031MP004 OX=2601658 GN=8 PE=4 SV=1
+---------YELECDRWGIFPDGTNPVETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYTGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNTYN----------------
+>tr|A0A5J6T6E0|A0A5J6T6E0_9CAUD Tail spike OS=Bacillus phage 022DV001 OX=2601655 GN=8 PE=4 SV=1
+---------YELECDRWGIFPDGTNPVETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYAGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTIVDGNKYN----------------
+>tr|A0A5J6T8J3|A0A5J6T8J3_9CAUD Tail spike OS=Bacillus phage 055SW001 OX=2601662 GN=8 PE=4 SV=1
+---------YELECDRWGISPDGTNPTETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYAGSTYITARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNKYN----------------
+>tr|A0A7U3TW25|A0A7U3TW25_9CAUD Minor tail protein OS=Bacillus phage 000TH009 OX=2801831 GN=222 PE=4 SV=1
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSTNVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>tr|A0A5J6T602|A0A5J6T602_9CAUD Tail spike OS=Bacillus phage 031MP002 OX=2601656 GN=7 PE=4 SV=1
+---------YELECDRWGISPDGTNPPETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYHEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYAGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTVEEAGG--VGPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGVVKPYGIDSLGVSSTETGNRASIKGNTIRGFNIGINAKGKGILVSKNTIEDVESVGIQVYQATSALVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLHTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNKYN----------------
+>tr|A0A7T8C426|A0A7T8C426_9CAUD Minor tail protein OS=Bacillus phage 000TH008 OX=2801830 GN=222 PE=4 SV=1
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSINVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>tr|A0A076G7N8|A0A076G7N8_9CAUD Tailspike protein OS=Bacillus phage Bobb OX=1527469 PE=4 SV=1
+---------YFIDFEKHGIRSNGTAARETTDGFISALNDAVASGYKTVYVPKGNYLIDGVG--EDKMPEYGGGIQFPSNIEVIFHKEAVFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMVSPFRRTHEWGYGVHIRGCRNILIEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTEKGRRNNIATDGCLGLLIDDCDIIKAGGDTIGPQLGIDLEGYAEDGIKYGHPYEINITNCRFRKNGRGALNINVSAKVHATNNFSDDVFSYGYSSDVSICNNKIINDSGTKKYGIDSIRKSSTETGNRAIISGNHVIGFEIGICARGLGVKISNNYLKDISSIGIYPYLAEEVSVSDN-IIDSNCLHVWVRESKDVKISDNKTKGAANYFAYRVEASSDV-IISDSKSQSKGGIQVLRSRKVVLKDNDLALIGTDYGIHWDKQSEVEVLHNTVRDAAMIAIAGNSELYPSIIKGNNIKDCTYLVGLYVNGGSDHILWDNDVSFTGSANGGYGVQLVGTENAWLMNNKVRVSNGRTLSSSYESRGSQNTMYINNALQTG--------------
+>tr|A0A7T7ZC39|A0A7T7ZC39_9CAUD Minor tail protein OS=Bacillus phage 015DV002 OX=2801832 GN=212 PE=4 SV=1
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KSGVRVSRSTNVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>tr|R4JDQ9|R4JDQ9_9CAUD SPBc2 prophage-derived protein YorA OS=Bacillus phage SIOphi OX=1285382 GN=SIOphi_00245 PE=4 SV=1
+---------YFIDFDQFGIKDDGTDATSTTSGFVAAFKRAVELGHSAVYVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGHIVGDRHEHNYRQVNENRRTHEWGFGIQVRGSKNVTIENVTIEDCTGDNIWVTSKGMMNWPG-VYIPSESVTIRKCRTLRGRRNNIAAGASVGLLIDDCDIIEAGGDEIGPQLGIDLEGYADNSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGHKKFGIDSIRKSTSETANRAVVTGNVIRGFQTGIAARGKTVTVSNNILEDISSIGIYPYLCDQAVVSSN-IIDSDCLHIWVRESKDIKVSDNKGTGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSTNVRIVDNDIDMIGPDYGIYFDKQSEVHLRDNLVKNAAFTAIRGYADQYSSYIKGNIIQDCKYMIAIHIDGGSKHMIKDNDITFRRGSNAGYGVYLIGANDSRLHNNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>tr|A0A7U3TFK2|A0A7U3TFK2_9CAUD Minor tail protein OS=Bacillus phage 015DV004 OX=2801833 GN=228 PE=4 SV=1
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQSNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSTNVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>tr|A0A5J6TBR2|A0A5J6TBR2_9CAUD Tail spike OS=Bacillus phage 035JT001 OX=2601659 GN=8 PE=4 SV=1
+---------YELECDRWGIFPDGTNPESTTRGFNDALTFAAAEGYKEIYIPKGVYKIDCVSRFGSK-PEYGGGIRNPSNLDVDMHTEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEDKTKTHEWGYGVHIRGSKNINIENMFISDCTGDNIWVAANGMMNYEGSTYIPSKDVTVRKCTLMRGRRNGLATNGCEGLLVDDCTIEESGGGGTRPEYGIDLEGFGEGGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRASIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSALVIGNRI-DADCTHIQMLYAEKTTVIGNESEGNTQNFAYKVTYSDRTVFSGNTLYDGDGGLDVGQSTLTKFKGNTLFLTGENFGVHWGSSSDLEVSGNTFHMGSGVAIFGYADLHTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKIARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSAGTLVDGNKYN----------------
+>tr|A0A2I6UI00|A0A2I6UI00_9CAUD Uncharacterized protein OS=Bacillus phage BSP10 OX=2069312 GN=BSP10_173 PE=4 SV=1
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALKDAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAKNYYGIKVEDSSDV-VVNDNKQVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKTSQVKLVKNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>tr|A0A890URD5|A0A890URD5_9CAUD Tailspike OS=Bacillus phage BSTP3 OX=2801528 GN=BSTP3_034 PE=4 SV=1
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALKDAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAKNYYGIKVEDSSDV-VVNDNKQVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKTSQVKLVKNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>tr|U5PXV9|U5PXV9_9CAUD Tailspike OS=Bacillus phage Grass OX=1406785 GN=Grass_33 PE=4 SV=1
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALKEAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFMVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTVPDNRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPAKGMMNWEGSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFSYGFSTDSTISNNTITNETGDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVQVGNNKGKDAENYYGIKVEDSSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKTSQVKLIKNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>tr|S6BUP9|S6BUP9_9CAUD Beta_helix domain-containing protein OS=Bacillus phage phiNIT1 OX=207656 GN=orf587 PE=4 SV=1
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALREAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAENYYGIKVEDSSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKISQVKLVKNWISCAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>tr|A0A384XD57|A0A384XD57_9CAUD Uncharacterized protein OS=Bacillus phage BSP9 OX=2041339 GN=BSP9_162 PE=4 SV=1
+----NSNYMYFVDFEKFGIRSDGTEARATTEGWIAALKEAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAENYYGIKVEASSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKISQVKLVKNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>tr|L0L8C8|L0L8C8_9CAUD Putative Pectin lyase-like protein OS=Bacillus phage phiAGATE OX=1204533 PE=4 SV=1
+---------YFIDFEKHGIKSDGTAARETTDGFTYALNDAVNKGYKTVYVPKGDYLINGVG--EDRMPEYGGGIQFPSNIEVIFHKKAIFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMVSKFRKTHEWGYGVHIRGSRNILVEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTERGRRNNIATDGCLGLLIDDCDIIEAGGDTIGPQLGIDLEGFAEDGIKYGHPYEINVVNNRIRNNGRGSLNINVSAKVHASNNFSDDVFSYGYSSDVSICNNKIINDSGKRKYGIDSIRKSSTETGNRAIITGNHIIGFEIGICARGLGVKIANNYLKDISSIGIYPYLAEEVSVSDN-IVDSNCLHVWVRESKDVKISDNKTKGADNDFAYRVESSSDV-IISDSKSQANGGIQVIRSRKVTLKDNDLTLTGADYGIYWDKQSEVEVLHNTVRDAAMIAIAGNSNLYPSIVKGNNIKDCTYLVGLYMNGGRDHVIWDNDVSFKGSSNGGYGVQLIATTNAWLMDNKVRVSNGRTLSSAYESQSSYKTLYVNNAMQIG--------------
+>tr|A0A1Z1DEW7|A0A1Z1DEW7_9CAUD Tailspike protein OS=Bacillus phage vB_BsuM-Goe3 OX=1933063 GN=Goe3_c03000 PE=4 SV=1
+----NSKYVYDIDFGKFGIKPDCTEAAATTEGFITALEDAVDQGYPKVYIPEGFYLIDAVGT-SGKLPEFGGGLRFPSNIEVIFHEKAVFIVDPNDATGYACFNLENVENVTLRGGVVIGDRYKHTYEGVPDNRKTHEWGYGLQIRGCRNIKVENMTLMDATGDNIWVPAKGMMNWEGSTYIPSEGITIDKCYTLRGRRNNLATNGCLGLNINDCDFVEAGGDTIGPAYGIDLEGFAENSIKYDHPYEINVTNCRFKRNGKGALTINVAGKAHATNNFSDDIISYGFSTDATISNNTITNESEEKEYGIDSIRKSSSETGNRAIITGNHIRGFKSGICARGVGVVASNNYLENISSVGIYAYLAKNVLMADNVI-NSDCLHVWVRESEDVKISNSKGKGAINNWGIKVEASSNVS-LNDNEHDSKGGVQVARSTDVRAWDNRFTLVGNEYGAYWDKTSEVVFEGNHIFNPSTIAIAGYGDTYASSIVRNTIHDCKYLTAIYLSGGSQHFVKGNDIRFRRGANGGYGIKLTGTSGVKVIGNDVRTMDGCSLNASYDSSGSVNTQYANNTYHTG--RMLLHD------
+>tr|A0A516KNA2|A0A516KNA2_9CAUD Putative pectin lyase OS=Bacillus phage vB_BveM-Goe7 OX=2593639 GN=Goe7_c00300 PE=4 SV=1
+----NSKYVYDIDFGKFGIKPDCTEAAATTEGFITALEDAVDQGYPKVYIPEGFYLIDAVGT-SGKLPEFGGGLRFPSNIEVIFHEKAVFIVDPNDATGYACFNLENVENVTLRGGVVIGDRYKHTYEGVPDNRKTHEWGYGLQIRGCRNIKVENMTLMDATGDNIWVPAKGMMNWEGSTYIPSEGITIDKCYTLRGRRNNLATNGCLGLNINDCDFVEAGGDTIGPAYGIDLEGFAENSIKYDHPYEINVTNCRFKRNGKGALTINVAGKAHATNNFSDDIISYGFSTDATISNNTITNESEEKEYGIDSIRKSSSETGNRAIITGNHIRGFKSGICARGVGVVASNNYLENISSVGIYAYLAKNVLMADNVI-NSDCLHVWVRESEDVKISNSKGKGAINNWGIKVEASSNVS-LNDNEHDSKGGVQVARSTDVRAWDNRFTLVGNEYGAYWDKTSEVVFEGNHIFNPSTIAIAGYGDTYASSIVRNTIHDCKYLTAIYLSGGSQHFVKGNDIRFRRGANGGYGIKLTGTSGVKVIGNDVRTMDGCSLNASYDSSGSVNTQYANNTYHTG--RMLLHD------
+>tr|A0A345MJP4|A0A345MJP4_9CAUD NosD domain-containing protein OS=Bacillus phage BSP38 OX=2283013 GN=BSP38_034 PE=4 SV=1
+----NSKYVYFVDFEKFGIKSDGTDAAATTSGWIAALKEAVDLGYPKVYVPAGLYLIDAVGKTDSL-PEYGGGLRFPSNIEVIFHEMALFKVEPNSSTGYACFNLENVENVTLRGGYVIGDRYEHDYTLVPNNRRTHEWGHCLHIRGCRNIYVENMTLMNATGDNIWVPAKGMMNWEGSTYIPSEGITIHKCTTIRGRRNNFATNGCIGLNIDDCDFIEAGGDVIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFTDDVISYGFSTDGTISNNTITNETGHKPFGIDSIRKSSSETGNRTIITGNQIRGFASGICARGVGVIVSNNYLSDISSVGIYPYLSEEVLVSNN-IINSDCLHVWVRESKDVKVNNTKGKGAANNYGIKVEASHDV-VLNDNEHEAKGGIQIARSTNVRVKDNDLNLIGNGNGISWDKTSQVILDGNWINGAVAIAISGYGEVYPTNIMRNTIEDCKYLIGIYLNGGSQHVIKDNDIMFRRGSNGGYGVQLKDTTDVRVYRNDVRTMDGGTLYSSFDSSGALSTKYVGNTMDAG--------------
+>tr|A0A5B9NKS7|A0A5B9NKS7_9CAUD Putative right-handed parallel beta-helix repeat-containing protein OS=Bacillus phage vB_BspS_SplendidRed OX=2591379 GN=SPLENDIDRED_11 PE=4 SV=1
+---MNKELYYHIDLERFGIRDDLTEANATTQGFNAALKDAKEQGYHYFVFPEGKYLINTISNFGGL-PEYGGGIRIPSNIHIIMD-NPYFEAEANDRTGYSIFYLEAVENVEISGGTICGDRYNHDYDLKDDRTKTHEWGFGIHIRGCRRVAIKGLTVKNCTGDNIWIPAKGMMNFPG-DYTPSRDILIQDCDLIHGRRNNLATNGCYGLTVERCDIKEAGGDTIGPQLGIDLEGYGDKGIKYDHPYEITIKNNWIKNNGRGALTAHTSGKVLIEGNFTDAVISYAYSTDVKIKDNFIINEGQEKPYGIDSIGVSSSETANRVNISGNTVSGFKTGICARGSKVKVRNNEVEGATAAAIQIFQCEKAEVSDN-TTDGNAVGLLIQQSKTVEASDNTFRGAENKYGIKIQDSSDIILKDNRIRG-FGGIFCESVQNVVVRDHDINLTGSGYGVYFDAKSCVFLDGVTIYNPENTSVYGLADEYAAIIKGVEVIGCKSIIGIYLHGGINHDIKGNTVRFKRGKDQGYGIYLDGTKGAVLARNDVVSTDGFKLSAAYKTDESEQTTLIEN-------------------
+>tr|A0A386K842|A0A386K842_9CAUD Uncharacterized protein OS=Bacillus phage Ray17 OX=2315627 GN=Ray17_11 PE=4 SV=1
+---MSKGLYYHIDLERFGIKDDLTEANATTQGFNAALKDAKDQGYHYFVFPEGKYLINAVSNFGGL-PEYGGGIRIPSNINIIMD-NPYFEAEANDQTGYSIFYLEAVENVKISGGTICGDRYNHDYDLKDDRTKTHEWGFGIHIRGCRRVEIKGLTVKNCTGDNIWIPAKGMMNWP-TDYTPSRDILIQDCDLIQGRRNNLATNGCYGLTVERCDIKEAGGDTIGPQLGIDLEGYGDKGIKYDHPYEITIKNNWIKNNGRGALTAHTSGKVLIEGNFTDAVISYAYSTDVKIKDNFIINEGQEKPYGIDSIGVSSSETANRVNISGNTVSGFKTGICARGSKVKIHGNEVEGATAAAIQIYQCEKVEVSDN-TTDGNAVGLLIQQSKTVEASDNTFRGSENKYGIKIQDSSDIILKDNRIRG-FGGIFCESAQKVIVRDHDIDLTGSGYGVYFDAKSSVFLDGVTIYNPENTPVYGLADEFAAIMKDVEVIGCKSIIGIYMHGGFGHDIKGNTVRFRRGKDQGYGIFLDGTKSAVLTRNDVLSTDGFKLSAAYKTDGSERTTLIEN-------------------
+>tr|D0VXF4|D0VXF4_9CAUD Beta_helix domain-containing protein OS=Bacillus phage phiNIT1 OX=207656 PE=4 SV=1
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALREAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALTSTLQGKFMLLIT-SPMMAQLWFSTDSTISNNTITNETGDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAENYYGIKVEDSSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKISQVKLVKNWISCAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>tr|A0A0A0PLR7|A0A0A0PLR7_9CAUD Putative pectin lyase-like protein OS=Bacillus phage Bp8p-T OX=1445811 GN=Bp8pT_172 PE=4 SV=1
+-------------------------------------------------------------------PEYGGGIQFPSNIEVIFHKEAVFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMVSKFRKTHEWGYGVHIRGCRNILVEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTERGRRNNIATDGCLGLLIDDCDIVEAGGDTIGPQLGIDLEGFAEDGIKYGHPYEINITNNRFRENGRGSLNINVSAKVHATNNFSDDVFSYGYSSDVSICNNKIINESGKRKYGIDSIRKSSTETGNRAIITGNHIIGFEIGICARGLGVKIANNYLKDISSIGIYPYLAEEVSVSDN-IIDSNCLHVWVRESKDVKISDNKTKGAANHFAYRVEASSDV-LISDSKSQSKGGIQVIRSRKVILKDNDLSLTGADYGIQWDKQSEVEVLNNTVRDAAMIAIAGNSELYPSVIKGNNIKDCTYLVGLYVNGGSNHILWDNDISFTGTTNGGYGVQLVGTENVWLMNNKVRTSNGRLLSSAYESRNSKKTMYINNALQAG--------------
+>tr|A0A0A0PUI4|A0A0A0PUI4_9CAUD Putative pectin lyase-like protein OS=Bacillus phage Bp8p-C OX=1445810 GN=Bp8pC_172 PE=4 SV=1
+-------------------------------------------------------------------PEYGGGIQFPSNIEVIFHKEAVFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMVSKFRKTHEWGYGVHIRGCRNILVEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTERGRRNNIATDGCLGLLIDDCDIVEAGGDTIGPQLGIDLEGFAEDGIKYGHPYEINITNNRFRENGRGSLNINVSAKVHATNNFSDDVFSYGYSSDVSICNNKIINESGKRKYGIDSIRKSSTETGNRAIITGNHIIGFEIGICARGLGVKIANNYLKDISSIGIYPYLAEEVSVSDN-IIDSNCLHVWVRESKDVKISDNKTKGAANHFAYRVEASSDV-LISDSKSQSKGGIQVIRSRKVILKDNDLSLTGADYGIQWDKQSEVEVLNNTVRDAAMIAIAGNSELYPSVIKGNNIKDCTYLVGLYVNGGSNHILWDNDISFTGTTNGGYGVQLVGTENVWLMNNKVRTSNGRLLSSAYESRNSKKTMYINNALQAG--------------
+>tr|A0A5P8PIG3|A0A5P8PIG3_9CAUD Uncharacterized protein OS=Bacillus phage 049ML003 OX=2601661 GN=42 PE=4 SV=1
+---------YPVNLEEWGINKDFQEPEATTEAFNKAFTYAKNMGYFEVWVPPGNYLIDGVNESNIYATENGGGIHLHSNTHYKLNPESVFKINANNAQGYSVFYIGLAYNVTLEGGQLIGDRHEHDYSTVTQNRNTHEFGFGVNVHGSERVNIVNVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDVIGPQLGIDFEGYAENGIKYAHPYNLQLKNSRFRDNGRGCFTAHAVGKAIISENFFDDRVSYGFGTDISIVDNHIINDGEVRDLAIDSIQPPSYDNANRVKISGNKIKGFKKGMTIRGKEIDVTDNDLNNITETGIHVYLAEEITVNENRV-NSDCVPLNIQISKKVNVSDNTFKGGAEKYGVIVSEVEDISFKDNHI-EAGGGIDAGSAKNVRISKNEIFVKGKLNALRNNAGSTVKVNGLNIYDPAAYPMAGALDIKNV-----SIYGCKAFIAINIKNGRRHKIKNNDIVFERETNGGYGVYLSGTERTKLMDNDVSTSNDFAIGAPFHTEGSMYSTIMHNYYDSG--------------
+>tr|M4ZRV1|M4ZRV1_9CAUD Beta_helix domain-containing protein OS=Bacillus phage PM1 OX=547228 PE=4 SV=1
+---------YPLNLEEWGINKEFQEPEETTAAFNKAFEYAKSMGYFKILVPPGNFLIDGVNESNIYATENGGGIHLHSNTHYLLHPESVFKINANDAQGYSVFYIGLAYNVTLEGGQLIGDRHEHDYSTSTQNRNTHEFGFGVNVHGSERVNIINVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDTIGPQLGIDFEGYAENGVKYAHPYNLQVKDSRFKNNGRGCFTAHAVGKAIISKNFFDDRVSYGFGTDISIVDNHIINDGEVRPLAIDSIQPPSYDNANRVKISGNTIKGFKKGMTIRGKEVDVIDNKLNNITDTGIHVYLAEEITVNENRV-NSDCVPLNIQISEKVNVSDNTFKGGSEKYGVVISEVEDISFKDNHI-EAGGGIDAGVAKNVRISKNEIFVKGKLNALRNNAGSTVKVNGLNIYDPAPMELDGSAGALDIR--NVSIYGCKAFIAINIKNGKSHKIKNNDIIFNRGSNGGYGIHLSGTEKAKLTNNYVSTSDGFAIGSPYHTENSTYSTVMNNYYDSG--------------
+>tr|A0A5P8PHR1|A0A5P8PHR1_9CAUD Beta_helix domain-containing protein OS=Bacillus phage 000TH010 OX=2601652 GN=49 PE=4 SV=1
+---------YPVNLEEWGINKDFQEPEATTEAFNRAFTYAKNMGYFEVWVPPGNYLIDGVNESNVYATENGGGIHLHSNTHYKLNPESVFKINANDAQGYSVFYVGLAYNVTLEGGQLIGDRYEHNYSTVAPNRSTHEFGFGVNVHGSERVNIINVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDIIGPQLGIDFEGYAENGIKYAHPYNLQLKNSRFKDNGRGCFTAHATGKAIISENFFDDRVSYGFGTDISIVDNHIINDGEVRPLAIDSIQPPSYDNANRVKVAGNKIKGFKKGMTIRGKEVDVTDNDLNDVTETGIHVYLAEEITVNENRV-NSDCVPLNIQISKKVNVSDNTFKGGAEKYGVVISEVEDISFKDNHI-EAGGGIDAGSAKNVRISKNEIFVKGKLNALRNNPGSTMKVNGLNIYDPAAYPMELDGSAGSLDIKNVSIYGCKAFIAINIKNGRRHKIKNNDIIFERETNGGYGIYLSGTERTKLMDNDVSTSNDFAIGSPFHTENAMYSTIMHNYYDSG--------------
+>tr|A0A5P8PI75|A0A5P8PI75_9CAUD Beta_helix domain-containing protein OS=Bacillus phage 049ML001 OX=2601660 GN=42 PE=4 SV=1
+---------YSVNLEEWGINKDFQEPEATTEAFNKAFTYAKNMGYFEVWVPPGNYLIDGVNESNIYATENGGGIHLHSNTHYKLNPESVFKINANNAQGYSVFYIGLAYNVTLEGGQLIGDRHEHDYSTVTQNRNTHEFGFGVNVHGSERVNIVNVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDVIGPQLGIDFEGYAENGIKYAHPYNLQLKNSRFRDNGRGCFTAHAVGKAIISENFFDDRVSYGFGTDISIVDNHIINDGEIRALAIDSIQPPSYDNANRVKISGNKIKGFKKGMTIRGKEIDVTDNDLNNITETGIHVYLAEEITVNENRV-NSDCVPLNIQISKKVNVSDNTFKGGAEKYGVIVSEVEDISFKDNHI-EAGGGIDAGSAKNVRISKNEIFVKGKLNALRNNPGSTVKVNGLNIYDPAAYPMAGALDIKNV-----SIYGCKAFIAMNIKNGRRHKIKNNDIVFERETNGGYGVYLSGTERTKLTDNDVSTSNDFAIGAPFHTEGSMYSTIMYNYYDSG--------------
diff --git a/test/unit/data/uniprot.mode5.txt b/test/unit/data/uniprot.mode5.txt
new file mode 100644
index 00000000..8e8d2208
--- /dev/null
+++ b/test/unit/data/uniprot.mode5.txt
@@ -0,0 +1,120 @@
+>O31912
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A6H0H3G5
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A162RH73
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A6M4JNF4
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>O64135
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>O31912
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A857HHC0
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFPIVEVPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGGSKEYGIDSVGVSSTETGNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSAYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVKGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGARVLSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A410R1H8
+MTLLNKSIRYYVDFDQWGINAFNSNPIETTKGFNEALIYASENNFSIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNTELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGVSSTETSNRIQITDNNIQGFKIGMMIRGKGVSVDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSTYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGTRVLSHPYATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A7G5CIE1
+MTLLNKSIRYYVDFDQWGINAFNLNPIETTKGFNEALIYASENNFPIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGFSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVCNNKGKGTTSTYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYFNGTKKVRLIRNDVQGIGTRVLSHPYATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A7G5CIX1
+MTLLNKSIRYYVDFDQWGINAFNLNPIETTKGFNEALIYASENNFPIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGFSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVCNNKGKGTTSTYAIKVMDSNDVKFLNNTFSNLYGGLYCERSQAVRIKLNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYFNGTKKVRLIRNDVQGIGTRVLSHPYATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>G4EVD8
+MTLLNKSIRYYVDFDQWGINAFNLNPIETTKGFNEALIYASENNFPIVEIPKGNFIIDSVNTLNQRNPEIGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGRIIGDRYQHDYSLIDTNRKTHEWGFGIHVHGSKNVLIENVQISDCIGDNIWIAAHGMMNYPGMVYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGFSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVCNNKGKGTTSTYAIKVMDSNDVTFINNKFSNLYGGLYCERSQSIRIKQNDFLLSGKGYGIYWDKDSKVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIMFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGSRILSHPFATFNASSTTLIHNTYDSGTPRLALDDTVIDYK
+>A0A7G5CHW7
+MILLNKSMRYYVDFDQWGINAFNSNPNETTKGFNEALIYASKNNFPIVEIPKGNFIIDSVNTLNQRNPEVGGGIKIPSNMELLLDPEAVFQVNPNGYQGYSCFYIGLAENVIIRGGHIIGDRYQHDYSLIDTDRKTHEWGFGIHVHGSKNVLIENVKISDCIGDNIWIAAHGMMNYPGMAYTPSKSVTVRKCELKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGYGENGRKYDHPYELTISDCRFRKNGRGSVTAHTSGKVSIKDNYCDNVISYGYSTDVSIKGNKIINEGESKEYGIDSVGVSSTETSNRIQITDNNIQGFKIGMMIRGKGVSIDNNTVKNASNCAIATHMAEDVSISNNRIQDSDCIQIQVRNSSDIKVSNNKGKGTTSTYAIKVMDSNDVTFINNKFSNLYGGLYCERSQSIRIKKNDFLLSGKGYGIYWDKDSEVFLTRNEIFEPRNVAIMGAADMYNIRISDNQIYNCKAIIAIHLIGGSEHMVRGNEIVFNRDSDQGYGIYLNGTKKVRLIRNDVQGIGSRILSHPFATFNASSTTLIHNTYDSGTPRLALDDTLIDYK
+>A0A837Y204
+MNMIDKSLRVHVDFEQWGINPEGLNPIETTKGFNDALQSAASNFYSVVEVPKGNYLIDAVNT-SKRLPEFGGGIKIPSNIELILHPEAVFRVNPNGYQGYSCFYIGQAENVTIRGGRIIGDRYEHDYSKINTIQKTHEWGYGIHVHGSRNVLIENVSVSDCIGDNIWIAADGMMN-TDVTYTPSRSVTVRKCRLKRGRRNNLATNGCEGLLVEDCDIEEAGGDTIGPQLGIDLEGFAEKGIKYDHPYELTIADCRFKKNGRGSITAHTSGKVIIKDNYCDNVISYGFSTDVSIKGNKIINEGEPKEYGIDSIGVSSTETGNRAKITGNTVRGFKIGIMVRGRGVTAKNNTIGNSSNCAIATHTAEEVFIAKNKIENSNCIQIQVRNSSDVKVNGNTGKGTTSSYALKVIDSKDVTLTGNEFSNIYGGLYCERSQAVRVKSNDFLMRGTGYGIYWDKSSEVFLTRNEIYEPRNIAITGTADIYNIRISENQIYNCKALVAIHLLGGSDHMLRGNEIMFNREADQGYGIYLESTKKVRLIRNDVQGIGDRVLSHPYATFKSSNTTLIHNTYNSGTLRLAVDDIVI---
+>A0A150FBD2
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGFNRALEYASSNSFFRVYVPKGKYLIDAVNT-TKRLPEFGGGIYVPSNIELILHPEAVFHVLPNDYQGYSCFYVGQASNVTIRGGQIIGDRYEHDYSKINSTQETHEWGYGIHIHGSKNVLIENVSISDCIGDNIWIAAYGMMNTSG-TYTPSRNVTVRKCTLKRGRRNNLATNGCEGFLVDDCDIEEAGGDTIGPQLGIDLEGFGEKGIKYDHPYKLTVRNCRFKNNGRGSITAHTSGKVIIDGNYCDNVISYGYSTDVSIKNNKIINEGSVKTYGIDSVGVSTTESGNRVQIDGNTVSGFEVGICARGKGVTISNNTLERIKACPISTHQAEDVLITDNRMENSDCIQVQVRNSNDVRVVNNKGKGTTTAYASKIMDSTRVSLINNEFVNVYGGVYCERSQSVRLKGNDLILSGSGHGIFWDKDSSVSLHRNEIHEPKNVAIKGTPEKYSCQISENQIYFCKSLIAIHLVGGSEHILKDNEIMFNRSSDQGYGVYLENTNKARLVRNDVHGIGGKLLSHPYCTEKAKNTTLIHNTYNSGTLKTAEGDTIV---
+>A0A109WGG2
+---MRQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKISAIQKTHEWGYGIHVHGSSNVLIENVQVSDCIGDNIWIAAEGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGEVNLEGNYSDNVISYGYSTDVSVKDNKIINKGKSKKYGIDSVGVSSTESGNRVQIIGNTVRGFEIGICVRGKGVHVADNILENITACPIATHEAEDVFISNNHIENSDCIQVQVRNSKDVRVTNNKGGNTTSAYAIKIMDSNRVSFAINEFANVHGGVYCERSQSVRLKLNDLFLSGSGYGIFWDKDSEVYFNGNEIHNPRNVAIKGTSEKYSCQISENQIYFCKSLIAIHLAGGSEHMLNNNEIMFNRSTDQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>A0A8A5UUR4
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNITVRKCALLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGEVNLEGNYSDNVISYGYSTDVSVKDNKIINKGNSKKYGIDSVGVSSTESGNRVQISGNTVRGFEIGICVRGKGIDVTDNILENISACPIATHEAEDVFISNNHIENSDCIQVQVRNSKDVRVTNNKGGNTTSAYAIKIMDSNRVSFAINEFANVHGGVYCERSQLVRLKLNDLFLGGSGYGIFWDKDSEVYFNGNEIHNPRNVAIKGTSEKYSCQISKNQIYFCKSLIAIHLTGGSEHMLNNNEIMFNRSTDQGYGVYLENTNKVRLVRNDTRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>A0A4R2A540
+---MQQPLYYSVDALDWGIDDKGSNAIETTEGINRALKYASSKSFYKVHIPKGTYLIDAVNT-SRRLPEFGGGINIPSNIELILHPEAVFKVLPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKVTSIKRTHEWGYGIHIHGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGQVIIEGNYSDNVISYGFSTDVSIKNNKIINDAETKKYGIDSVGVSSTESGNRVQIEGNTVRGFEIGICARGKGVLISNNTLEGIKTCPIATHQAEDVLITDNRIENSDCIQVQVRNSNDVRVVNNKGKGTISAYAVKIMDSTRISLINNEFVNVYGGIYCERSQSVRLKGNDLLLNGSGYGIFWDKDSSVSLQRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKALIAIQLTGGSEHMLKDNEIMFNRSTDQGYGVYLENTDKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>A0A853LAC0
+---MQQPLFYFVDAQDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGTYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIKEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIDGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGIDSVGVSSTESGNRVQIDGNTISGFEVGICVRGQGGTVSNNTLEKIKACPIATHQAEDVLITDNRIENSDCIQVQVRNSNDIRVVNNKGKGTTSAYAAKIMDSTRISLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPDKYSCQISENQIYLCKSLIAVQLTGGSEHILKDNEIMFNRSADQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIYNTYDSGTLKTAEGDIVV---
+>S6FH05
+---MQQPLYYSVDALDWGIDDKGSNAIETTEGINRALKYASSKSFYKVHIPKGTYLIDAVNT-SRRLPEFGGGINVPSNIELVLHPEAIFKVLPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKVTSIKRTHEWGYGIHIHGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGQVIIEGNYSDNVISYGFSTDVSIKNNKIINDAEVKKYGIDSVGVSSTESGNRVQIEGNTVRGFEVGICARGKGVSISNNTLEGIKACPIATHQAEDVLITDNRIENSDCIQVQVRNSNDVRVVNNKGKGTISAYAVKIMDSTRISLINNEFVNVYGGIYCERSQSVRLKGNDLLLNGSGYGIFWDKDSSVSLQRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKALIAIQLTGGSEHILKDNEIMFNRSTDQGYGVYLENTDKVRLVRNDARGIGGKLLSHPYCTDKAKNTTLIHNTFDSGTLKTAEGDIVV---
+>A0A6H3B795
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGVDSVGVSSTESGNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLITDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSTRISLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKSLIAIQLTGGSEHILKDNEIMFNRSVDQGYGVYLENTDKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>A0A7U4HXJ2
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYACSKSFYKVYVPKGIYLIDAVNT-SKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINEKEIKTYGIDSVGVSSTESGNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLFTDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSSRVSLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPDKYSCQISENQIYFCKSLIAIQLTGGSEHILKDNEIMFNRSADQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIYNTYDSGTLKTAEGDIVV---
+>I2C5Q7
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDAVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVQPNDYQGYSCFYIGQASNVTIRGGQIIGDRHEHDYSKITSIKKTHEWGFGIHVNGSSNVLIENVQVSDCIGDNIWIAADGMMNTSG-TYTPSKNVTVRKCTLLRGRRNNLATNGCEGLLVDDCDIEEAGGGTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGVDSVGVSSTESGNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLITDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSTRISLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKSLIAIQLTGGSEHILKDNEIMFNRSVDQGYGVYLENTDKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDIVV---
+>A0A4V7TQN6
+---MQQPLYYFVDALDWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGVYLIDAVNTA-KRLPEFGGGINVPSNIELILHPEAIFKVQPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKINAIQKTHEWGYGIHIHGSNNILIDGVHVSDCIGDNIWIAADGMMNTSG-VYTPSSSATVQKCTLLRGRRNNMATNGCEGLLVDDCDIEEAGGDTIGPQLGIDLEGFGENGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSGKVIIEGNYSDHVISYGYSTDVSIKNNKIINENEIKTYGIDSVGVSSTESSNRVQIDGNTISGFEVGICVRGKGGTVSNNTFEKIKACPIATHQAEDFLISDNRIENSDCVQVQVRNSNDIKVVNTKGKGTSSSYAAKIMDSSRVSLVNNEFANVYGGIYCERSQSVRLKGNDLLLSGSGYGIFWDKDSSVSLHRNEIHEPRNVAIKGTPEKYSCQISENQIYFCKSLIAIQLTGGSEHMLKDNEIMFNRSADQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIYNTYDSGTLKTAEGDIVV---
+>A0A8B2V7S0
+---------YFVDALNWGIDDKGSNAIETTEGLNRALEYASSKSFYKVHIPKGIYLIDSVNT-TKRLPEFGGGINVPSNIELILHPEAIFKVLPNDSQGYSCFYIGQASNVTIRGGQIIGDRYEHDYSKINAIQKTHEWGYGIHVHGSSNVLIDGVHVSDCIGDNIWIAADGMMNTSGK-YTPSRSVTVQKCTLKRGRRNNLATSGCNGLLVDDCDIEEAGGDTIGPQLGIDLEGYGEDGIKYDHPYKLTVRNCRFKNNGRGSVTAHTSDKVIIEGNYSDHVISYGYSTDVSIKNNKIINENQVKTYGIDSVGVSSTESGNRVQINGNTIRGFAIGVCVRGKGIDVTDNIFENITACPITTHEAEDVYISDNHIENSDCIQVQVRNSKDVRVTNNKGGNTTSSYAIKVMDSNRVSCAINEFANVNGGVYCERSQSVRLKGNDFFLNGSGYGIFWDKDSEMYMNRNEIHNPRNFAIKGTSEKYSCQISENQIYFCKSLIAIHLTGGSEHMLNNNEIMFNRSTDQGYGVYLENTNKVRLVRNDVRGIGGKLLSHPYCTDKAKNTTLIHNTYDSGTLKTAEGDVVV---
+>A0A7T7ZAL2
+---------YELEIDRWGISSGGSNPIETTQGFNDAIQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIYIKNVFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLIRGRRNCLATNGCEGLLVDDCAIEDAGGEgGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVESNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGIYWGVNSEVEAKGNTIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGVKLKNNSVEVTNDRGLTSSFYTEKSTDSLVVMNDYNKGVIKSHETDTV----
+>A0A5J6T752
+---------YELEIDRWGISSGGSNPIETTQGFNDAVQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTKTHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLVRGRRNCLATNGCEGLLVDDCAIEDAGGEgGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVGNNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGTGMGIYWGINSEVEAKGNIIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKTHETDTV----
+>A0A5J6T3Z8
+---------YELEIDRWGISSGGSNPIETTQGFNDAVQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTKTHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLVRGRRNCLATNGCEGLLVDDCAIEDAGGEgGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVGNNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGTGMGIYWGINSEVEAKGNIIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKTHETDTV----
+>A0A5J6T9J0
+---------YELEIDRWGISSGGSNPIETTQGFNDAIQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TLYTPARDVTVSKCTLIRGRRNCLATNGCEGLLVDDCAIEDAGGEgGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGALVESNTLENISAVAVQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGIYWGVNSEVEAKGNTIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKSHETDTV----
+>A0A5J6T6D8
+---------YELEIDRWGISSGGSNPIETTQGFNDAIQYAKTEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIHIKNVFVADCTGDNIWIAAHGMMNWT-TLYTPARDVTVSKCTLIRGRRNCLATNGCEGLLVDDCAIEDAGGEgGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKVIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGALVESNTLENISAVAVQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGIYWGVNSEVEAKGNTIEAGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKSHETDTV----
+>A0A5P8PIC1
+---------YELEIDRWGISSGGSNPIETTQGFNDAVQYAKSEGYAEIFVPKGHYLIDCVSKFGSR-PEYGGGIRLVSDLNVTLHPEATFKVLANDATGYSLFYLELIENVTIKGGRIYGDRYEHTYTYYNDNTETHEWGYGIHVRGSRNIHIKNAFVADCTGDNIWIAAHGMMNWT-TPYTPARDVTVSKCTLVRGRRNCLATNGCEGLLVDDCAIEDAGGEgGTRPQYGIDLEGFGESGIKYDHPYKLVVRNCKFKGNALGDISSFTAGKIIIEGNTCENVISYGYSTDILIENNLIINEGEVKPYGIDSLGVSSTETGNRATIKGNTIRGFNIGINAKGKGVLVESNTLENISAVAIQVYQATDALIANNRV-DSDCIHFQALLAENTLFAGNKSEGNSKDYAYKITNSKGITFTGNELTEGYGGYYVQGSLRSKIISNTLQLVGAGMGVYWGVNSEVEAKGNTIEVGSGVPIMGYADLYKAIIKDNTVKGCQAVYAVYLKGGKRHNIESNILEIARNADYGYGVYIEGTSGAKLKGNSVEVTNDRGLTSSFYTEKSTGSLVVMNDYNKGVIKSHETDTV----
+>A0A5J6T5S7
+---------YELECDRWGIFPDGTNPVETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYTGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGgtrPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNTYN----------------
+>A0A5J6T527
+---------YELECDRWGIFPDGTNPVETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYTGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGgtrPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNTYN----------------
+>A0A5J6T6E0
+---------YELECDRWGIFPDGTNPVETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYAGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGgtrPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTIVDGNKYN----------------
+>A0A5J6T8J3
+---------YELECDRWGISPDGTNPTETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYAGSTYITARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTIEEAGG--VGgtrPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRVSIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSSLVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLYTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNKYN----------------
+>A0A7U3TW25
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQdVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGvHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSTNVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>A0A5J6T602
+---------YELECDRWGISPDGTNPPETTKGFNDALNYAAAEGYREIYIPKGVYKIDCVSNFGSR-PEYGGGIRNPSNLDVDMHPEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYHEEKTKTHEWGYGIHIRGSKNINIENVFVSDCTGDNIWIAANGMMNYAGSTYIPARDVTIKKCTLMRGRRNCLATNGCEGLLVDDCTVEEAGG--VGgtrPEYGIDLEGFGENGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGVVKPYGIDSLGVSSTETGNRASIKGNTIRGFNIGINAKGKGILVSKNTIEDVESVGIQVYQATSALVIGNRI-DADCTHIKMLYAKKTTVIGNESEGNTDNFAYQVTYSERTVFSGNTLYDGDGGLSVGNSTLTKFKGNTLFITGENYGVHWDASSDLEVSDNTFHMGSGVAIMGYADLHTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKVARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSVGTLVDGNKYN----------------
+>A0A7T8C426
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQdVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGvHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSINVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>A0A076G7N8
+---------YFIDFEKHGIRSNGTAARETTDGFISALNDAVASGYKTVYVPKGNYLIDGVG--EDKMPEYGGGIQFPSNIEVIFHKEAVFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMnVSPFRRTHEWGYGVHIRGCRNILIEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTEKGRRNNIATDGCLGLLIDDCDIIKAGGDTIGPQLGIDLEGYAEDGIKYGHPYEINITNCRFRKNGRGALNINVSAKVHATNNFSDDVFSYGYSSDVSICNNKIINDSGTvKKYGIDSIRKSSTETGNRAIISGNHVIGFEIGICARGLGVKISNNYLKDISSIGIYPYLAEEVSVSDN-IIDSNCLHVWVRESKDVKISDNKTKGAANYFAYRVEASSDV-IISDSKSQSKGGIQVLRSRKVVLKDNDLALIGTDYGIHWDKQSEVEVLHNTVRDAAMIAIAGNSELYPSIIKGNNIKDCTYLVGLYVNGGSDHILWDNDVSFkgTGSANGGYGVQLVGTENAWLMNNKVRVSNGRTLSSSYESRGSQNTMYINNALQTG--------------
+>A0A7T7ZC39
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQdVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGvHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KSGVRVSRSTNVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>R4JDQ9
+---------YFIDFDQFGIKDDGTDATSTTSGFVAAFKRAVELGHSAVYVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQPNDSTGYACFNLEGVENVTIRGGHIVGDRHEHNYRQdVNENRRTHEWGFGIQVRGSKNVTIENVTIEDCTGDNIWVTSKGMMNWPG-VYIPSESVTIRKCRTLRGRRNNIAAGASVGLLIDDCDIIEAGGDEIGPQLGIDLEGYADNSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGvHKKFGIDSIRKSTSETANRAVVTGNVIRGFQTGIAARGKTVTVSNNILEDISSIGIYPYLCDQAVVSSN-IIDSDCLHIWVRESKDIKVSDNKGTGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSTNVRIVDNDIDMIGPDYGIYFDKQSEVHLRDNLVKNAAFTAIRGYADQYSSYIKGNIIQDCKYMIAIHIDGGSKHMIKDNDITFRRGSNAGYGVYLIGANDSRLHNNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>A0A7U3TFK2
+---------YFIDFEQFGIKGDGTDATSTTNGFVAAFKRAVELGYSAVFVPEGTYLIDAVG-VGDYLPEYGGGLQFPSNIEVILHEKALFKVQSNDSTGYACFNLEGVENVTIRGGRIVGDRYEHNYRQdVNENRRTHEWGFGIQVRGSKNITIENVTIEDCTGDNIWVTSKGMMNWPG-EYIPSKSVTIRKCQTYRGRRNNIAAGASVGLLIDDCDIIEAGGDTIGPQLGIDLEGYADKSIKYQHPYEINVINCRFKDNGRGSMNINVSGKVNAIGNFCDDYIGYGFSTDVTISNNVITNETGvHKKFGIDSIRKSTSETANRAVIVGNVIRGFQTGIAARGKTVTVSDNILEDISSIGIYPYLCEQAVVSDN-IIDSDCLHIWVRESKDIKVSDNKGIGAANNVSIKVDASKDVLLSDNEVSG-KGGVRVSRSTNVRIVDNDIELIGADYGIYFDKQSEVHLRDNLIKNAAFTAIMGYADQYSSYIRGNIIQDCKYMIAVHIDGGAKHMIKDNDITFRRGSNAGYGIYLIGANDSRLHSNDIRVMDGFGLINSFYTIQSTNTKLIGNTYDTG--------------
+>A0A5J6TBR2
+---------YELECDRWGIFPDGTNPESTTRGFNDALTFAAAEGYKEIYIPKGVYKIDCVSRFGSK-PEYGGGIRNPSNLDVDMHTEATFLVLENDAVGYSLFYINLAENITMKGGRIIGDRYKHTYTYYEDKTKTHEWGYGVHIRGSKNINIENMFISDCTGDNIWVAANGMMNYEGSTYIPSKDVTVRKCTLMRGRRNGLATNGCEGLLVDDCTIEESGGaGGTRPEYGIDLEGFGEGGIKYDHPYKLIIRNCRIKNNGLGAISSFTAGKVIIEGNEVDDVISYGYSTDVTITNNQIINEGEIKPYGIDSLGVSSTETGNRASIKGNTIRGFNIGINAKGKGILVSKNTIEDVESIGIQVYQATSALVIGNRI-DADCTHIQMLYAEKTTVIGNESEGNTQNFAYKVTYSDRTVFSGNTLYDGDGGLDVGQSTLTKFKGNTLFLTGENFGVHWGSSSDLEVSGNTFHMGSGVAIFGYADLHTNIIKDNVIHDSKATYAIYLKGGSFHAVERNTVKIARNADFGYGIYIEGTTGVRMTGNDVAVTNGRDLTAPITTEKSAGTLVDGNKYN----------------
+>A0A2I6UI00
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALKDAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTdgVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGiDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAKNYYGIKVEDSSDV-VVNDNKQVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKTSQVKLVKsNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>A0A890URD5
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALKDAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTdgVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGiDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAKNYYGIKVEDSSDV-VVNDNKQVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKTSQVKLVKsNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>U5PXV9
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALKEAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFMVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTdgVPDNRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPAKGMMNWEGSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFSYGFSTDSTISNNTITNETGiDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVQVGNNKGKDAENYYGIKVEDSSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKTSQVKLIKsNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>S6BUP9
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALREAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTdgVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGvDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAENYYGIKVEDSSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKISQVKLVKsNWISCAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>A0A384XD57
+----NSNYMYFVDFEKFGIRSDGTEARATTEGWIAALKEAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTdgVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFSDDVFNYGFSTDSTISNNTITNETGiDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAENYYGIKVEASSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKISQVKLVKsNWISGAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>L0L8C8
+---------YFIDFEKHGIKSDGTAARETTDGFTYALNDAVNKGYKTVYVPKGDYLINGVG--EDRMPEYGGGIQFPSNIEVIFHKKAIFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMnVSKFRKTHEWGYGVHIRGSRNILVEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTERGRRNNIATDGCLGLLIDDCDIIEAGGDTIGPQLGIDLEGFAEDGIKYGHPYEINVVNNRIRNNGRGSLNINVSAKVHASNNFSDDVFSYGYSSDVSICNNKIINDSGKvRKYGIDSIRKSSTETGNRAIITGNHIIGFEIGICARGLGVKIANNYLKDISSIGIYPYLAEEVSVSDN-IVDSNCLHVWVRESKDVKISDNKTKGADNDFAYRVESSSDV-IISDSKSQANGGIQVIRSRKVTLKDNDLTLTGADYGIYWDKQSEVEVLHNTVRDAAMIAIAGNSNLYPSIVKGNNIKDCTYLVGLYMNGGRDHVIWDNDVSFKgvGSSNGGYGVQLIATTNAWLMDNKVRVSNGRTLSSAYESQSSYKTLYVNNAMQIG--------------
+>A0A1Z1DEW7
+----NSKYVYDIDFGKFGIKPDCTEAAATTEGFITALEDAVDQGYPKVYIPEGFYLIDAVGT-SGKLPEFGGGLRFPSNIEVIFHEKAVFIVDPNDATGYACFNLENVENVTLRGGVVIGDRYKHTYvqEGVPDNRKTHEWGYGLQIRGCRNIKVENMTLMDATGDNIWVPAKGMMNWEGSTYIPSEGITIDKCYTLRGRRNNLATNGCLGLNINDCDFVEAGGDTIGPAYGIDLEGFAENSIKYDHPYEINVTNCRFKRNGKGALTINVAGKAHATNNFSDDIISYGFSTDATISNNTITNESEElKEYGIDSIRKSSSETGNRAIITGNHIRGFKSGICARGVGVVASNNYLENISSVGIYAYLAKNVLMADNVI-NSDCLHVWVRESEDVKISNSKGKGAINNWGIKVEASSNVS-LNDNEHDSKGGVQVARSTDVRAWDNRFTLVGNEYGAYWDKTSEVrVFEGNHIFNPSTIAIAGYGDTYASSIVRNTIHDCKYLTAIYLSGGSQHFVKGNDIRFRRGANGGYGIKLTGTSGVKVIGNDVRTMDGCSLNASYDSSGSVNTQYANNTYHTG--RMLLHD------
+>A0A516KNA2
+----NSKYVYDIDFGKFGIKPDCTEAAATTEGFITALEDAVDQGYPKVYIPEGFYLIDAVGT-SGKLPEFGGGLRFPSNIEVIFHEKAVFIVDPNDATGYACFNLENVENVTLRGGVVIGDRYKHTYvqEGVPDNRKTHEWGYGLQIRGCRNIKVENMTLMDATGDNIWVPAKGMMNWEGSTYIPSEGITIDKCYTLRGRRNNLATNGCLGLNINDCDFVEAGGDTIGPAYGIDLEGFAENSIKYDHPYEINVTNCRFKRNGKGALTINVAGKAHATNNFSDDIISYGFSTDATISNNTITNESEElKEYGIDSIRKSSSETGNRAIITGNHIRGFKSGICARGVGVVASNNYLENISSVGIYAYLAKNVLMADNVI-NSDCLHVWVRESEDVKISNSKGKGAINNWGIKVEASSNVS-LNDNEHDSKGGVQVARSTDVRAWDNRFTLVGNEYGAYWDKTSEVrVFEGNHIFNPSTIAIAGYGDTYASSIVRNTIHDCKYLTAIYLSGGSQHFVKGNDIRFRRGANGGYGIKLTGTSGVKVIGNDVRTMDGCSLNASYDSSGSVNTQYANNTYHTG--RMLLHD------
+>A0A345MJP4
+----NSKYVYFVDFEKFGIKSDGTDAAATTSGWIAALKEAVDLGYPKVYVPAGLYLIDAVGKTDSL-PEYGGGLRFPSNIEVIFHEMALFKVEPNSSTGYACFNLENVENVTLRGGYVIGDRYEHDYTLdgVPNNRRTHEWGHCLHIRGCRNIYVENMTLMNATGDNIWVPAKGMMNWEGSTYIPSEGITIHKCTTIRGRRNNFATNGCIGLNIDDCDFIEAGGDVIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALNINVTGKVHATNNFTDDVISYGFSTDGTISNNTITNETGvHKPFGIDSIRKSSSETGNRTIITGNQIRGFASGICARGVGVIVSNNYLSDISSVGIYPYLSEEVLVSNN-IINSDCLHVWVRESKDVKVNNTKGKGAANNYGIKVEASHDV-VLNDNEHEAKGGIQIARSTNVRVKDNDLNLIGNGNGISWDKTSQVkILDGNWINGAVAIAISGYGEVYPTNIMRNTIEDCKYLIGIYLNGGSQHVIKDNDIMFRRGSNGGYGVQLKDTTDVRVYRNDVRTMDGGTLYSSFDSSGALSTKYVGNTMDAG--------------
+>A0A5B9NKS7
+---MNKELYYHIDLERFGIRDDLTEANATTQGFNAALKDAKEQGYHYFVFPEGKYLINTISNFGGL-PEYGGGIRIPSNIHIIMD-NPYFEAEANDRTGYSIFYLEAVENVEISGiGTICGDRYNHDYvrDLKDDRTKTHEWGFGIHIRGCRRVAIKGLTVKNCTGDNIWIPAKGMMNFPG-DYTPSRDILIQDCDLIHGRRNNLATNGCYGLTVERCDIKEAGGDTIGPQLGIDLEGYGDKGIKYDHPYEITIKNNWIKNNGRGALTAHTSGKVLIEGNFTDAVISYAYSTDVKIKDNFIINEtGQEKPYGIDSIGVSSSETANRVNISGNTVSGFKTGICARGSKVKVRNNEVEGATAAAIQIFQCEKAEVSDN-TTDGNAVGLLIQQSKTVEASDNTFRGAENKYGIKIgQDSSDIILKDNRIRG-FGGIFCESVQNVVVRDHDINLTGSGYGVYFDAKSCVFLDGVTIYNPENTSVYGLADEYAAIIKGVEVIGCKSIIGIYLHGGINHDIKGNTVRFKRGKDQGYGIYLDGTKGAVLARNDVVSTDGFKLSAAYKTDESEQTTLIEN-------------------
+>A0A386K842
+---MSKGLYYHIDLERFGIKDDLTEANATTQGFNAALKDAKDQGYHYFVFPEGKYLINAVSNFGGL-PEYGGGIRIPSNINIIMD-NPYFEAEANDQTGYSIFYLEAVENVKISGiGTICGDRYNHDYvrDLKDDRTKTHEWGFGIHIRGCRRVEIKGLTVKNCTGDNIWIPAKGMMNWP-TDYTPSRDILIQDCDLIQGRRNNLATNGCYGLTVERCDIKEAGGDTIGPQLGIDLEGYGDKGIKYDHPYEITIKNNWIKNNGRGALTAHTSGKVLIEGNFTDAVISYAYSTDVKIKDNFIINEtGQEKPYGIDSIGVSSSETANRVNISGNTVSGFKTGICARGSKVKIHGNEVEGATAAAIQIYQCEKVEVSDN-TTDGNAVGLLIQQSKTVEASDNTFRGSENKYGIKIgQDSSDIILKDNRIRG-FGGIFCESAQKVIVRDHDIDLTGSGYGVYFDAKSSVFLDGVTIYNPENTPVYGLADEFAAIMKDVEVIGCKSIIGIYMHGGFGHDIKGNTVRFRRGKDQGYGIFLDGTKSAVLTRNDVLSTDGFKLSAAYKTDGSERTTLIEN-------------------
+>D0VXF4
+----NSNYMYFVDFEKFGIRSDGTEARATTDGWIAALREAVELGYHTVYVPEGLYLIDAVSTVGSL-PEYGGGLMFPSNIEVIFHERALFQVAPNSSTGYACFNLENVENVTLRGGTIIGDRYEHDYVTdgVPDKRKTHEWGHGIHIRGCRNITVENATVMNCTGDNIWVPSKGMMNWEDSTYIPSEGITIRKCILIRGRRNNLATNGCLGMNVDDCDFIEAGGDTIGPAFGIDLEGFAENSIKYDHPYEINITNCRFKRNGKGALTSTLQGKFMLLIT-SPMMAQLWFSTDSTISNNTITNETGvDKPYGIDSIRKSSSETGNRTIITGNQIRGFATGICARGVGVIVSQNYLEDISSVGINPYLSEDVMVANNTI-NSDCLHVWVRNSVDVKVGNNKGKGAENYYGIKVEDSSDV-VVNDNKHVAKGGIQVARSTNVRIKDNDLTLIGNGNGISWDKISQVKLVKsNWISCAVAAAISGYADAYSTIISYNILEDCKYLIAIYLNGGAHHMLKGNDIMFRRGANGGYGVQLVNTTQARLISNDVRTMDGCTLHASYDSTGSTYTKYAYNTY-----------------
+>A0A0A0PLR7
+-------------------------------------------------------------------PEYGGGIQFPSNIEVIFHKEAVFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMnVSKFRKTHEWGYGVHIRGCRNILVEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTERGRRNNIATDGCLGLLIDDCDIVEAGGDTIGPQLGIDLEGFAEDGIKYGHPYEINITNNRFRENGRGSLNINVSAKVHATNNFSDDVFSYGYSSDVSICNNKIINESGKvRKYGIDSIRKSSTETGNRAIITGNHIIGFEIGICARGLGVKIANNYLKDISSIGIYPYLAEEVSVSDN-IIDSNCLHVWVRESKDVKISDNKTKGAANHFAYRVEASSDV-LISDSKSQSKGGIQVIRSRKVILKDNDLSLTGADYGIQWDKQSEVEVLNNTVRDAAMIAIAGNSELYPSVIKGNNIKDCTYLVGLYVNGGSNHILWDNDISFrgTGTTNGGYGVQLVGTENVWLMNNKVRTSNGRLLSSAYESRNSKKTMYINNALQAG--------------
+>A0A0A0PUI4
+-------------------------------------------------------------------PEYGGGIQFPSNIEVIFHKEAVFKVEPNSSTGYACFNLENVDNVILRGGCVVGERFEHDYDMnVSKFRKTHEWGYGVHIRGCRNILVEDMHISDCTGDCIWVPAHGMMNWGDTVYIPSESITIRKCRTERGRRNNIATDGCLGLLIDDCDIVEAGGDTIGPQLGIDLEGFAEDGIKYGHPYEINITNNRFRENGRGSLNINVSAKVHATNNFSDDVFSYGYSSDVSICNNKIINESGKvRKYGIDSIRKSSTETGNRAIITGNHIIGFEIGICARGLGVKIANNYLKDISSIGIYPYLAEEVSVSDN-IIDSNCLHVWVRESKDVKISDNKTKGAANHFAYRVEASSDV-LISDSKSQSKGGIQVIRSRKVILKDNDLSLTGADYGIQWDKQSEVEVLNNTVRDAAMIAIAGNSELYPSVIKGNNIKDCTYLVGLYVNGGSNHILWDNDISFrgTGTTNGGYGVQLVGTENVWLMNNKVRTSNGRLLSSAYESRNSKKTMYINNALQAG--------------
+>A0A5P8PIG3
+---------YPVNLEEWGINKDFQEPEATTEAFNKAFTYAKNMGYFEVWVPPGNYLIDGVNESNIYATENGGGIHLHSNTHYKLNPESVFKINANNAQGYSVFYIGLAYNVTLEGGQLIGDRHEHDYSTVTQNRNTHEFGFGVNVHGSERVNIVNVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDVIGPQLGIDFEGYAENGIKYAHPYNLQLKNSRFRDNGRGCFTAHAVGKAIISENFFDDRVSYGFGTDISIVDNHIINDGEVRDLAIDSIQPPSYDNANRVKISGNKIKGFKKGMTIRGKEIDVTDNDLNNITETGIHVYLAEEITVNENRV-NSDCVPLNIQISKKVNVSDNTFKGGAEKYGVIVSgEVEDISFKDNHI-EAGGGIDAGSAKNVRIlSKNEIFVKGKLNALRNNAGSTVKVNGLNIYDPAAYPMeldgsAGALDIKNV-----SIYGCKAFIAINIKNGRRHKIKNNDIVFERETNGGYGVYLSGTERTKLMDNDVSTSNDFAIGAPFHTEGSMYSTIMHNYYDSG--------------
+>M4ZRV1
+---------YPLNLEEWGINKEFQEPEETTAAFNKAFEYAKSMGYFKILVPPGNFLIDGVNESNIYATENGGGIHLHSNTHYLLHPESVFKINANDAQGYSVFYIGLAYNVTLEGGQLIGDRHEHDYSTSTQNRNTHEFGFGVNVHGSERVNIINVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDTIGPQLGIDFEGYAENGVKYAHPYNLQVKDSRFKNNGRGCFTAHAVGKAIISKNFFDDRVSYGFGTDISIVDNHIINDGEVRPLAIDSIQPPSYDNANRVKISGNTIKGFKKGMTIRGKEVDVIDNKLNNITDTGIHVYLAEEITVNENRV-NSDCVPLNIQISEKVNVSDNTFKGGSEKYGVVISgEVEDISFKDNHI-EAGGGIDAGVAKNVRIlSKNEIFVKGKLNALRNNAGSTVKVNGLNIYDPAayPMELDGSAGALDIR--NVSIYGCKAFIAINIKNGKSHKIKNNDIIFNRGSNGGYGIHLSGTEKAKLTNNYVSTSDGFAIGSPYHTENSTYSTVMNNYYDSG--------------
+>A0A5P8PHR1
+---------YPVNLEEWGINKDFQEPEATTEAFNRAFTYAKNMGYFEVWVPPGNYLIDGVNESNVYATENGGGIHLHSNTHYKLNPESVFKINANDAQGYSVFYVGLAYNVTLEGGQLIGDRYEHNYSTVAPNRSTHEFGFGVNVHGSERVNIINVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDIIGPQLGIDFEGYAENGIKYAHPYNLQLKNSRFKDNGRGCFTAHATGKAIISENFFDDRVSYGFGTDISIVDNHIINDGEVRPLAIDSIQPPSYDNANRVKVAGNKIKGFKKGMTIRGKEVDVTDNDLNDVTETGIHVYLAEEITVNENRV-NSDCVPLNIQISKKVNVSDNTFKGGAEKYGVVISgEVEDISFKDNHI-EAGGGIDAGSAKNVRIlSKNEIFVKGKLNALRNNPGSTMKVNGLNIYDPAAYPMELDGSAGSLDIKNVSIYGCKAFIAINIKNGRRHKIKNNDIIFERETNGGYGIYLSGTERTKLMDNDVSTSNDFAIGSPFHTENAMYSTIMHNYYDSG--------------
+>A0A5P8PI75
+---------YSVNLEEWGINKDFQEPEATTEAFNKAFTYAKNMGYFEVWVPPGNYLIDGVNESNIYATENGGGIHLHSNTHYKLNPESVFKINANNAQGYSVFYIGLAYNVTLEGGQLIGDRHEHDYSTVTQNRNTHEFGFGVNVHGSERVNIVNVRSRDMTGDNILITNKGNMNYPGQTYIPSKNVTVENCYLETARRNNLSAVGCDGVLIDNCDFIAAGGDVIGPQLGIDFEGYAENGIKYAHPYNLQLKNSRFRDNGRGCFTAHAVGKAIISENFFDDRVSYGFGTDISIVDNHIINDGEIRALAIDSIQPPSYDNANRVKISGNKIKGFKKGMTIRGKEIDVTDNDLNNITETGIHVYLAEEITVNENRV-NSDCVPLNIQISKKVNVSDNTFKGGAEKYGVIVSgEVEDISFKDNHI-EAGGGIDAGSAKNVRIlSKNEIFVKGKLNALRNNPGSTVKVNGLNIYDPAAYPMeldgsAGALDIKNV-----SIYGCKAFIAMNIKNGRRHKIKNNDIVFERETNGGYGVYLSGTERTKLTDNDVSTSNDFAIGAPFHTEGSMYSTIMYNYYDSG--------------
diff --git a/test/unit/test_af2_feature_finalizer.py b/test/unit/test_af2_feature_finalizer.py
new file mode 100644
index 00000000..c45dd02c
--- /dev/null
+++ b/test/unit/test_af2_feature_finalizer.py
@@ -0,0 +1,486 @@
+"""AlphaFold 2 features from a local MMseqs2 bundle, through AlphaFold 2's own code.
+
+Every property asserted here is one that fails silently when wrong: a feature key
+another source lacks crashes multimer pairing only when that chain happens to come
+first; a template profile built from the merged alignment returns different hits
+without complaint; a species lost from a header simply pairs nothing.
+"""
+
+from __future__ import annotations
+
+import json
+from pathlib import Path
+import pickle
+
+import numpy as np
+import pytest
+
+pipeline = pytest.importorskip(
+ "alphafold.data.pipeline", reason="needs the AlphaFold 2 data pipeline"
+)
+from alphafold.common import residue_constants # noqa: E402
+
+from alphapulldown.af2_feature_finalizer import ( # noqa: E402
+ Af2FeatureFinalizationSettings,
+ Af2FeatureFinalizer,
+)
+from alphapulldown.feature_batch import PROTEIN, RNA, FeatureRequest # noqa: E402
+
+
+FIXTURES = Path(__file__).resolve().parents[1] / "test_data" / "features" / "af2_features"
+
+# Measured on a natively generated (jackhmmer) pickle from the shared feature
+# store. Local features must carry every one of these, or a multimer mixing the
+# two sources fails on the missing key.
+NATIVE_KEYS = {
+ "aatype", "between_segment_residues", "deletion_matrix_int",
+ "deletion_matrix_int_all_seq", "domain_name", "msa", "msa_all_seq",
+ "msa_species_identifiers", "msa_species_identifiers_all_seq", "num_alignments",
+ "residue_index", "seq_length", "sequence", "template_aatype",
+ "template_all_atom_masks", "template_all_atom_positions",
+ "template_confidence_scores", "template_domain_names", "template_release_date",
+ "template_sequence", "template_sum_probs",
+}
+ACCESSION_KEYS = {
+ "msa_uniprot_accession_identifiers",
+ "msa_uniprot_accession_identifiers_all_seq",
+}
+
+QUERY = "MKTAYIAKQRQISFVKSHFSRQ"
+
+
+class RecordingSearcher:
+ """Stands in for hmmsearch and remembers the profile it was handed."""
+
+ input_format = "sto"
+ output_format = "sto"
+
+ def __init__(self):
+ self.queries: list[str] = []
+
+ def query(self, text):
+ self.queries.append(text)
+ return "RAW_HITS"
+
+ def get_template_hits(self, output_string, input_sequence):
+ return []
+
+
+class NoHitFeaturizer:
+ """What AlphaFold 2's HmmsearchHitFeaturizer returns when nothing is found."""
+
+ def get_templates(self, query_sequence, hits):
+ num_res = len(query_sequence)
+
+ class Result:
+ features = {
+ "template_aatype": np.zeros(
+ (1, num_res, len(residue_constants.restypes_with_x_and_gap)),
+ np.float32,
+ ),
+ "template_all_atom_masks": np.zeros(
+ (1, num_res, residue_constants.atom_type_num), np.float32
+ ),
+ "template_all_atom_positions": np.zeros(
+ (1, num_res, residue_constants.atom_type_num, 3), np.float32
+ ),
+ "template_domain_names": np.array([b""], dtype=object),
+ "template_sequence": np.array([b""], dtype=object),
+ "template_sum_probs": np.array([0], dtype=np.float32),
+ }
+
+ return Result()
+
+
+def _a3m(records):
+ return "".join(f">{description}\n{sequence}\n" for description, sequence in records)
+
+
+def _write_bundle(msa_dir: Path, name: str, sequence: str, *, uniref90, mgnify,
+ small_bfd, paired) -> None:
+ msa_dir.mkdir(parents=True, exist_ok=True)
+ unpaired = [("query", sequence), *uniref90, *mgnify, *small_bfd]
+ paired_records = [("query", sequence), *paired]
+ (msa_dir / f"{name}_mmseqs_msa.json").write_text(
+ json.dumps(
+ {
+ "schemaVersion": 3,
+ "name": name,
+ "sequence": sequence,
+ "unpairedMsa": _a3m(unpaired),
+ "pairedMsa": _a3m(paired_records),
+ "unpairedDepth": len(unpaired),
+ "pairedDepth": len(paired_records),
+ "unpairedDatabaseRows": [
+ {"name": "uniref90", "rows": len(uniref90)},
+ {"name": "mgnify", "rows": len(mgnify)},
+ {"name": "small_bfd", "rows": len(small_bfd)},
+ ],
+ "provenance": {"schema_version": 5, "fixture": name},
+ }
+ ),
+ encoding="utf-8",
+ )
+
+
+def _mutate(sequence: str, position: int, residue: str) -> str:
+ return sequence[:position] + residue + sequence[position + 1 :]
+
+
+def _insert(sequence: str, position: int, insertion: str) -> str:
+ return sequence[:position] + insertion + sequence[position:]
+
+
+def _standard_bundle(msa_dir: Path, name: str = "alpha", sequence: str = QUERY):
+ """Rows named by database, one uniref90 hit with an insertion, UniProt species."""
+ _write_bundle(
+ msa_dir,
+ name,
+ sequence,
+ uniref90=[
+ ("UniRef90_U1 uniref hit", _mutate(sequence, 3, "W")),
+ # A three-residue insertion before position 5 -- lowercase, as stitched.
+ # It also carries its own substitution: a row whose match columns equal
+ # the query's is a duplicate of it, and AlphaFold 2 drops it as one.
+ ("UniRef90_U2 inserted", _insert(_mutate(sequence, 11, "W"), 5, "ggg")),
+ ],
+ mgnify=[("MGYP000000001", _mutate(sequence, 7, "W"))],
+ small_bfd=[("BFD_B1", _mutate(sequence, 9, "W"))],
+ paired=[
+ ("sp|P12345|KIN1_HUMAN kinase OS=Homo sapiens OX=9606", _mutate(sequence, 2, "V")),
+ ("tr|Q67890|Q67890_MOUSE kinase OS=Mus musculus OX=10090", _mutate(sequence, 4, "V")),
+ ],
+ )
+
+
+def _finalizer(tmp_path: Path, **overrides):
+ settings = dict(
+ output_dir=tmp_path / "features",
+ msa_input_dir=tmp_path / "msas",
+ max_template_date="2050-01-01",
+ template_seqres_database_id="pdb-seqres-2050",
+ template_mmcif_database_id="mmcif-2050",
+ )
+ settings.update(overrides)
+ searcher = RecordingSearcher()
+ finalizer = Af2FeatureFinalizer(
+ settings=Af2FeatureFinalizationSettings(**settings),
+ template_searcher=searcher,
+ template_featurizer=NoHitFeaturizer(),
+ )
+ return finalizer, searcher
+
+
+def _features(tmp_path: Path, name: str = "alpha") -> dict:
+ with open(tmp_path / "features" / f"{name}.pkl", "rb") as handle:
+ return pickle.load(handle).feature_dict
+
+
+def _generate(tmp_path, name="alpha", sequence=QUERY, **overrides):
+ finalizer, searcher = _finalizer(tmp_path, **overrides)
+ result = finalizer.generate([FeatureRequest(name=name, sequence=sequence)])
+ assert result.failures == (), result.failures
+ return result, searcher
+
+
+def test_features_carry_the_native_key_set_plus_accession_identifiers(tmp_path):
+ _standard_bundle(tmp_path / "msas")
+ _generate(tmp_path)
+ assert set(_features(tmp_path)) == NATIVE_KEYS | ACCESSION_KEYS
+
+
+def test_insertions_reach_the_deletion_matrix(tmp_path):
+ """The point of recovering insertions: native features have them, and until
+ now every local MMseqs2 alignment produced an all-zero deletion matrix."""
+ _standard_bundle(tmp_path / "msas")
+ _generate(tmp_path)
+ features = _features(tmp_path)
+
+ deletions = features["deletion_matrix_int"]
+ assert deletions.shape == features["msa"].shape
+ assert deletions.sum() == 3, "three inserted residues, counted once"
+ # Recorded against the residue that follows the insertion.
+ row = int(np.nonzero(deletions.sum(axis=1))[0][0])
+ assert deletions[row, 5] == 3
+
+
+def test_rows_follow_alphafold2s_merge_order(tmp_path):
+ _standard_bundle(tmp_path / "msas")
+ _generate(tmp_path)
+ msa = _features(tmp_path)["msa"]
+ mutated_at = [int(np.nonzero(row != msa[0])[0][0]) if (row != msa[0]).any() else None
+ for row in msa]
+ # query, uniref90 (3, 11), then BFD (9) before MGnify (7), as AlphaFold 2 merges.
+ assert mutated_at == [None, 3, 11, 9, 7]
+
+
+def test_templates_are_searched_from_uniref90_alone(tmp_path):
+ _standard_bundle(tmp_path / "msas")
+ _, searcher = _generate(tmp_path)
+ [profile] = searcher.queries
+ assert "UniRef90_U1" in profile
+ assert "MGYP000000001" not in profile and "BFD_B1" not in profile
+
+
+def test_pairing_features_come_from_uniprot_with_parsed_species(tmp_path):
+ _standard_bundle(tmp_path / "msas")
+ _generate(tmp_path)
+ features = _features(tmp_path)
+
+ assert list(features["msa_species_identifiers_all_seq"]) == [b"", b"HUMAN", b"MOUSE"]
+ assert list(features["msa_uniprot_accession_identifiers_all_seq"]) == [
+ b"", b"P12345", b"Q67890",
+ ]
+ # Not a copy of the unpaired features, which is what the remote path uses.
+ assert features["msa_all_seq"].shape[0] == 3
+ assert features["msa"].shape[0] == 5
+
+
+def test_no_network_is_ever_touched(tmp_path, monkeypatch):
+ """A batch of thousands of chains must not start calling UniProt REST."""
+ import urllib.request
+
+ def refuse(*args, **kwargs):
+ raise AssertionError("the local AlphaFold 2 path queried the network")
+
+ monkeypatch.setattr(urllib.request, "urlopen", refuse)
+ _write_bundle(
+ tmp_path / "msas",
+ "alpha",
+ QUERY,
+ uniref90=[("UniRef90_A0A0A0A0A0 no species in this header", _mutate(QUERY, 3, "W"))],
+ mgnify=[],
+ small_bfd=[],
+ # A bare accession: exactly the case the shared helper would look up.
+ paired=[("P12345", _mutate(QUERY, 2, "V"))],
+ )
+ _generate(tmp_path)
+
+
+def test_published_pickle_is_a_monomeric_object_and_is_reused(tmp_path):
+ from alphapulldown.objects import MonomericObject
+
+ _standard_bundle(tmp_path / "msas")
+ first, searcher = _generate(tmp_path)
+ assert [artifact.name for artifact in first.written] == ["alpha"]
+ with open(tmp_path / "features" / "alpha.pkl", "rb") as handle:
+ monomer = pickle.load(handle)
+ assert isinstance(monomer, MonomericObject)
+ assert monomer.sequence == QUERY and monomer.skip_msa is False
+ assert list((tmp_path / "features").glob("alpha_feature_metadata_*.json"))
+
+ again, searcher_again = _generate(tmp_path)
+ assert [artifact.name for artifact in again.reused] == ["alpha"]
+ assert searcher_again.queries == [], "a reused artifact must not search again"
+
+
+def test_changed_template_settings_are_not_served_from_cache(tmp_path):
+ _standard_bundle(tmp_path / "msas")
+ _generate(tmp_path)
+ moved, _ = _generate(tmp_path, max_template_date="2020-01-01")
+ assert [artifact.name for artifact in moved.written] == ["alpha"]
+
+
+def test_hhsearch_cache_tracks_pdb70_without_rebuilding_the_msa(tmp_path):
+ _standard_bundle(tmp_path / "msas")
+ bundle = tmp_path / "msas" / "alpha_mmseqs_msa.json"
+ original_bundle = bundle.read_bytes()
+ options = dict(template_searcher="hhsearch", template_pdb70_database_id="pdb70-v1")
+ first, _ = _generate(tmp_path, **options)
+ assert [artifact.name for artifact in first.written] == ["alpha"]
+ again, searcher = _generate(tmp_path, **options)
+ assert [artifact.name for artifact in again.reused] == ["alpha"]
+ assert searcher.queries == []
+
+ changed, searcher = _generate(
+ tmp_path, **{**options, "template_pdb70_database_id": "pdb70-v2"}
+ )
+ assert [artifact.name for artifact in changed.written] == ["alpha"]
+ assert len(searcher.queries) == 1
+ assert bundle.read_bytes() == original_bundle
+ with open(tmp_path / "features" / "alpha.pkl", "rb") as handle:
+ provenance = pickle.load(handle).local_msa_provenance["af2_templates"]
+ assert provenance["pdb70_database_id"] == "pdb70-v2"
+ assert "pdb_seqres_database_id" not in provenance
+
+
+@pytest.mark.parametrize("searcher,unused_id", [
+ ("hmmsearch", "template_pdb70_database_id"),
+ ("hhsearch", "template_seqres_database_id"),
+])
+def test_unused_template_database_does_not_invalidate_features(tmp_path, searcher, unused_id):
+ _standard_bundle(tmp_path / "msas")
+ options = dict(template_searcher=searcher, template_pdb70_database_id="pdb70-v1")
+ _generate(tmp_path, **options)
+ options[unused_id] = "unused-database-v2"
+ result, recording = _generate(tmp_path, **options)
+ assert [artifact.name for artifact in result.reused] == ["alpha"]
+ assert recording.queries == []
+
+
+@pytest.mark.parametrize("missing", [None, "", " "])
+def test_hhsearch_requires_a_pdb70_identity(tmp_path, missing):
+ finalizer, _ = _finalizer(
+ tmp_path, template_searcher="hhsearch", template_pdb70_database_id=missing
+ )
+ with pytest.raises(ValueError, match="template_pdb70_database_id"):
+ finalizer.generate([])
+
+
+def test_hhsearch_does_not_require_an_unused_seqres_identity(tmp_path):
+ _standard_bundle(tmp_path / "msas")
+ result, _ = _generate(
+ tmp_path, template_searcher="hhsearch", template_seqres_database_id=None,
+ template_pdb70_database_id="pdb70-v1",
+ )
+ assert [artifact.name for artifact in result.written] == ["alpha"]
+
+
+def test_compressed_output_round_trips(tmp_path):
+ import lzma
+
+ _standard_bundle(tmp_path / "msas")
+ _generate(tmp_path, compress=True)
+ with lzma.open(tmp_path / "features" / "alpha.pkl.xz", "rb") as handle:
+ assert pickle.load(handle).sequence == QUERY
+
+
+def test_rna_is_refused_by_name(tmp_path):
+ finalizer, _ = _finalizer(tmp_path)
+ result = finalizer.generate(
+ [FeatureRequest(name="trna", sequence="ACGU", molecule_type=RNA)]
+ )
+ assert [failure.name for failure in result.failures] == ["trna"]
+ assert "protein" in result.failures[0].error
+
+
+def _local_monomer(tmp_path: Path, name: str, sequence: str):
+ _standard_bundle(tmp_path / "msas", name, sequence)
+ _generate(tmp_path, name=name, sequence=sequence)
+ with open(tmp_path / "features" / f"{name}.pkl", "rb") as handle:
+ return pickle.load(handle)
+
+
+def _native_like_monomer():
+ """An older pickle with 21 keys and no accession identifiers at all."""
+ with open(FIXTURES / "protein" / "P61626.pkl", "rb") as handle:
+ return pickle.load(handle)
+
+
+@pytest.mark.parametrize("local_first", (True, False))
+def test_local_chain_pairs_with_a_pickle_from_another_source(tmp_path, local_first):
+ """AlphaFold 2 pairing takes its key set from the FIRST chain and indexes every
+ other chain with it, so an extra key crashes only in one order (issue #619).
+ Both orders, through the real pairing code."""
+ from alphapulldown.objects import MultimericObject
+
+ local = _local_monomer(tmp_path, "alpha", QUERY)
+ native = _native_like_monomer()
+ chains = [local, native] if local_first else [native, local]
+
+ merged = MultimericObject(interactors=chains, pair_msa=True).feature_dict
+
+ total = len(local.sequence) + len(native.sequence)
+ assert merged["aatype"].shape == (total,)
+ assert merged["msa"].shape[1] == total
+
+
+def test_two_local_chains_pair_the_species_they_share(tmp_path):
+ """Which rows pair, not merely that pairing ran: HUMAN and MOUSE occur in both
+ chains' UniProt alignments, so those rows line up in the paired block."""
+ from alphapulldown.objects import MultimericObject
+
+ first = _local_monomer(tmp_path, "alpha", QUERY)
+ second_sequence = _mutate(QUERY, 12, "L")
+ second = _local_monomer(tmp_path, "beta", second_sequence)
+
+ merged = MultimericObject(interactors=[first, second], pair_msa=True).feature_dict
+
+ # The merged multimer MSA is in the model's residue order, not HHblits'.
+ to_id = residue_constants.restype_order_with_x
+ human_row = [to_id[r] for r in _mutate(QUERY, 2, "V") + _mutate(second_sequence, 2, "V")]
+ mouse_row = [to_id[r] for r in _mutate(QUERY, 4, "V") + _mutate(second_sequence, 4, "V")]
+ # An unpaired row carries one chain's residues and gaps across the other, so
+ # both chains' hits can only sit on one row if pairing put them there.
+ rows = [list(row) for row in merged["msa"]]
+ assert human_row in rows, "the HUMAN hits of both chains must share one row"
+ assert mouse_row in rows, "the MOUSE hits of both chains must share one row"
+ # And a hit present in only one chain's alignment is never paired.
+ unpaired_hit_a = [to_id[r] for r in _mutate(QUERY, 3, "W") + second_sequence]
+ assert unpaired_hit_a not in rows
+
+
+def test_a_homomer_of_a_local_chain_assembles(tmp_path):
+ """Two copies of one chain: AF2 merges identical entities into a dense MSA
+ instead of pairing them, a different code path from the heteromer."""
+ from alphapulldown.objects import MultimericObject
+
+ first = _local_monomer(tmp_path, "alpha", QUERY)
+ with open(tmp_path / "features" / "alpha.pkl", "rb") as handle:
+ second = pickle.load(handle)
+
+ merged = MultimericObject(interactors=[first, second], pair_msa=True).feature_dict
+
+ assert merged["aatype"].shape == (2 * len(QUERY),)
+ assert merged["msa"].shape[1] == 2 * len(QUERY)
+
+
+def test_local_chains_assemble_without_pairing(tmp_path):
+ """pair_msa=False skips species pairing and block-diagonalises the MSAs."""
+ from alphapulldown.objects import MultimericObject
+
+ first = _local_monomer(tmp_path, "alpha", QUERY)
+ second = _local_monomer(tmp_path, "beta", _mutate(QUERY, 12, "L"))
+
+ merged = MultimericObject(interactors=[first, second], pair_msa=False).feature_dict
+
+ to_id = residue_constants.restype_order_with_x
+ # Unpaired, a HUMAN hit shares a row with no other chain's residues.
+ human_row = [to_id[r] for r in _mutate(QUERY, 2, "V") + _mutate(QUERY, 2, "V")]
+ assert human_row not in [list(row) for row in merged["msa"]]
+ assert merged["msa"].shape[1] == 2 * len(QUERY)
+
+
+def test_a_chopped_local_chain_pairs_with_a_full_one(tmp_path):
+ """Issue #619's shape: a full chain first, a chopped chain second. The chopped
+ chain must keep the accession identifiers, row-aligned, or pairing crashes."""
+ from alphapulldown.objects import ChoppedObject, MultimericObject
+
+ full = _local_monomer(tmp_path, "alpha", QUERY)
+ source = _local_monomer(tmp_path, "beta", _mutate(QUERY, 12, "L"))
+ region = (3, 15)
+ chopped = ChoppedObject(
+ source.description, source.sequence, source.feature_dict, [region]
+ )
+ chopped.prepare_final_sliced_feature_dict()
+ assert (
+ chopped.feature_dict["msa_uniprot_accession_identifiers_all_seq"].shape[0]
+ == chopped.feature_dict["msa_all_seq"].shape[0]
+ )
+
+ merged = MultimericObject(interactors=[full, chopped], pair_msa=True).feature_dict
+
+ region_length = region[1] - region[0] + 1
+ assert merged["aatype"].shape == (len(QUERY) + region_length,)
+
+
+@pytest.mark.parametrize("damage", ("spans_do_not_add_up", "no_spans"))
+def test_a_bundle_unusable_to_alphafold2_is_deleted_so_it_is_rebuilt(tmp_path, damage):
+ """Rejecting such a bundle and leaving it in place fails the same finalization on
+ every retry: its Shard completion still validates, so no repair is scheduled.
+ Deleting it is what gets it rebuilt."""
+ _standard_bundle(tmp_path / "msas")
+ bundle_path = tmp_path / "msas" / "alpha_mmseqs_msa.json"
+ bundle = json.loads(bundle_path.read_text())
+ if damage == "no_spans":
+ del bundle["unpairedDatabaseRows"]
+ else:
+ bundle["unpairedDatabaseRows"][0]["rows"] += 1
+ bundle_path.write_text(json.dumps(bundle))
+
+ finalizer, _ = _finalizer(tmp_path)
+ result = finalizer.generate([FeatureRequest(name="alpha", sequence=QUERY)])
+
+ assert [failure.name for failure in result.failures] == ["alpha"]
+ assert "row spans" in result.failures[0].error
+ assert not bundle_path.exists()
diff --git a/test/unit/test_af2_msa_inputs.py b/test/unit/test_af2_msa_inputs.py
new file mode 100644
index 00000000..0e4d9454
--- /dev/null
+++ b/test/unit/test_af2_msa_inputs.py
@@ -0,0 +1,100 @@
+"""Cutting an MSA bundle into the alignments AlphaFold 2 builds features from.
+
+No AlphaFold import: this is string slicing, and it has to be right in every
+environment -- a wrong cut does not fail, it hands AlphaFold 2 another database's
+rows or a template profile built from the wrong alignment.
+"""
+
+from __future__ import annotations
+
+import pytest
+
+from alphapulldown import af2_feature_finalizer
+from alphapulldown.af2_feature_finalizer import af2_msa_inputs
+from alphapulldown.feature_batch import SearchedMsas
+
+
+QUERY = "MKTAYI"
+
+
+def _msas(uniref90=2, mgnify=2, small_bfd=2, paired=3) -> SearchedMsas:
+ """Distinguishable rows: U/M/B for each database, P for UniProt."""
+
+ def rows(prefix, count):
+ return [(f"{prefix}{index}", f"{prefix}KTAYI") for index in range(count)]
+
+ unpaired = [("query", QUERY), *rows("U", uniref90), *rows("M", mgnify)]
+ unpaired += rows("B", small_bfd)
+ return SearchedMsas(
+ unpaired="".join(f">{d}\n{s}\n" for d, s in unpaired),
+ paired="".join(
+ f">{d}\n{s}\n" for d, s in [("query", QUERY), *rows("P", paired)]
+ ),
+ unpaired_rows=(
+ ("uniref90", uniref90),
+ ("mgnify", mgnify),
+ ("small_bfd", small_bfd),
+ ),
+ )
+
+
+def _names(a3m: str) -> list[str]:
+ return [line[1:] for line in a3m.splitlines() if line.startswith(">")]
+
+
+def test_main_alignment_follows_alphafold2_merge_order():
+ # The bundle merges uniref90, mgnify, small_bfd; AlphaFold 2 merges uniref90,
+ # BFD, MGnify (pipeline.py:265). Order decides what its MSA sampling sees first.
+ inputs = af2_msa_inputs(_msas())
+ assert _names(inputs.main_a3m) == ["query", "U0", "U1", "B0", "B1", "M0", "M1"]
+
+
+def test_templates_come_from_uniref90_alone():
+ inputs = af2_msa_inputs(_msas())
+ assert _names(inputs.template_a3m) == ["query", "U0", "U1"]
+
+
+def test_caps_count_the_query_row_as_alphafold2_does(monkeypatch):
+ # jackhmmer's max_sto_sequences stops at that many sequence NAMES, query first,
+ # so a cap of 3 means the query plus two hits.
+ monkeypatch.setattr(
+ af2_feature_finalizer, "AF2_MAX_SEQUENCES", {"uniref90": 3, "mgnify": 2}
+ )
+ inputs = af2_msa_inputs(_msas(uniref90=5, mgnify=5, small_bfd=5))
+
+ assert _names(inputs.template_a3m) == ["query", "U0", "U1"]
+ assert _names(inputs.main_a3m) == [
+ "query", "U0", "U1", "B0", "B1", "B2", "B3", "B4", "M0",
+ ]
+
+
+def test_paired_alignment_is_uniprot_truncated_like_all_seq_msa_features(monkeypatch):
+ monkeypatch.setattr(af2_feature_finalizer, "PAIRED_MAX_SEQUENCES", 3)
+ inputs = af2_msa_inputs(_msas(paired=10))
+ assert _names(inputs.paired_a3m) == ["query", "P0", "P1"]
+
+
+def test_real_defaults_are_alphafold2s():
+ assert af2_feature_finalizer.AF2_MAX_SEQUENCES == {
+ "uniref90": 10_000,
+ "mgnify": 501,
+ }
+ assert af2_feature_finalizer.PAIRED_MAX_SEQUENCES == 50_000
+
+
+def test_a_bundle_without_row_spans_is_refused():
+ """Without spans there is no uniref90 to build templates from -- and no way to
+ fake one, since the merged alignment has lost the boundaries."""
+ msas = _msas()
+ spanless = SearchedMsas(unpaired=msas.unpaired, paired=msas.paired)
+ with pytest.raises(ValueError):
+ af2_msa_inputs(spanless)
+
+
+def test_a_bundle_with_no_paired_alignment_is_refused():
+ msas = _msas()
+ unpaired_only = SearchedMsas(
+ unpaired=msas.unpaired, paired="", unpaired_rows=msas.unpaired_rows
+ )
+ with pytest.raises(ValueError, match="paired"):
+ af2_msa_inputs(unpaired_only)
diff --git a/test/unit/test_af2_template_stack.py b/test/unit/test_af2_template_stack.py
new file mode 100644
index 00000000..ca241fff
--- /dev/null
+++ b/test/unit/test_af2_template_stack.py
@@ -0,0 +1,170 @@
+"""Exercise template construction and finalization through their caller interfaces."""
+from unittest.mock import Mock, patch
+
+import pytest
+
+from alphapulldown.af2_feature_finalizer import build_af2_template_stack
+from alphapulldown.scripts import create_individual_features as legacy
+from alphapulldown.scripts import finalize_batch_features as cli
+from alphapulldown.scripts._mmseqs2_cli import (
+ require_template_flags,
+ required_template_flag_names,
+)
+from absl.testing import flagsaver
+from types import SimpleNamespace
+
+
+@pytest.fixture
+def finalization_flags(tmp_flags, tmp_path):
+ with flagsaver.flagsaver():
+ tmp_flags.msa_input_dir = str(tmp_path / "msas")
+ tmp_flags.template_seqres_database_id = "seqres-v1"
+ tmp_flags.template_pdb70_database_id = "pdb70-v1"
+ tmp_flags.template_mmcif_database_id = "mmcif-v1"
+ tmp_flags.keep_msas = False
+ (tmp_path / "a.fasta").write_text(">query\nACDE\n")
+ yield tmp_flags
+
+
+@pytest.mark.parametrize("hhsearch", [False, True])
+def test_template_stack_resolves_defaults_without_mutating_flags(finalization_flags, hhsearch):
+ finalization_flags.use_hhsearch = hhsearch
+ before = finalization_flags.flag_values_dict()
+ settings = legacy.af2_template_stack_settings()
+ assert settings.searcher_name == ("hhsearch" if hhsearch else "hmmsearch")
+ assert settings.pdb70_database_path == "/db/pdb70/pdb70"
+ assert settings.pdb_seqres_database_path == "/db/pdb_seqres/pdb_seqres.txt"
+ assert settings.template_mmcif_dir == "/db/pdb_mmcif/mmcif_files"
+ assert finalization_flags.flag_values_dict() == before
+
+
+def test_template_stack_honors_overrides_without_a_data_root(finalization_flags):
+ finalization_flags.data_dir = None
+ finalization_flags.pdb70_database_path = "/custom/pdb70"
+ settings = legacy.af2_template_stack_settings()
+ assert settings.pdb70_database_path == "/custom/pdb70"
+ assert settings.pdb_seqres_database_path is None
+
+
+@pytest.mark.parametrize("hhsearch", [False, True])
+def test_template_factory_builds_the_selected_search_and_featurizer(finalization_flags, hhsearch):
+ finalization_flags.use_hhsearch = hhsearch
+ settings = legacy.af2_template_stack_settings()
+ with patch("alphafold.data.tools.hhsearch.HHSearch") as hh, \
+ patch("alphafold.data.tools.hmmsearch.Hmmsearch") as hmm, \
+ patch("alphafold.data.templates.HhsearchHitFeaturizer") as hh_features, \
+ patch("alphafold.data.templates.HmmsearchHitFeaturizer") as hmm_features:
+ searcher, featurizer = build_af2_template_stack(settings)
+ selected_search, selected_features = (hh, hh_features) if hhsearch else (hmm, hmm_features)
+ assert searcher is selected_search.return_value
+ assert featurizer is selected_features.return_value
+ if hhsearch:
+ hh.assert_called_once_with(binary_path="hhsearch", databases=[settings.pdb70_database_path])
+ hmm.assert_not_called()
+ else:
+ hmm.assert_called_once_with(binary_path="hmmsearch", hmmbuild_binary_path="hmmbuild",
+ database_path=settings.pdb_seqres_database_path)
+ hh.assert_not_called()
+ assert selected_features.call_args.kwargs == dict(
+ mmcif_dir=settings.template_mmcif_dir, max_template_date=settings.max_template_date,
+ max_hits=20, kalign_binary_path="kalign", release_dates_path=None,
+ obsolete_pdbs_path=settings.obsolete_pdbs_path,
+ )
+
+
+@pytest.mark.parametrize("hhsearch", [False, True])
+def test_metadata_contains_only_the_template_resources_used(finalization_flags, hhsearch):
+ finalization_flags.use_hhsearch = hhsearch
+ stack = legacy.af2_template_stack_settings()
+ with patch.object(cli.save_meta_data, "get_meta_dict", return_value={"sentinel": 1}) as metadata:
+ assert cli.af2_template_metadata(stack) == {"sentinel": 1}
+ supplied = metadata.call_args.args[0]
+ assert supplied["kalign_binary_path"] == "kalign"
+ assert supplied["template_mmcif_dir"] == stack.template_mmcif_dir
+ if hhsearch:
+ assert supplied["pdb70_database_path"] == stack.pdb70_database_path
+ assert "pdb_seqres_database_path" not in supplied
+ assert "hmmsearch_binary_path" not in supplied
+ else:
+ assert supplied["pdb_seqres_database_path"] == stack.pdb_seqres_database_path
+ assert "pdb70_database_path" not in supplied
+ assert "hhsearch_binary_path" not in supplied
+ assert "jackhmmer_binary_path" not in supplied
+ assert "hhblits_binary_path" not in supplied
+
+
+@pytest.mark.parametrize("backend,hhsearch,required", [
+ ("alphafold2", True, "template_pdb70_database_id"),
+ ("alphafold2", False, "template_seqres_database_id"),
+ ("alphafold3", True, "template_seqres_database_id"),
+])
+def test_template_identity_validation_selects_the_database(finalization_flags, backend, hhsearch, required):
+ finalization_flags.data_pipeline = backend
+ finalization_flags.use_hhsearch = hhsearch
+ assert required_template_flag_names(data_pipeline=backend, use_hhsearch=hhsearch) == (
+ required, "template_mmcif_database_id"
+ )
+ require_template_flags(finalization_flags)
+ setattr(finalization_flags, required, " ")
+ with pytest.raises(ValueError, match=required):
+ require_template_flags(finalization_flags)
+
+
+@pytest.mark.parametrize("hhsearch", [False, True])
+def test_af2_finalization_cli_passes_selected_identity_and_requests(finalization_flags, hhsearch):
+ finalization_flags.use_hhsearch = hhsearch
+ if hhsearch:
+ finalization_flags.template_seqres_database_id = None
+ result = SimpleNamespace(written=(), reused=(), failures=())
+ with patch.object(cli, "build_af2_template_stack", return_value=("searcher", "featurizer")), \
+ patch.object(cli, "af2_template_metadata", return_value={"software": {}}), \
+ patch.object(cli, "Af2FeatureFinalizer") as factory:
+ factory.return_value.generate.return_value = result
+ cli.main([])
+ settings = factory.call_args.kwargs["settings"]
+ assert settings.template_searcher == ("hhsearch" if hhsearch else "hmmsearch")
+ assert settings.template_pdb70_database_id == "pdb70-v1"
+ assert settings.template_mmcif_database_id == "mmcif-v1"
+ assert factory.call_args.kwargs["template_searcher"] == "searcher"
+ [request] = factory.return_value.generate.call_args.args[0]
+ assert (request.name, request.sequence) == ("query", "ACDE")
+
+
+def test_af3_finalization_cli_keeps_its_seqres_identity(finalization_flags):
+ finalization_flags.data_pipeline = "alphafold3"
+ result = SimpleNamespace(written=(), reused=(), failures=())
+ with patch.object(legacy, "create_pipeline_af3", return_value="af3-pipeline"), \
+ patch.object(legacy, "get_af3_feature_metadata", return_value={}) as metadata, \
+ patch.object(cli, "FeatureFinalizer") as factory:
+ factory.return_value.generate.return_value = result
+ cli.main([])
+ settings = factory.call_args.kwargs["settings"]
+ assert settings.template_seqres_database_id == "seqres-v1"
+ assert settings.template_mmcif_database_id == "mmcif-v1"
+ assert factory.call_args.kwargs["af3_pipeline"] == "af3-pipeline"
+ assert metadata.call_args.kwargs["skip_msa"] is True
+ [request] = factory.return_value.generate.call_args.args[0]
+ assert request.sequence == "ACDE"
+
+
+def test_cli_rejects_missing_pdb70_identity_before_loading_tools(finalization_flags):
+ finalization_flags.use_hhsearch = True
+ finalization_flags.template_pdb70_database_id = None
+ with patch.object(cli, "build_af2_template_stack") as factory:
+ with pytest.raises(ValueError, match="template_pdb70_database_id"):
+ cli.main([])
+ factory.assert_not_called()
+
+
+def test_cli_reports_per_sequence_failures(finalization_flags):
+ result = SimpleNamespace(written=(), reused=(), failures=(SimpleNamespace(name="query", error="damaged bundle"),))
+ with patch.object(cli, "_finalize_alphafold2", return_value=result):
+ with pytest.raises(RuntimeError, match=r"query \(damaged bundle\)"):
+ cli.main([])
+
+
+@pytest.mark.parametrize("flag", ["skip_msa", "keep_msas", "use_mmseqs2", "path_to_mmt"])
+def test_cli_rejects_incompatible_feature_modes(finalization_flags, flag):
+ setattr(finalization_flags, flag, "/tmp/mmt" if flag == "path_to_mmt" else True)
+ with pytest.raises(ValueError, match="cannot be combined"):
+ cli.main([])
diff --git a/test/unit/test_feature_batch.py b/test/unit/test_feature_batch.py
index 76338c50..e1f6bb6f 100644
--- a/test/unit/test_feature_batch.py
+++ b/test/unit/test_feature_batch.py
@@ -119,6 +119,10 @@ def result_to_msa(
del query_db, result_db
msa_db.write_text(database.name, encoding="utf-8")
+ # The fixture's hits carry no insertions and single-token headers, so both
+ # result2msa passes format them identically and the stitch is a no-op.
+ result_to_a3m = result_to_msa
+
def unpack_msa(self, query_db: Path, msa_db: Path, output_dir: Path) -> None:
output_dir.mkdir(parents=True, exist_ok=True)
database_name = msa_db.read_text(encoding="utf-8")
@@ -176,18 +180,52 @@ def search(
super().search(query_db, database, result_db, work_dir, settings)
-class FullHeaderAlignedFastaMmseqs(FakeMmseqsProcess):
+class TwoPassMmseqs(FakeMmseqsProcess):
+ """Formats one hit the way the real pinned MMseqs2 build does, in both passes.
+
+ The hit carries a one-residue insertion (X, between C and D). Mode 2 keeps the
+ full UniProt header and drops the insertion; mode 5 keeps the insertion and cuts
+ the header to the accession. Measured, not assumed: see msa_formats.
+
+ This replaces a fixture that fed mode 2 a query row WITH a gap column, on the
+ belief that mode 2 carries insertions that way. The real build never emits one
+ -- every row comes back at query width -- so that path never ran on real data.
+ """
+
+ def result_to_msa(self, query_db, database, result_db, msa_db) -> None:
+ del query_db, database, result_db
+ msa_db.write_text("headers", encoding="utf-8")
+
+ def result_to_a3m(self, query_db, database, result_db, msa_db) -> None:
+ del query_db, database, result_db
+ msa_db.write_text("insertions", encoding="utf-8")
+
def unpack_msa(self, query_db: Path, msa_db: Path, output_dir: Path) -> None:
- del msa_db
output_dir.mkdir(parents=True, exist_ok=True)
+ insertions = msa_db.read_text(encoding="utf-8") == "insertions"
for index, (query_id, sequence) in enumerate(self._queries[query_db]):
assert sequence == "ACDE"
+ hit = (
+ ">P12345\nACxDE\n"
+ if insertions
+ else ">sp|P12345|KINASE_HUMAN Protein kinase OS=Homo sapiens "
+ "OX=9606 GN=KIN1\nACDE\n"
+ )
+ (output_dir / f"{index}.fasta").write_text(
+ f">{query_id}\nACDE\n{hit}", encoding="utf-8"
+ )
+
+
+class ReorderedPassesMmseqs(TwoPassMmseqs):
+ """The two passes disagree about which hit is which, as a future MMseqs2 might."""
+
+ def unpack_msa(self, query_db: Path, msa_db: Path, output_dir: Path) -> None:
+ output_dir.mkdir(parents=True, exist_ok=True)
+ insertions = msa_db.read_text(encoding="utf-8") == "insertions"
+ for index, (query_id, _) in enumerate(self._queries[query_db]):
+ first, second = ("ACDE", "ACDQ") if insertions else ("ACDQ", "ACDE")
(output_dir / f"{index}.fasta").write_text(
- f">{query_id} query description\n"
- "AC-DE\n"
- ">sp|P12345|KINASE_HUMAN Protein kinase OS=Homo sapiens "
- "OX=9606 GN=KIN1\n"
- "ACXDE\n",
+ f">{query_id}\nACDE\n>sp|P1|A_HUMAN\n{first}\n>sp|P2|B_YEAST\n{second}\n",
encoding="utf-8",
)
@@ -247,6 +285,31 @@ def test_subprocess_adapter_requests_aligned_fasta_output(tmp_path):
assert command[command.index("--msa-format-mode") + 1] == "2"
+def test_subprocess_adapter_requests_a3m_for_the_insertion_pass(tmp_path):
+ # Mode 5 is the only result2msa format that keeps insertions.
+ binary = tmp_path / "mmseqs"
+ arguments = Path(f"{binary}.arguments")
+ binary.write_text(
+ '#!/bin/sh\nprintf \'%s\\n\' "$@" > "${0}.arguments"\n',
+ encoding="utf-8",
+ )
+ binary.chmod(0o755)
+ database = DatabaseSpec(
+ name="uniprot", path=tmp_path / "uniprot", identifier="fixture"
+ )
+
+ SubprocessMmseqsProcess(binary).result_to_a3m(
+ tmp_path / "query",
+ database,
+ tmp_path / "result",
+ tmp_path / "msa",
+ )
+
+ command = arguments.read_text(encoding="utf-8").splitlines()
+ assert command[0] == "result2msa"
+ assert command[command.index("--msa-format-mode") + 1] == "5"
+
+
def test_gpu_search_does_not_pass_ignored_sensitivity_option(tmp_path):
binary = tmp_path / "mmseqs"
arguments = Path(f"{binary}.arguments")
@@ -570,10 +633,15 @@ def test_downstream_af3_failure_preserves_a_valid_msa_bundle(tmp_path):
assert bundle.exists()
-def test_aligned_fasta_conversion_preserves_taxon_header_and_insertions(tmp_path):
+def test_stitched_alignment_keeps_taxon_header_and_insertions(tmp_path):
+ """Both halves reach AlphaFold 3 -- which neither result2msa pass gives alone.
+
+ The header decides species pairing; the insertion is what mode 2 used to
+ discard for 86% of real uniprot hits.
+ """
batch = FeatureBatch(
settings=_settings(tmp_path),
- mmseqs_process=FullHeaderAlignedFastaMmseqs(),
+ mmseqs_process=TwoPassMmseqs(),
af3_pipeline=PassthroughAf3Pipeline(),
)
@@ -591,6 +659,78 @@ def test_aligned_fasta_conversion_preserves_taxon_header_and_insertions(tmp_path
assert "\nACxDE\n" in paired_msa
+def test_passes_that_disagree_fail_the_request_rather_than_mislabel_hits(tmp_path):
+ """A positional join that silently went wrong would label P1's sequence as P2's.
+
+ On the paired database that means pairing chains by the wrong species: a wrong
+ answer that looks entirely plausible. It has to fail, loudly and per request,
+ and publish nothing.
+ """
+ settings = _settings(tmp_path)
+ batch = FeatureBatch(
+ settings=settings,
+ mmseqs_process=ReorderedPassesMmseqs(),
+ af3_pipeline=PassthroughAf3Pipeline(),
+ )
+
+ result = batch.generate([FeatureRequest(name="alpha", sequence="ACDE")])
+
+ assert [failure.name for failure in result.failures] == ["alpha"]
+ assert "no longer in the same order" in result.failures[0].error
+ assert not (settings.msa_output_dir / "alpha_mmseqs_msa.json").exists()
+ assert not (tmp_path / "features" / "alpha_af3_input.json").exists()
+
+
+def test_bundle_records_how_many_rows_each_database_contributed(tmp_path):
+ """AlphaFold 2 searches templates from uniref90 alone and caps each database
+ separately, so the merged alignment is only usable if its boundaries survive."""
+ settings = _settings(tmp_path)
+ FeatureBatch(
+ settings=settings,
+ mmseqs_process=FakeMmseqsProcess(),
+ af3_pipeline=PassthroughAf3Pipeline(),
+ ).generate([FeatureRequest(name="alpha", sequence="ACDEFG")])
+
+ bundle = json.loads(
+ (settings.msa_output_dir / "alpha_mmseqs_msa.json").read_text(encoding="utf-8")
+ )
+ assert bundle["schemaVersion"] == 3
+ spans = bundle["unpairedDatabaseRows"]
+ assert [span["name"] for span in spans] == ["uniref90", "mgnify", "small_bfd"]
+ # The fixture gives each database one distinct hit, and the spans must account
+ # for every row of the merged alignment except the query.
+ assert [span["rows"] for span in spans] == [1, 1, 1]
+ assert sum(span["rows"] for span in spans) == bundle["unpairedDepth"] - 1
+
+ # And each span really is that database's rows, in order.
+ rows = bundle["unpairedMsa"].splitlines()[3::2]
+ assert [row[0] for row in rows] == ["V", "R", "N"]
+
+
+def test_bundle_whose_row_spans_do_not_add_up_is_searched_again(tmp_path):
+ """A wrong count does not fail when sliced -- it hands AlphaFold 2 another
+ database's rows as uniref90. So a bundle that does not add up is not reused."""
+ settings = _settings(tmp_path)
+ request = FeatureRequest(name="alpha", sequence="ACDEFG")
+ FeatureBatch(
+ settings=settings,
+ mmseqs_process=FakeMmseqsProcess(),
+ af3_pipeline=PassthroughAf3Pipeline(),
+ ).generate([request])
+ bundle_path = settings.msa_output_dir / "alpha_mmseqs_msa.json"
+ bundle = json.loads(bundle_path.read_text(encoding="utf-8"))
+ bundle["unpairedDatabaseRows"][0]["rows"] += 1
+ bundle_path.write_text(json.dumps(bundle), encoding="utf-8")
+
+ searching = FakeMmseqsProcess()
+ result = MsaBatch(
+ settings=_msa_settings(settings), mmseqs_process=searching
+ ).generate([request])
+
+ assert [artifact.name for artifact in result.written] == ["alpha"]
+ assert result.reused == ()
+
+
def test_matching_artifact_is_reused_without_external_search(tmp_path):
settings = _settings(tmp_path)
pipeline = _native_pipeline_with_no_template_hits(tmp_path)
diff --git a/test/unit/test_feature_batch_rna.py b/test/unit/test_feature_batch_rna.py
index 5202e432..37feb58e 100644
--- a/test/unit/test_feature_batch_rna.py
+++ b/test/unit/test_feature_batch_rna.py
@@ -29,6 +29,7 @@
FeatureRequest,
MsaBatch,
MsaBatchSettings,
+ SearchedMsas,
SubprocessMmseqsProcess,
feature_requests_from_fastas,
)
@@ -137,6 +138,10 @@ def result_to_msa(self, query_db, database, result_db, msa_db) -> None:
del query_db, result_db
msa_db.write_text(database.name, encoding="utf-8")
+ # The fixture's hits carry no insertions and single-token headers, so both
+ # result2msa passes format them identically and the stitch is a no-op.
+ result_to_a3m = result_to_msa
+
def unpack_msa(self, query_db: Path, msa_db: Path, output_dir: Path) -> None:
output_dir.mkdir(parents=True, exist_ok=True)
database_name = msa_db.read_text(encoding="utf-8")
@@ -245,17 +250,28 @@ def test_rna_databases_are_the_three_alphafold3_searches_in_its_merge_order():
# --------------------------------------------------------------------------------
-def test_protein_cache_signature_is_exactly_what_it_was_before_rna_existed(tmp_path):
- """Pinned literally: changing it silently invalidates every cached protein MSA."""
+def test_protein_cache_signature_is_pinned(tmp_path):
+ """Pinned literally: changing it silently invalidates every cached protein MSA.
+
+ It last moved, deliberately, when insertions were recovered (schema 4 -> 5,
+ and ``msa_format`` added). Bundles written before that came from mode 2 alone
+ and carry no insertions -- 86% of uniprot hits lost theirs on a real query --
+ so reusing them would have kept the defect. The only cache that existed at
+ the time was two bundles of e2e test data. Move it again only as deliberately.
+ """
batch = MsaBatch(
settings=_msa_settings(_settings(tmp_path)),
mmseqs_process=FakeMmseqsProcess(),
)
assert batch._cache_signature(PROTEIN) == {
- "schema_version": 4,
+ "schema_version": 5,
"mmseqs_identity": "mmseqs-fixture-1",
"search_mode": "gpu",
+ "msa_format": {
+ "headers": "result2msa mode 2",
+ "sequences": "result2msa mode 5",
+ },
"e_value": 1e-4,
"unpaired_databases": [
{
@@ -306,12 +322,12 @@ def test_a_protein_bundle_records_no_molecule_type_so_old_bundles_still_match(tm
)
protein = batch._msa_payload(
- FeatureRequest(name="alpha", sequence="ACDE"), ">query\nACDE\n", ">query\nACDE\n"
+ FeatureRequest(name="alpha", sequence="ACDE"),
+ SearchedMsas(unpaired=">query\nACDE\n", paired=">query\nACDE\n"),
)
rna = batch._msa_payload(
FeatureRequest(name="beta", sequence="ACGU", molecule_type=RNA),
- ">query\nACGU\n",
- "",
+ SearchedMsas(unpaired=">query\nACGU\n", paired=""),
)
assert "moleculeType" not in protein
@@ -323,6 +339,7 @@ def test_a_protein_bundle_records_no_molecule_type_so_old_bundles_still_match(tm
"pairedMsa",
"unpairedDepth",
"pairedDepth",
+ "unpairedDatabaseRows",
"provenance",
]
assert rna["moleculeType"] == RNA
@@ -763,7 +780,9 @@ def test_an_rna_query_reaches_mmseqs_spelled_as_dna(tmp_path, monkeypatch):
batch = MsaBatch(settings=settings, mmseqs_process=process)
monkeypatch.setattr(
- feature_batch_module, "_aligned_fasta_to_a3m", lambda fasta, query, kind: fasta
+ feature_batch_module,
+ "_stitched_to_a3m",
+ lambda records, query, kind: "".join(f">{d}\n{s}\n" for d, s in records),
)
batch._search_chunk(["ACGUUU"], RNA)
@@ -781,7 +800,9 @@ def test_a_protein_query_is_handed_to_mmseqs_unchanged(tmp_path, monkeypatch):
batch = MsaBatch(settings=settings, mmseqs_process=process)
monkeypatch.setattr(
- feature_batch_module, "_aligned_fasta_to_a3m", lambda fasta, query, kind: fasta
+ feature_batch_module,
+ "_stitched_to_a3m",
+ lambda records, query, kind: "".join(f">{d}\n{s}\n" for d, s in records),
)
batch._search_chunk(["ACDEFGU"], PROTEIN)
diff --git a/test/unit/test_light_import_invariant.py b/test/unit/test_light_import_invariant.py
index ce1181ea..c6bfd6df 100644
--- a/test/unit/test_light_import_invariant.py
+++ b/test/unit/test_light_import_invariant.py
@@ -54,3 +54,48 @@ def test_the_light_path_pulls_in_neither_alphafold_nor_jax(module):
"MMseqs2 search; importing JAX there preallocates GPU memory. Import it "
"inside the function that needs it instead."
)
+
+
+# Importing the module was never the hard part. Converting a search result used
+# `alphafold3.cpp.msa_conversion`, so the stage imported cleanly in the AlphaFold 2
+# image -- which installs AlphaPulldown without the `alphafold3` extra -- and then
+# died on the first result. Exercise the conversion itself, not just the import.
+RESULT_PROBE = """
+import importlib, sys
+feature_batch = importlib.import_module("alphapulldown.feature_batch")
+from alphapulldown.utils.msa_formats import stitch_headers_and_insertions
+headers = [
+ ("query_0", "MKTAYIAKQRQ"),
+ ("sp|P00001|EXACT_HUMAN exact OS=Homo sapiens OX=9606", "MKTAYIAKQRQ"),
+ ("tr|P00003|DELETE_YEAST deletion OS=Saccharomyces OX=4932", "MKT---AKQRQ"),
+]
+insertions = [
+ ("query_0", "MKTAYIAKQRQ"),
+ ("P00001", "MKTAYIAKQRQ"),
+ ("P00003", "MKT---AKwwQRQ"),
+]
+a3m = feature_batch._stitched_to_a3m(
+ stitch_headers_and_insertions(headers, insertions), "MKTAYIAKQRQ"
+)
+assert "sp|P00001|EXACT_HUMAN" in a3m, "full headers must survive conversion"
+assert "MKT---AKwwQRQ" in a3m, "deletions and insertions must survive conversion"
+leaked = sorted(
+ name for name in sys.modules
+ if any(name == f or name.startswith(f + ".") for f in {forbidden!r})
+)
+print(",".join(leaked))
+"""
+
+
+def test_converting_a_search_result_pulls_in_neither_alphafold_nor_jax():
+ completed = subprocess.run(
+ [sys.executable, "-c", RESULT_PROBE.format(forbidden=FORBIDDEN)],
+ capture_output=True,
+ text=True,
+ )
+ assert completed.returncode == 0, completed.stderr[-2000:]
+ leaked = [name for name in completed.stdout.strip().split(",") if name]
+ assert not leaked, (
+ f"converting a search result now imports {leaked}. The MSA stage has to "
+ "run in the AlphaFold 2 image, which has no AlphaFold 3 at all."
+ )
diff --git a/test/unit/test_mmseqs_process_options.py b/test/unit/test_mmseqs_process_options.py
new file mode 100644
index 00000000..1313ba43
--- /dev/null
+++ b/test/unit/test_mmseqs_process_options.py
@@ -0,0 +1,174 @@
+"""Process-level MMseqs2 options, and which of them may touch the cache identity.
+
+Deliberately free of any AlphaFold 3 import: the search stage runs in the
+AlphaFold 2 image too, and a module-level skip there would report success while
+silently testing nothing. The equivalent assertions in ``test_feature_batch.py``
+cannot run in that image because that module needs AlphaFold 3 for the finalizer.
+"""
+
+from __future__ import annotations
+
+import dataclasses
+from pathlib import Path
+
+import pytest
+
+from alphapulldown.feature_batch import (
+ DatabaseSpec,
+ MsaBatch,
+ MsaBatchSettings,
+ SubprocessMmseqsProcess,
+)
+
+
+PROTEIN_DATABASES = ("uniref90", "mgnify", "small_bfd")
+
+
+@pytest.fixture
+def recording_binary(tmp_path: Path) -> tuple[Path, Path]:
+ """A stand-in executable that records the arguments it was called with."""
+ binary = tmp_path / "mmseqs"
+ binary.write_text(
+ '#!/bin/sh\nprintf \'%s\\n\' "$@" > "${0}.arguments"\n', encoding="utf-8"
+ )
+ binary.chmod(0o755)
+ return binary, Path(f"{binary}.arguments")
+
+
+def _settings(tmp_path: Path) -> MsaBatchSettings:
+ return MsaBatchSettings(
+ output_dir=tmp_path / "out",
+ temp_dir=tmp_path / "tmp",
+ unpaired_databases=tuple(
+ DatabaseSpec(name=name, path=tmp_path / name, identifier=f"{name}-fixture")
+ for name in PROTEIN_DATABASES
+ ),
+ paired_database=DatabaseSpec(
+ name="uniprot", path=tmp_path / "uniprot", identifier="uniprot-fixture"
+ ),
+ max_sequences_per_batch=8,
+ max_residues_per_batch=10_000,
+ threads=4,
+ )
+
+
+def _database(tmp_path: Path) -> DatabaseSpec:
+ return DatabaseSpec(
+ name="uniref90", path=tmp_path / "uniref90", identifier="fixture"
+ )
+
+
+def test_db_load_mode_reaches_the_search(tmp_path: Path, recording_binary):
+ binary, arguments = recording_binary
+ SubprocessMmseqsProcess(binary, db_load_mode=2).search(
+ tmp_path / "query",
+ _database(tmp_path),
+ tmp_path / "result",
+ tmp_path / "work",
+ _settings(tmp_path),
+ )
+ command = arguments.read_text(encoding="utf-8").splitlines()
+ assert command[command.index("--db-load-mode") + 1] == "2"
+
+
+def test_db_load_mode_reaches_result_to_msa(tmp_path: Path, recording_binary):
+ # Both commands read the target database, so both must honour the setting;
+ # passing it only to the search would leave the peak memory it exists to
+ # lower untouched in the second half of the stage.
+ binary, arguments = recording_binary
+ SubprocessMmseqsProcess(binary, db_load_mode=2).result_to_msa(
+ tmp_path / "query",
+ _database(tmp_path),
+ tmp_path / "result",
+ tmp_path / "msa",
+ )
+ command = arguments.read_text(encoding="utf-8").splitlines()
+ assert command[command.index("--db-load-mode") + 1] == "2"
+
+
+@pytest.mark.parametrize("operation", ("search", "result_to_msa"))
+def test_the_option_is_absent_when_unset(
+ tmp_path: Path, recording_binary, operation: str
+):
+ """Unset must mean "say nothing", so MMseqs2 keeps choosing for itself."""
+ binary, arguments = recording_binary
+ process = SubprocessMmseqsProcess(binary)
+ if operation == "search":
+ process.search(
+ tmp_path / "query",
+ _database(tmp_path),
+ tmp_path / "result",
+ tmp_path / "work",
+ _settings(tmp_path),
+ )
+ else:
+ process.result_to_msa(
+ tmp_path / "query",
+ _database(tmp_path),
+ tmp_path / "result",
+ tmp_path / "msa",
+ )
+ assert "--db-load-mode" not in arguments.read_text().splitlines()
+
+
+def test_db_load_mode_stays_out_of_the_cache_signature(tmp_path: Path):
+ """It changes memory behaviour, never the alignment.
+
+ If it reached the signature, turning it on to survive a tight allocation
+ would discard every alignment already computed -- a re-search costing hours
+ per shard to produce byte-identical output. Asserted on two real adapters
+ that differ in exactly this one setting.
+ """
+ binary = tmp_path / "mmseqs"
+ binary.write_text("#!/bin/sh\necho mmseqs-fixture-version\n", encoding="utf-8")
+ binary.chmod(0o755)
+ settings = _settings(tmp_path)
+
+ plain = MsaBatch(
+ settings=settings, mmseqs_process=SubprocessMmseqsProcess(binary)
+ )
+ mapped = MsaBatch(
+ settings=settings,
+ mmseqs_process=SubprocessMmseqsProcess(binary, db_load_mode=2),
+ )
+ assert plain._cache_signature() == mapped._cache_signature()
+
+ # The comparison above is only meaningful if a setting that DOES change the
+ # alignment moves the signature. GPU and CPU search are such a setting.
+ on_cpu = MsaBatch(
+ settings=settings,
+ mmseqs_process=SubprocessMmseqsProcess(binary, gpu=False),
+ )
+ assert plain._cache_signature() != on_cpu._cache_signature()
+
+
+def test_iterations_reach_protein_searches_but_never_nucleotide_ones(
+ tmp_path: Path, recording_binary
+):
+ """Iterative profile search is protein-only. Measured on the pinned build,
+ --num-iterations 3 on a nucleotide search exits 1, so raising the setting
+ used to fail every RNA shard."""
+ binary, arguments = recording_binary
+ settings = dataclasses.replace(_settings(tmp_path), num_iterations=3)
+ process = SubprocessMmseqsProcess(binary)
+
+ process.search(
+ tmp_path / "query",
+ _database(tmp_path),
+ tmp_path / "result",
+ tmp_path / "work",
+ settings,
+ )
+ protein = arguments.read_text(encoding="utf-8").splitlines()
+ assert protein[protein.index("--num-iterations") + 1] == "3"
+
+ rfam = DatabaseSpec(
+ name="rfam", path=tmp_path / "rfam", identifier="rfam-fixture",
+ molecule_type="rna",
+ )
+ process.search(
+ tmp_path / "query", rfam, tmp_path / "result", tmp_path / "work", settings
+ )
+ nucleotide = arguments.read_text(encoding="utf-8").splitlines()
+ assert "--num-iterations" not in nucleotide
+ assert nucleotide[nucleotide.index("--search-type") + 1] == "3"
diff --git a/test/unit/test_msa_bundle_validation.py b/test/unit/test_msa_bundle_validation.py
new file mode 100644
index 00000000..f5799e2a
--- /dev/null
+++ b/test/unit/test_msa_bundle_validation.py
@@ -0,0 +1,121 @@
+"""Validate persisted alignment data before finalization can trust it."""
+
+import json
+
+import pytest
+
+from alphapulldown.feature_batch import (
+ FeatureRequest,
+ RNA,
+ RNA_DATABASE_NAMES,
+ read_msa_bundle,
+)
+
+
+@pytest.fixture
+def bundle(tmp_path):
+ payload = {
+ "sequence": "ACDE",
+ "provenance": {"fixture": "bundle-validation"},
+ "unpairedMsa": ">query\nACDE\n>hit\nACDF\n",
+ "pairedMsa": ">query\nACDE\n",
+ "unpairedDatabaseRows": [
+ {"name": "uniref90", "rows": 1},
+ {"name": "mgnify", "rows": 0},
+ {"name": "small_bfd", "rows": 0},
+ ],
+ }
+ return tmp_path / "alpha_mmseqs_msa.json", payload
+
+
+@pytest.mark.parametrize(
+ "damage", ("missing_role", "duplicate_role", "unknown_role", "empty_paired", "empty_unpaired")
+)
+def test_unusable_alignment_data_is_deleted_before_finalization(bundle, damage):
+ path, payload = bundle
+ if damage == "missing_role":
+ payload["unpairedDatabaseRows"].pop()
+ elif damage == "duplicate_role":
+ # Keep every required role and the correct total, but duplicate UniRef90.
+ # A decoder keyed only by name would silently replace its nonempty span.
+ payload["unpairedDatabaseRows"].append({"name": "uniref90", "rows": 0})
+ elif damage == "unknown_role":
+ payload["unpairedDatabaseRows"][-1]["name"] = "unknown"
+ elif damage == "empty_paired":
+ payload["pairedMsa"] = ""
+ else:
+ payload["unpairedMsa"] = ""
+ payload["unpairedDatabaseRows"][0]["rows"] = 0
+ path.write_text(json.dumps(payload))
+
+ with pytest.raises(ValueError):
+ read_msa_bundle(
+ path.parent, FeatureRequest("alpha", "ACDE"), require_row_spans=True
+ )
+
+ assert not path.exists(), "An unusable bundle must be removed so the shard repairs it"
+
+
+def test_valid_protein_bundle_keeps_its_query_only_pairing_alignment(bundle):
+ path, payload = bundle
+ path.write_text(json.dumps(payload))
+
+ result = read_msa_bundle(
+ path.parent, FeatureRequest("alpha", "ACDE"), require_row_spans=True
+ )
+
+ assert result == payload
+ assert path.exists()
+
+
+def test_rna_bundle_has_no_paired_alignment_and_uses_its_own_database_roles(bundle):
+ path, payload = bundle
+ payload.update(
+ sequence="ACGU", moleculeType=RNA,
+ unpairedMsa=">query\nACGU\n", pairedMsa="",
+ unpairedDatabaseRows=[{"name": name, "rows": 0} for name in RNA_DATABASE_NAMES],
+ )
+ path.write_text(json.dumps(payload))
+
+ result = read_msa_bundle(
+ path.parent, FeatureRequest("alpha", "ACGU", RNA), require_row_spans=True
+ )
+
+ assert result == payload
+ assert path.exists()
+
+
+def test_template_search_failure_preserves_a_valid_af2_msa_bundle(bundle):
+ pytest.importorskip("alphafold.data.pipeline", reason="needs AlphaFold 2")
+ from alphapulldown.af2_feature_finalizer import (
+ Af2FeatureFinalizationSettings,
+ Af2FeatureFinalizer,
+ )
+
+ class FailingTemplateSearcher:
+ input_format = "sto"
+ output_format = "sto"
+
+ def query(self, text):
+ raise RuntimeError("template database is temporarily unavailable")
+
+ path, payload = bundle
+ encoded = json.dumps(payload)
+ path.write_text(encoded)
+ finalizer = Af2FeatureFinalizer(
+ settings=Af2FeatureFinalizationSettings(
+ output_dir=path.parent / "features", msa_input_dir=path.parent,
+ max_template_date="2050-01-01", template_seqres_database_id="seqres-v1",
+ template_mmcif_database_id="mmcif-v1",
+ ),
+ template_searcher=FailingTemplateSearcher(),
+ template_featurizer=None,
+ )
+
+ result = finalizer.generate([FeatureRequest("alpha", "ACDE")])
+
+ assert not result.written
+ assert [(failure.name, failure.error) for failure in result.failures] == [
+ ("alpha", "template database is temporarily unavailable")
+ ]
+ assert path.read_text() == encoded
diff --git a/test/unit/test_msa_formats.py b/test/unit/test_msa_formats.py
new file mode 100644
index 00000000..4eb140f5
--- /dev/null
+++ b/test/unit/test_msa_formats.py
@@ -0,0 +1,171 @@
+"""Joining two MMseqs2 formats into one A3M with headers AND insertions."""
+
+from __future__ import annotations
+
+from pathlib import Path
+import re
+import subprocess
+import sys
+
+import pytest
+
+from alphapulldown.utils.msa_formats import (
+ StitchMismatch,
+ stitch_headers_and_insertions,
+ strip_insertions,
+)
+
+
+def test_conversion_does_not_import_alphafold():
+ """The whole point: this must work in the AlphaFold 2 image.
+
+ Checked in a subprocess, because the test session may already have imported
+ AlphaFold for other modules and would mask exactly what is being measured.
+ """
+ probe = (
+ "import sys;"
+ "from alphapulldown.utils.msa_formats import stitch_headers_and_insertions as f;"
+ "f([('q', 'MKTAYI')], [('q', 'MKTAYI')]);"
+ "print(','.join(n for n in sys.modules if n.startswith('alphafold')))"
+ )
+ completed = subprocess.run(
+ [sys.executable, "-c", probe], capture_output=True, text=True, check=True
+ )
+ assert completed.stdout.strip() == ""
+
+
+def test_strip_insertions_leaves_one_column_per_query_position():
+ # Lowercase residues are insertions; gaps and match residues are columns.
+ assert strip_insertions("MKTwwAY-I") == "MKTAY-I"
+
+
+def test_stitch_takes_headers_from_one_pass_and_insertions_from_the_other():
+ headers = [("query", "MKTAYI"), ("sp|P1|A_HUMAN full header", "MKTAYI")]
+ insertions = [("query", "MKTAYI"), ("P1", "MKTwwAYI")]
+ assert stitch_headers_and_insertions(headers, insertions) == [
+ ("query", "MKTAYI"),
+ ("sp|P1|A_HUMAN full header", "MKTwwAYI"),
+ ]
+
+
+def test_stitch_refuses_rows_that_disagree():
+ """A silent positional join here would pair a header with another hit's
+ sequence -- for the paired database, pairing chains by the wrong species."""
+ headers = [("query", "MKTAYI"), ("sp|P1|A_HUMAN", "MKTAYI")]
+ reordered = [("query", "MKTAYI"), ("P2", "MKTAYQ")]
+ with pytest.raises(StitchMismatch, match="no longer in the same order"):
+ stitch_headers_and_insertions(headers, reordered)
+
+
+def test_stitch_refuses_differing_row_counts():
+ with pytest.raises(StitchMismatch, match="different row counts"):
+ stitch_headers_and_insertions([("query", "MKT")], [])
+
+
+def _read_records(path: Path) -> list[tuple[str, str]]:
+ records, description, parts = [], None, []
+ for line in path.read_text(encoding="utf-8").splitlines():
+ if line.startswith(">"):
+ if description is not None:
+ records.append((description, "".join(parts)))
+ description, parts = line[1:], []
+ elif description is not None:
+ parts.append(line)
+ if description is not None:
+ records.append((description, "".join(parts)))
+ return records
+
+
+REAL_MODE2 = Path(__file__).parent / "data" / "small_bfd.mode2.txt"
+REAL_MODE5 = Path(__file__).parent / "data" / "small_bfd.mode5.txt"
+
+
+@pytest.mark.skipif(
+ not (REAL_MODE2.exists() and REAL_MODE5.exists()),
+ reason="real MMseqs2 output fixtures are not checked in",
+)
+def test_stitch_holds_on_real_mmseqs_output():
+ """The synthetic cases prove the logic; this proves the assumption.
+
+ Fixtures are the two passes over one real search of a 586-residue query
+ against small_bfd, produced by the pinned MMseqs2 build.
+
+ Note which database this is. How much a header loses in mode 5 depends on the
+ FASTA it was built from: small_bfd headers are a single token
+ (``A0A163VT74_9BACL``) and survive intact, so the stitch changes only the
+ sequences here. It is uniprot that loses the species --
+ ``sp|P83570|GWA_SEPOF …`` becomes a bare ``P83570`` -- and uniprot is exactly
+ where species decides chain pairing. The insertion half of the join is what
+ this fixture exercises; ``test_stitch_recovers_uniprot_species_headers``
+ covers the other half.
+ """
+ headers = _read_records(REAL_MODE2)
+ insertions = _read_records(REAL_MODE5)
+ stitched = stitch_headers_and_insertions(headers, insertions)
+
+ assert len(stitched) == len(headers) > 1
+ assert [description for description, _ in stitched] == [
+ description for description, _ in headers
+ ]
+ assert [sequence for _, sequence in stitched] == [
+ sequence for _, sequence in insertions
+ ]
+ # The point of the exercise: insertions the header pass discarded are back.
+ recovered = sum(
+ 1 for _, sequence in stitched for residue in sequence if residue.islower()
+ )
+ assert recovered > 0, "insertions must survive the stitch"
+ assert not any(
+ residue.islower() for _, sequence in headers for residue in sequence
+ ), "the header pass is expected to carry no insertions at all"
+
+
+UNIPROT_MODE2 = Path(__file__).parent / "data" / "uniprot.mode2.txt"
+UNIPROT_MODE5 = Path(__file__).parent / "data" / "uniprot.mode5.txt"
+
+
+@pytest.mark.skipif(
+ not (UNIPROT_MODE2.exists() and UNIPROT_MODE5.exists()),
+ reason="real uniprot MMseqs2 output fixtures are not checked in",
+)
+def test_stitch_recovers_uniprot_species_headers():
+ """The half that decides whether multimer pairing works at all.
+
+ AlphaFold 2 reads the species mnemonic out of ``sp|ACC|NAME_SPECIES``. Mode 5
+ reduces that to ``ACC``, so an alignment built from it alone would pair no
+ chains; the stitched alignment must carry the parseable form.
+ """
+ headers = _read_records(UNIPROT_MODE2)
+ insertions = _read_records(UNIPROT_MODE5)
+ stitched = stitch_headers_and_insertions(headers, insertions)
+
+ # Mirrors alphafold.data.msa_identifiers._UNIPROT_PATTERN, which is what
+ # actually decides whether a row can be paired. Reproduced rather than
+ # imported because this module must stay free of AlphaFold; the authoritative
+ # check against the real function belongs with the AF2 finalizer tests.
+ uniprot = re.compile(
+ r"^(?:tr|sp)\|[A-Za-z0-9]{6,10}(?:_\d)?\|[A-Za-z0-9]+_([A-Za-z0-9]{1,5})"
+ r"(?:_\d+)?$"
+ )
+
+ def species(records):
+ found = set()
+ for description, _ in records:
+ match = uniprot.match(description.split()[0])
+ if match:
+ found.add(match.group(1))
+ return found
+
+ stitched_species = species(stitched)
+ assert len(stitched_species) > 1, (
+ "the stitched alignment must yield species mnemonics; without them "
+ "AlphaFold 2 pairs no chains at all"
+ )
+ assert species(insertions) == set(), (
+ "the insertion pass is expected to yield none, which is why it is stitched"
+ )
+ assert species(headers) == stitched_species
+ assert (
+ sum(1 for _, sequence in stitched for residue in sequence if residue.islower())
+ > 0
+ )
diff --git a/test/unit/test_msa_quality.py b/test/unit/test_msa_quality.py
index d69551f3..4de6ef2b 100644
--- a/test/unit/test_msa_quality.py
+++ b/test/unit/test_msa_quality.py
@@ -66,3 +66,82 @@ def test_compare_directories_rejects_unpaired_artifact_sets(tmp_path):
with pytest.raises(ValueError, match="missing from candidate"):
compare_directories(reference, candidate)
+
+
+def _af2_pickle(path, sequence, msa_rows, *, deletions=None, species=(), templates=()):
+ """An AlphaFold 2 feature pickle, as far as the comparison reads one.
+
+ Pickles the lightweight stand-in, so this needs no AlphaFold import.
+ """
+ import pickle
+
+ import numpy as np
+
+ from alphapulldown.utils.af2_to_af3_msa import AF2_ID_TO_A3M
+ from alphapulldown.utils.lightweight_pickles import LightweightMonomericObject
+
+ msa = np.array([[AF2_ID_TO_A3M.index(r) for r in row] for row in msa_rows],
+ dtype=np.int32)
+ feature_dict = {
+ "msa": msa,
+ "deletion_matrix_int": (
+ np.asarray(deletions) if deletions is not None else np.zeros_like(msa)
+ ),
+ "msa_all_seq": msa[: 1 + len(species)],
+ "msa_species_identifiers_all_seq": np.array(
+ [b"", *[s.encode() for s in species]], dtype=object
+ ),
+ "template_domain_names": np.array(
+ [t.encode() for t in templates] or [b""], dtype=object
+ ),
+ }
+ monomer = LightweightMonomericObject(
+ description=path.stem, sequence=sequence, feature_dict=feature_dict
+ )
+ path.write_bytes(pickle.dumps(monomer))
+
+
+def test_af2_comparison_measures_what_each_pickle_gives_the_model(tmp_path):
+ from alphapulldown.scripts.compare_msa_backends import (
+ compare_af2_directories,
+ summarize_af2,
+ )
+
+ reference, candidate = tmp_path / "native", tmp_path / "local"
+ reference.mkdir()
+ candidate.mkdir()
+ _af2_pickle(reference / "alpha.pkl", "ACDEFG", ["ACDEFG", "ACDEFW", "ACDEWG"],
+ deletions=[[0] * 6, [0, 2, 0, 0, 0, 0], [0] * 6],
+ species=("HUMAN", "MOUSE"), templates=("1abc_A",))
+ _af2_pickle(candidate / "alpha.pkl", "ACDEFG", ["ACDEFG", "ACDEFW"],
+ species=("HUMAN",))
+
+ [row] = compare_af2_directories(reference, candidate)
+
+ assert row["reference"]["unpaired"]["depth"] == 3
+ assert row["candidate"]["unpaired"]["depth"] == 2
+ assert row["reference"]["rows_with_insertions"] == 1
+ assert row["candidate"]["rows_with_insertions"] == 0
+ assert row["reference"]["paired_species"] == 2
+ assert row["candidate"]["paired_species"] == 1
+ assert row["reference"]["template_count"] == 1
+ # AlphaFold 2's empty-template placeholder is not a template.
+ assert row["candidate"]["template_count"] == 0
+ assert summarize_af2([row])["mean_candidate_paired_species"] == 1
+
+
+def test_af2_comparison_refuses_unpaired_or_mismatched_sets(tmp_path):
+ from alphapulldown.scripts.compare_msa_backends import compare_af2_directories
+
+ reference, candidate = tmp_path / "native", tmp_path / "local"
+ reference.mkdir()
+ candidate.mkdir()
+ _af2_pickle(reference / "alpha.pkl", "ACDEFG", ["ACDEFG"])
+ _af2_pickle(candidate / "beta.pkl", "ACDEFG", ["ACDEFG"])
+ with pytest.raises(ValueError, match="differ"):
+ compare_af2_directories(reference, candidate)
+
+ (candidate / "beta.pkl").unlink()
+ _af2_pickle(candidate / "alpha.pkl", "ACDEFW", ["ACDEFW"])
+ with pytest.raises(ValueError, match="Sequence mismatch"):
+ compare_af2_directories(reference, candidate)
diff --git a/workflows/mmseqs2-gpu.md b/workflows/mmseqs2-gpu.md
index ff2547ce..7395bf0a 100644
--- a/workflows/mmseqs2-gpu.md
+++ b/workflows/mmseqs2-gpu.md
@@ -52,6 +52,11 @@ RNA databases from `--data_dir`. Final artifact provenance therefore also
includes `--max_template_date`, `--template_seqres_database_id`, and
`--template_mmcif_database_id`.
+AF2 finalization with `--use_hhsearch` requires `--template_pdb70_database_id`
+instead of the unused seqres identity. Update the selected immutable identity
+when its database is rebuilt, including rebuilds at the same path. Only features
+are invalidated; the search-stage MSA bundles remain reusable.
+
GPU database memory can be substantial. Prefer fast node-local storage and an
Ampere-or-newer GPU. A database larger than VRAM can stream from host RAM, but
requires enough host memory and runs below peak throughput.
@@ -70,9 +75,23 @@ knob and does not include one in cache provenance.
## MSA and template behavior
For each chunk, one query database is reused for UniRef90, MGnify, small BFD,
-and paired UniProt searches. Aligned FASTA is converted to A3M while retaining
-insertions and complete UniProt descriptions, including taxonomy metadata.
-Unpaired hits from all three databases are merged and deduplicated.
+and paired UniProt searches. Each search result is formatted twice, because no
+single `result2msa` format carries both things an alignment needs: mode 2 keeps
+complete UniProt descriptions, including the species AlphaFold pairs chains by,
+but drops every insertion; mode 5 keeps the insertions but cuts the header to
+the accession. The two are joined row by row, and the join is verified on every
+row rather than trusted. The second pass costs about 16 ms per hit.
+
+MSA bundles written before this (bundle schema 2, provenance schema 4) came
+from mode 2 alone and carry no insertions, so the deletion matrix AlphaFold
+derived from them was all zeros; against a real query, 81.7% of small BFD hits
+and 86.4% of UniProt hits had insertions that were lost. The provenance change
+means such bundles are never reused: they are searched again.
+
+Unpaired hits from all three databases are merged and deduplicated, and the
+bundle records how many rows each database contributed. AlphaFold 3 does not
+need that, but an AlphaFold 2 consumer does: it builds its template profile from
+UniRef90 alone and caps each database separately.
The finalizer passes that merged unpaired MSA to native AF3 with `templates`
unset. This matches AF3's own pipeline: it merges UniRef90, small-BFD, and MGnify