Skip to content

CellRanger4 + clip5pNbases/clip3pNbases misplaces reads by clip5pNbases #199

Description

@Psy-Fer

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions