Summary
--clipAdapterType CellRanger4 combined with a non-zero --clip5pNbases / --clip3pNbases misplaces most reads by exactly clip5pNbases. Each option on its own is fine; only the pairing breaks.
Found while validating the CR4 clip work in the hyalite PR (#198 ). It predates that PR and is not caused by it.
Reproduction
Real 10x mouse chr19 (see CONTRIBUTING.md for dataset) , rustar and STAR 2.7.11b with the same flags:
SC=test/data/singlecell
COMMON="--readFilesIn $SC/reads/S10_L001_R2_001.fastq.gz $SC/reads/S10_L001_R1_001.fastq.gz \
--readFilesCommand zcat --soloType CB_UMI_Simple \
--soloCBwhitelist $SC/reference/10xv2_whitelist_sub50K.txt --soloFeatures Gene \
--clipAdapterType CellRanger4 --clip5pNbases 5 --clip3pNbases 3 \
--outSAMattributes NH HI AS nM --outSAMtype SAM --runThreadN 4"
./target/release/rustar-aligner --runMode alignReads --genomeDir $SC/solo_idx \
--sjdbGTFfile $SC/reference/gencode.vM19.annotation.chr19.gtf \
$COMMON --outFileNamePrefix $SC/rustar_cr4clip_
STAR --genomeDir $SC/star_solo_idx $COMMON --outFileNamePrefix $SC/star_cr4clip_
Then histogram the per-read POS delta (rustar − STAR) over primary records present in both.
What it looks like
POS delta, ~16.8k reads in both:
| delta |
reads |
| −5 |
8527 |
| +5 |
3546 |
| 0 |
552 |
−5 and +5 are exactly clip5pNbases. Same read at the same POS carries CIGARs differing by 5 in the leading soft clip, e.g. 5S82M3S (rustar) vs 10S77M3S (STAR).
Mapped counts stay close — 14747 vs 14687 uniquely mapped — so reads are being misplaced, not lost, which is why Log.final.out looks healthy.
Scope: only the combination
| configuration |
result |
CellRanger4 alone |
fine — 0 clip diffs, 900 other (the usual mapping/tie baseline) |
--clip5pNbases 5 --clip3pNbases 3 alone (no CR4) |
fine — 1 leading-clip diff, 980 other |
| both together |
broken — 15605 differing, dominated by ±5 |
Notes for whoever picks this up
- Not
apply_read_clips (src/io/sam.rs:1106). It already swaps lead/trail for reverse strand and does not touch POS. I checked this first; it's clean. The cause is upstream, in what sequence reaches the aligner or how POS is derived from it.
- The bidirectional ±5 split (~70/30) suggests something strand-dependent, but that is a hypothesis, not a finding.
- The POS-delta histogram is the diagnostic that made this obvious. CIGAR-level diffing hid it, because the CIGARs look individually plausible.
Dead end — please don't repeat it
STAR's ClipMate::clip does the fixed N-trim before the adapter trim, so our poly-A scan window is formally wrong for this pairing (we scan raw[TSO..], STAR scans raw[TSO+clip5p .. len-clip3p]). I tried narrowing the window to match, and agreement got worse: leading-clip diffs went 475 → 549, because the position bug swamps the window effect. It's reverted, with an NB comment at solo::clip_adapter_cr4_with_tso.
Fix the position bug first; then the window correction can be measured honestly.
Why it matters now
#176 makes clip_adapter_type = "CellRanger4" a default on 10x geometry (CELLRANGER_DEFAULTS). Today CR4 is opt-in, so this only bites users who asked for it. If #176 lands first, any 10x user who adds --clip5pNbases hits this without ever typing --clipAdapterType CellRanger4.
This should be fixed before #176 merges.
Summary
--clipAdapterType CellRanger4combined with a non-zero--clip5pNbases/--clip3pNbasesmisplaces most reads by exactlyclip5pNbases. Each option on its own is fine; only the pairing breaks.Found while validating the CR4 clip work in the hyalite PR (#198 ). It predates that PR and is not caused by it.
Reproduction
Real 10x mouse chr19 (see CONTRIBUTING.md for dataset) , rustar and STAR 2.7.11b with the same flags:
Then histogram the per-read POS delta (rustar − STAR) over primary records present in both.
What it looks like
POS delta, ~16.8k reads in both:
−5 and +5 are exactly
clip5pNbases. Same read at the same POS carries CIGARs differing by 5 in the leading soft clip, e.g.5S82M3S(rustar) vs10S77M3S(STAR).Mapped counts stay close — 14747 vs 14687 uniquely mapped — so reads are being misplaced, not lost, which is why
Log.final.outlooks healthy.Scope: only the combination
CellRanger4alone--clip5pNbases 5 --clip3pNbases 3alone (no CR4)Notes for whoever picks this up
apply_read_clips(src/io/sam.rs:1106). It already swaps lead/trail for reverse strand and does not touch POS. I checked this first; it's clean. The cause is upstream, in what sequence reaches the aligner or how POS is derived from it.Dead end — please don't repeat it
STAR's
ClipMate::clipdoes the fixed N-trim before the adapter trim, so our poly-A scan window is formally wrong for this pairing (we scanraw[TSO..], STAR scansraw[TSO+clip5p .. len-clip3p]). I tried narrowing the window to match, and agreement got worse: leading-clip diffs went 475 → 549, because the position bug swamps the window effect. It's reverted, with an NB comment atsolo::clip_adapter_cr4_with_tso.Fix the position bug first; then the window correction can be measured honestly.
Why it matters now
#176 makes
clip_adapter_type = "CellRanger4"a default on 10x geometry (CELLRANGER_DEFAULTS). Today CR4 is opt-in, so this only bites users who asked for it. If #176 lands first, any 10x user who adds--clip5pNbaseshits this without ever typing--clipAdapterType CellRanger4.This should be fixed before #176 merges.