Prophages¶
Stage 07.phages looks for viral sequence in the finished genome — free phage contigs and
prophages integrated in the chromosome — and then grades what it found. It runs in all four
modes, and both callers read the same contigs_final.fasta, so nothing here branches on the
sequencing technology.
Two callers are wired in and exactly one of them runs, chosen by a single config key. CheckV v1.0.3 runs either way, because neither caller reports completeness or host contamination.
flowchart TD
F([contigs_final.fasta])
G[genomad_end_to_end<br/>opt-in]
V[viral_identification_virsorter2<br/>default]
F --> G
F --> V
GV([07.phages/genomad/sample/<br/>..._summary/contigs_final_virus.fna])
GP([..._plasmid_summary.tsv])
VV([07.phages/virsorter/sample/<br/>final-viral-combined.fa])
G --> GV
G --> GP
V --> VV
GP --> S06[stage 06, plasmid concordance]
Q[viral_quality<br/>CheckV]
GV --> Q
VV --> Q
Q --> QS([07.phages/checkv/sample/<br/>quality_summary.tsv])
The two callers sit behind mutually exclusive guards, so only one set of rules is ever
defined. The run prints which one it is at startup: Phage caller: virsorter2 (default).
Plasmid stage: Platon-only (geNomad off).
Terms used on this page
| HMM | hidden Markov model — a statistical profile of a gene or protein family |
| SOP | standard operating procedure |
Choosing the caller¶
| VirSorter2 2.2.4 | geNomad 1.12.0 | |
|---|---|---|
| Status | default | opt-in |
| Licence | GPLv2 | Berkeley Lab, academic / non-commercial use |
| Finds | viruses | viruses and plasmids, in one run |
| Database | ~10 GB | ~1.5 GB |
| Also changes | nothing else | switches on the Platon + geNomad plasmid concordance in stage 06 |
VirSorter2 is the default because the whole default path — VirSorter2, Platon, CheckV — was
chosen with their licences in view, and geNomad's did not fit.
Licensing records what each licensor published and where it was
read; read it before setting genomad.
Choosing geNomad also changes the plasmid stage, by design rather than as a side effect: one geNomad run produces both a virus FASTA and a plasmid summary, so opting in hands stage 06 a second, independent caller without a second run.
VirSorter2¶
Rules virsorter2_db (or virsorter2_db_local) and viral_identification_virsorter2.
VirSorter2 scores contigs against curated viral HMM groups. BacFlux uses the settings from the VirSorter2 SOP:
| Setting | Value | Why |
|---|---|---|
--include-groups |
dsDNAphage,NCLDV,RNA,ssDNA,lavidaviridae |
the five groups the SOP screens for |
--min-score |
0.5 |
deliberately loose, for sensitivity — CheckV downstream is what grades the result |
--keep-original-seq |
on | keeps the original sequence of circular and near-fully-viral contigs instead of VirSorter2's trimmed version, so CheckV sees the real contig |
| In | contigs_final.fasta + the VirSorter2 database |
| Out | 07.phages/virsorter/{sample}/ — key file final-viral-combined.fa |
| Next | CheckV |
The ~10 GB database is fetched once by virsorter setup. If you already hold a copy —
the directory that command produced, containing hmm/, group/, rbs/ and Done_all_setup —
point directories.vs2_db at it and nothing is downloaded. BacFlux then builds a symlink view
of it rather than reading it in place, because Snakemake wipes a directory() output before
re-running its rule, and that must never happen to a database someone else shares.
Why envs/virsorter.yaml lists so many packages
VirSorter2 is itself a Snakemake workflow, and left alone it builds a second conda
environment at run time and does its real work inside that. That nesting is what broke
every phage run before v2.0.0: an old transitive mamba against a modern conda, failing
with No module named 'conda._vendor.auxlib'.
BacFlux switches the nesting off — virsorter setup --skip-deps-install,
virsorter run --use-conda-off, and the environment's own bin put first on PATH — which
means every tool VirSorter2's internal rules call must already be in our environment. The
bioconda virsorter package does not bring them: with virsorter alone, screed, hmmer,
prodigal, last, pandas, scikit-learn, numpy, seaborn, imbalanced-learn and
ncbi-genome-download were all absent and the run died at the first internal rule on
No module named 'screed'. So envs/virsorter.yaml carries a copy of VirSorter2's own
internal dependency list, pins included — its classifier ships as a pickled scikit-learn
0.22.1 model, so the pins matter. If VirSorter2 is ever unpinned from 2.2.4, that list has
to be re-synced against the envs/vs2.yaml inside the package.
geNomad¶
Rules genomad_db (or genomad_db_local) and genomad_end_to_end, defined only when
phage.caller: genomad.
geNomad classifies each contig from its gene content against a marker-profile database, and
reports viruses and plasmids in the same run. BacFlux uses the default presets — neither
--conservative nor --relaxed — which is the combination CheckV is normally paired with,
and --cleanup to delete the intermediates.
| In | contigs_final.fasta + the geNomad database |
| Out | 07.phages/genomad/{sample}/contigs_final_summary/ — contigs_final_virus.fna and contigs_final_plasmid_summary.tsv |
| Next | CheckV (virus FASTA) and the plasmid concordance in stage 06 (plasmid summary) |
Get the database yourself if you opt in
genomad download-database is hard-coded to portal.nersc.gov — the same host whose
outages forced the CheckV database onto a Zenodo mirror — and it has no --url option, so
a mirror cannot be substituted the way links.checkv_link is. It fails as
URLError: [Errno 113] No route to host when that host is down.
BacFlux ships links.genomad_link pointing at the copy geNomad's own authors published on
Zenodo (record 14886553, database v1.9), with links.genomad_md5 beside it; a checksum
mismatch stops the run rather than extracting a truncated archive. Change one and you must
change the other. Better still, set directories.genomad_db to a copy you already hold —
the inner genomad_db/ directory, the one holding version.txt and genomad_db.dbtype,
not its parent.
A local geNomad database is checked at parse time, before any job starts, because both ways it can fail are slow and confusing to diagnose mid-run:
- Partly readable. On a shared copy it is easy for a few small files to end up mode 0640
while the large data files beside them are world-readable — seen here as 11 of 27 files,
including
version.txtand the whole integrase set.os.path.exists()is true for a file you may stat but not read, so BacFlux tests real read access on every file and names the offenders. - Too old for the installed geNomad. geNomad parses
genomad_marker_metadata.tsvby position from the end of each row, so a database with one fewer trailing column shifts every field and dies minutes in oninvalid literal for int()— a marker accession being read as a count. BacFlux checks for thePREVIOUS_MARKER_ACCESSIONcolumn instead of a version number, because that column's absence is the actual cause.
CheckV¶
Rule viral_quality, plus checkv_db or checkv_db_local.
CheckV estimates how complete each predicted viral sequence is, flags host sequence left on
the ends of proviruses, and trims it. The same checkv end_to_end command grades either
caller's output, so one rule serves both paths — the caller's directory is chosen at startup
and the rule itself never knows which one it got.
| In | whichever caller's virus FASTA, plus the CheckV database |
| Out | 07.phages/checkv/{sample}/ — key file quality_summary.tsv |
| Next | this is the end of the stage; the CheckV directory is what rule all asks for, and asking for it is what pulls in whichever caller ran |
quality_summary.tsv is the file to read: one row per predicted viral sequence, with
checkv_quality, completeness, contamination, viral and host gene counts, and CheckV's
own warnings. Under VirSorter2, treat a low-completeness, high-host-gene row as what the loose
0.5 cutoff was expected to produce — the caller is deliberately sensitive.
A genome with no phage does not fail
checkv end_to_end errors on an empty input, and a virus-free genome is a perfectly normal
result. So the rule tests the caller's FASTA first: if it holds no sequences, it writes a
header-only quality_summary.tsv and skips CheckV. An empty table means "nothing was
called", not "something went wrong" — the log says which.
The shipped default is checkv-db-v1.5, fetched from an unmodified Zenodo mirror
(links.checkv_link) with its .sha256 checked, or from CheckV's own downloader when that
link is cleared. Either way it lands in 07.phages/checkv_db/ and the rule finds the versioned
folder inside it at run time, so the two routes are interchangeable.
If you hold a copy already, set directories.checkv_db to the parent directory holding the
versioned folder. BacFlux symlinks the large files rather than copying them, but rebuilds the
DIAMOND index with this workflow's own DIAMOND: index formats are versioned, and an index
built by another site's DIAMOND makes CheckV fail deep into the completeness stage with
DIAMOND task failed. That rebuild costs about 950 MB against roughly 6.4 GB for a full copy.
What this stage does and does not feed¶
The prophage calls are a deliverable in their own right. A prophage is a mobile element, so
the mobilome module counts this stage as part of its subject — but not
as an input: no rule in stage 08 opens a file under 07.phages/. Stage 08 does consume the
plasmid stage, and opting in to geNomad changes what that stage hands it, because the
concordance table is built here.
What to check afterwards¶
07.phages/checkv/{sample}/quality_summary.tsv— the graded calls, or a header-only file when nothing was called.07.phages/virsorter/{sample}/final-viral-combined.faor07.phages/genomad/{sample}/contigs_final_summary/contigs_final_virus.fna— what the caller proposed before CheckV.logs/viral_quality_{sample}.log— CheckV's own output, or the "no viral sequences called" line.logs/virsorter2_db.log,logs/genomad_db.log,logs/checkv_db.log— the one-off database steps; the geNomad and CheckV logs record the checksum result. When you supplied the database yourself, the log is the_localvariant of the same name.