Repository navigation
Consensus Model
Consensus is generated per sample over every position of that sample's coverage BED. The model is caller-order independent by default and supports configurable absence, filtered-record and tie policies. Parameters are listed in Configuration; output fields are described in Output structure.
- Each caller BCF is normalised with
bcftools norm -f ref -m -any --atomize. - Multi-allelic records are split into one record per ALT, and complex alleles are atomised.
- Each record contributes votes for its own
(REF, ALT)alleles. Atomised records with different REF alleles at the same position (for example a SNPA>Gand a deletionAT>A) remain distinct. - Split records whose ALT copies exceed the caller's ploidy are inconsistent (for example
1/1plus0/1in a diploid) and make that caller abstain. - Alleles are keyed by REF and ALT sequences, so deletions that share an anchor ALT but have different REF lengths are distinct candidates.
- Low-quality records are kept with
FILTER=LowQualinstead of being removed. Under the defaultconsensus.filtered_vote: "abstain", a caller that saw a variant cannot be mistaken for a reference vote.
- An ALT allele becomes a candidate when at least
consensus.thresholdcallers support it. - Among the supporters of a candidate, the majority zygosity (heterozygous
0/1versus homozygous ALT1/1) decides the consensus genotype.
consensus.tie_policy resolves a zygosity tie:
-
"nocall"(default): the position is a no-call, independent of caller order. -
"first": the earliest supporter in the configured caller order decides.
When several ALT alleles reach the threshold, each becomes its own split consensus record. The records are re-joined for the final output unless output.split_multiallelic: true. The combined ALT copies must fit the site ploidy; if they do not (for example two hom-ALT alleles at a diploid site), the position is a no-call.
If no ALT reaches the threshold, the position is reference when at least consensus.threshold callers vote reference; otherwise it is a no-call.
| Caller state | Default vote |
|---|---|
| Caller has an ALT record supporting the allele | ALT vote |
| Caller calls the reference | Reference vote |
| Caller has no record | Reference (consensus.absent_vote: "ref") |
Caller has no record, absent_vote: "abstain"
|
Reference only when the pileup has at least coverage.min_coverage reads |
Caller record with missing genotype (./., 0/.) |
Abstain |
Caller record with FILTER not PASS/.
|
Abstain (consensus.filtered_vote: "abstain") |
Caller record with FILTER not PASS/., filtered_vote: "ref"
|
Reference |
Hom-reference calls of any ploidy vote reference. A no-call is not a hom-reference vote, so a position whose remaining non-abstaining votes are below the threshold is not written.
- Every covered position with a reference or variant consensus is written by default.
-
output.remove_invariant: truedrops reference-only records at export. - Positions whose reference base is an IUPAC ambiguity code (N included), or whose caller allele contains one, are omitted because they cannot be represented with an unambiguous REF allele.
- Consensus no-calls are omitted because there is no genotype to report.
- Reference positions use the gVCF-style
ALT="<*>"representation. See Output structure.
After a variant record, the walk advances one base at a time, so caller records inside a deletion span are still voted on and variant calls under the deletion are kept. Reference records are not written over a called deletion's REF span, because a 0/0 call over deleted bases would contradict the deletion genotype; those positions are represented by the deletion record's POS..END. Deletion support is carried across coverage BED chunk boundaries so bases deleted in the previous chunk are not overwritten by reference records.
- Transient failures (exit status 137 or 140) are retried up to
resources.max_retriestimes. - Any other caller failure terminates the run by default.
-
calling.allow_caller_failure: trueenables degraded mode: the failed caller is skipped with a warning, the surviving callers vote, and the run aborts ifconsensus.thresholdexceeds the number of survivors. - Failed callers are recorded in
CallersFailedin the consensus header. - A sample whose every caller fails is dropped. It is listed in
dropped_samples.txtand inSamplesDroppedin a merged header.
generate_consensus.py streams one cursor per caller BCF instead of materialising all records of a coverage span. Positions without a caller record take a fast path; BED intervals are grouped into spans that share one pileup iterator; and FORMAT/AD counts use bulk pileup accessors.
An optional Cython accelerator (bin/build_consensus_accel.py, built automatically in the Docker image) drives the pileup and writes records through htslib. Without it, an equivalent pure-pysam implementation is used and produces the same records.