Found while investigating why QUICKREF almost never fires once its coordinate bug is fixed (#30). This looks like a better explanation for the benchmark result than anything found so far, and it is a bigger problem than QUICKREF.
The measurement
On 2000 catalog loci of a 30x ONT sample, with QUICKREF disabled so every locus is genotyped properly, STRdust calls 1652 of 1999 loci (83%) non-reference. The benchmark paper reports that 83.6% of loci are invariant (homozygous for the reference allele) in the R10 HPRC assemblies. Even allowing for a different sample and a 1.4 Mb catalog subset, that gap is far too large to be locus selection.
Of those non-reference calls, more than half are noise-scale:
largest |RB| per locus count cumulative
0-1 bp 262 15.9%
2 bp 263 31.8%
3 bp 341 52.4%
>= 4 bp 786 100.0%
The median REF length at these loci is 11 bp.
The mechanism
is_similar_to_ref (src/vcf.rs) decides whether an allele counts as reference using an edit-distance threshold of reference.len() / 20 — 5%, floor division. The comment in the code states the consequence plainly:
// For 12bp: threshold = 0, so only exact matches pass
With a median REF length of 11 bp, most loci require the consensus to match the reference exactly to be called 0/0. A POA consensus over ONT reads at a short STR essentially never does, so a one-base stutter becomes a 0/1 call.
The same noise-intolerance shows up in QUICKREF, which requires every read to differ from the reference by exactly zero. Sweeping a tolerance there does not rescue it, because a few bp is also the size of most real variation at these loci:
| tolerance |
QUICKREF fires |
of which wrong |
| 0 |
1/1999 |
0 |
| 3 |
26/1999 |
9 |
| 5 |
153/1999 |
99 |
Why this matches the published benchmark
From "A comprehensive assessment of tandem repeat genotyping methods for Nanopore long-read genomes" (Genome Biology, in press), which benchmarked v0.16.0:
- "For 0/0 genotypes, all tools except STRdust achieved >90% concordance" — and 0/0 loci are 83.6% of all loci.
- "STRdust tends to call more genotypes with an alternate allele."
- Mendelian consistency at 0/0: 99.5% against 99.8-99.99% for every other tool, "driven by a higher rate of motif-length-off calls at this class".
- "Mononucleotide repeats were the most difficult to accurately call, with STRdust below 40% consistency" — homopolymers are exactly where ONT indel noise is worst and where
len()/20 is 0.
- Overall concordance 72.56% (R10), rising to 94.93% when an off-by-motif deviation is permitted.
Direction
That last figure is the most useful hint in the paper: the natural unit of tolerance is one motif, not a percentage of the interval length. STRdust currently does not know the motif at all — the catalog BED carries it in column 4 and STRdust ignores it, and src/motif.rs is an unimplemented stub.
Worth considering, roughly in order of effort:
- Give
is_similar_to_ref an absolute floor so a 1-2 bp difference at a short repeat does not force an alt call, rather than a percentage that rounds to zero.
- Read the motif from the catalog and make both the reference-similarity test and the reported allele length motif-aware.
- Model stutter/sequencing error properly, as Medaka Tandem (error model estimated from the reads) and LongTR (HipSTR-derived stutter model) do — the two tools that top the benchmark.
Should be measured with #23 rather than tuned against the alignment path.
Found while investigating why QUICKREF almost never fires once its coordinate bug is fixed (#30). This looks like a better explanation for the benchmark result than anything found so far, and it is a bigger problem than QUICKREF.
The measurement
On 2000 catalog loci of a 30x ONT sample, with QUICKREF disabled so every locus is genotyped properly, STRdust calls 1652 of 1999 loci (83%) non-reference. The benchmark paper reports that 83.6% of loci are invariant (homozygous for the reference allele) in the R10 HPRC assemblies. Even allowing for a different sample and a 1.4 Mb catalog subset, that gap is far too large to be locus selection.
Of those non-reference calls, more than half are noise-scale:
The median REF length at these loci is 11 bp.
The mechanism
is_similar_to_ref(src/vcf.rs) decides whether an allele counts as reference using an edit-distance threshold ofreference.len() / 20— 5%, floor division. The comment in the code states the consequence plainly:// For 12bp: threshold = 0, so only exact matches passWith a median REF length of 11 bp, most loci require the consensus to match the reference exactly to be called
0/0. A POA consensus over ONT reads at a short STR essentially never does, so a one-base stutter becomes a0/1call.The same noise-intolerance shows up in QUICKREF, which requires every read to differ from the reference by exactly zero. Sweeping a tolerance there does not rescue it, because a few bp is also the size of most real variation at these loci:
Why this matches the published benchmark
From "A comprehensive assessment of tandem repeat genotyping methods for Nanopore long-read genomes" (Genome Biology, in press), which benchmarked v0.16.0:
len()/20is 0.Direction
That last figure is the most useful hint in the paper: the natural unit of tolerance is one motif, not a percentage of the interval length. STRdust currently does not know the motif at all — the catalog BED carries it in column 4 and STRdust ignores it, and
src/motif.rsis an unimplemented stub.Worth considering, roughly in order of effort:
is_similar_to_refan absolute floor so a 1-2 bp difference at a short repeat does not force an alt call, rather than a percentage that rounds to zero.Should be measured with #23 rather than tuned against the alignment path.