Notes
Negative-control enrichment filter
ViralUnity uses interpretable enrichment statistics to filter taxa that could represent contamination bleed-in from negative controls. The filter compares each sample’s metric (RPKM when --viral-genomes is configured, otherwise RPM) to the distribution observed across negative-control samples.
Decision tiers:
|
|
Gate |
|---|---|---|
0 |
|
No filter; |
1 |
|
|
≥ 2 |
|
|
≥ 2, SD = 0 |
|
Same as single-control gate |
All metrics are recorded in the summary at the .neg step (the negative-control table in the cumulative chain, e.g. *_RPKM.nr.bleed.neg.tsv) for full traceability: fold_enrichment, log10_ratio, z_score, control_mean, control_sd, control_median, control_max, neg_metric, neg_decision, neg_pass, plus the thresholds and pseudocount used.
Taxa absent from the negative-control rows are treated as having a zero background (control_mean = 0) — they pass the enrichment gate easily, which is the conservative choice. The lineage-aware Krona filter (filter_krona_by_pass_taxids.py) also treats NA neg_pass as keep, so increasing the number of controls can only make the filter stricter, never accidentally drop a taxon.
RPKM and genome length: when --viral-genomes points to a RefSeq FASTA (with a corresponding --viral-taxids genome2taxid mapping), ViralUnity builds a per-taxon genome-length table at all ranks (family, genus, species) using the median length across all accessions under each node. RPKM at higher ranks (genus, family) is an approximation based on this median.
Segmented viruses
ViralUnity natively supports the assembly of segmented viral genomes. Instead of running the pipeline multiple times, pass multiple segment references with --segmented-reference:
viralunity consensus illumina \
--sample-sheet samples.csv \
--config-file config_segmented.yml \
--output /path/to/output \
--segmented-reference S=/path/to/s_segment.fasta \
--segmented-reference L=/path/to/l_segment.fasta
When this argument is detected, the pipeline dispatches a specialised modular workflow that processes each segment independently in parallel. Results are organised under samples/{sample_name}/{segment_name}/.
Nanopore data
The metagenomics pipeline supports Nanopore data via viralunity meta nanopore. There is no fastp-based QC step; optional dehosting, MEGAHIT assembly, and Racon/Medaka polishing are available. Sample sheets have two columns (sample ID, path to one FASTQ/FASTA per sample).
Reference header sanitization
The nanopore consensus workflow automatically sanitizes reference FASTA headers before use. Special characters (/, \, |, ,, ~, and spaces) in sequence identifiers are replaced with underscores (_). This prevents issues with downstream tools such as clair3 that use the sequence ID to create output directories.
Dynamic reference assembly
When --run-reference-assembly is enabled, the metagenomics pipeline adds a post-classification step that automatically selects reference genomes and runs consensus assembly for each sample that meets the hit threshold.
How it works
Selection checkpoint — after taxonomic classification, a Snakemake checkpoint reads the taxa summary TSVs and selects candidate references. The
--methodand--sourceflags control which classification results are used (e.g.,kraken2onreads). Only samples with at least--reads-countreads (or--contigs-countcontigs) assigned to one of the--familiesare selected.Reference extraction — for each selected sample, a unique assembly key (
ref_key) is constructed from the matched family and the reference accession ({family}_{accession}). The corresponding genome is extracted from--viral-genomes. The selection strategy controls how the reference accession is chosen (see below).Consensus assembly — uses the same alignment + consensus rules as
viralunity consensus, with the dynamically-selected reference. Output goes toassembly/{ref_key}/.
Reference selection strategies
--reference-selection-strategy taxid (default)
For each sample that has classification hits to a target family, every taxid from the summary (Kraken2 or Diamond) is looked up in --viral-taxids (genome2taxid.tsv). The lookup is performed in two steps:
Exact match — the taxid value from the summary row is searched directly in
genome2taxid.tsv. If one or more accessions are found, all of them are used as reference targets.Species-level fallback — if the exact taxid is absent (e.g. the classifier assigned a strain or subspecies taxid that is below species in the NCBI taxonomy), the species-level ancestor is resolved via
--taxdumpand retried againstgenome2taxid.tsv.
--taxdump is used only to (a) validate that the matched taxid belongs to a target family and (b) build the reference key label — it is not used to normalise the rank of the lookup itself. A warning is emitted once per family if no accession could be found for that family in the sample.
When to use: when your classifier database and your --viral-genomes database were both built from the same RefSeq release. The taxid linkage is direct and requires no sequence comparison. Fast and deterministic.
Limitation: a taxid match does not guarantee the reference is the closest relative in the database — it only guarantees taxonomic identity. If you need the closest possible reference rather than any representative of the species, use similarity instead.
Required databases: --viral-genomes, --viral-taxids, and --taxdump (all produced by viralunity get-databases virus-genome / NCBI taxdump).
viralunity meta illumina \
--sample-sheet samples.csv \
--config-file config.yaml \
--output /path/to/output \
--kraken2-database /path/to/kraken2_db \
--krona-database /path/to/krona_taxonomy \
--taxdump /path/to/taxdump \
--run-reference-assembly \
--reference-selection-strategy taxid \
--method kraken2 \
--source reads \
--families Coronaviridae,Orthomyxoviridae \
--reads-count 100 \
--viral-genomes databases/virus_genomes/viral.genomes.fasta \
--viral-taxids databases/virus_genomes/genome2taxid.tsv \
--threads 4 --threads-total 8
--reference-selection-strategy similarity
De novo assembled contigs from each sample are BLASTed against --viral-genomes using blastn. For each contig, BLAST returns hits sorted by bitscore (best first). The first hit per contig that passes both --blast-qcov and --blast-pident thresholds is selected; subsequent hits for the same contig are ignored. The selected accession is then validated against --viral-taxids and --taxdump: only hits whose taxid (at any rank — strain, species, genus, or family) traces back to a target family are kept as reference targets.
When to use: when sequence identity to a specific genome matters more than taxonomic label — for example, when working with divergent or novel strains where taxid-based lookup may return a reference that is genetically distant. Requires de novo assembly (--run-denovo-assembly) to produce the contigs used as BLAST queries.
Limitation: requires a pre-built BLAST index alongside --viral-genomes (created automatically by viralunity get-databases virus-genome). If no contigs pass the identity/coverage thresholds, no reference assembly is triggered for that sample.
Required databases: --viral-genomes with its BLAST index, --viral-taxids, and --taxdump (produced by viralunity get-databases virus-genome / NCBI taxdump).
viralunity meta illumina \
--sample-sheet samples.csv \
--config-file config.yaml \
--output /path/to/output \
--kraken2-database /path/to/kraken2_db \
--krona-database /path/to/krona_taxonomy \
--taxdump /path/to/taxdump \
--run-denovo-assembly \
--run-reference-assembly \
--reference-selection-strategy similarity \
--method kraken2 \
--source reads \
--families Coronaviridae,Orthomyxoviridae \
--reads-count 100 \
--blast-qcov 80 \
--blast-pident 80 \
--viral-genomes databases/virus_genomes/viral.genomes.fasta \
--threads 4 --threads-total 8
Strategy comparison
|
|
|
|---|---|---|
Requires de novo assembly |
No |
Yes |
Requires |
Yes |
Yes (family validation) |
Requires |
Yes (family validation + species fallback) |
Yes (family validation) |
Requires BLAST index |
No |
Yes |
Selection basis |
Taxonomic ID match (exact → species fallback) |
Best BLAST hit per contig |
Speed |
Fast |
Slower (BLAST per sample) |
Best for |
Known strains with good RefSeq coverage |
Divergent or novel strains |
Required databases
Option |
File produced by |
Used by |
|---|---|---|
|
|
Both strategies |
|
|
Both ( |
|
NCBI taxdump |
Both (family validation; species-level fallback for |
BLAST index ( |
|
|
Running tests
pytest -v test