Repository navigation
STARsolo Velocyto and stats files as STARsolo - #338
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
STARsolo Velocyto and stats files as STARsolo
Velocyto's spliced / unspliced / ambiguous matrices were computed with a rule of our own: per read, a junction meant spliced, an intronic block unspliced, anything else ambiguous. On the 10x v2 mouse chr19 fixture that gave 52 / 100 / 362 UMIs against STARsolo's 369 / 57 / 32. This ports STAR's algorithm. Raw and filtered matrices are now byte-identical to STARsolo 2.7.11b.
What STAR does, and what is ported
Transcriptome_classifyAlign.cpp:227-258):nAlignG == 1) whose barcode and UMI pass.--soloStrandkeeps, usingalignToTranscriptMinOverlapwith velocyto's 5-base flank. feat(quant): unspliced targets in TranscriptomeSAM, splicing-status tag and GeneSplicing counts for bulk total RNA-seq #283 already ported that for bulk use (quant/splice_status.rs), and it's reused unchanged. I re-checked it line by line, including thebinarySearch1exon lookup.reAnn1type bits. STAR drops a transcript only when a block of a spliced read runs into one of its introns; it does not compare the read's junctions with the transcript's, and neither do we.SoloFeature_countVelocyto.cpp)::33-38); reads with either undefined are skipped.:43-77). Once that set is empty, later reads are skipped.:95-136), using the collapse feat(quant): unspliced targets in TranscriptomeSAM, splicing-status tag and GeneSplicing counts for bulk total RNA-seq #283 ported.SoloFeature_outputResults.cpp): every (cell, gene) row appears in all three matrices, zeros included.Velocyto/filtered/, which wasn't written before (SoloFeature_cellFiltering.cpp:16-30): the Gene feature's called cells that Velocyto detected. A cell is detected when it's one of the whitelist matches of a read with a Velocyto record; under1MM_multi, every candidate counts. With no such cell, nothing is written (:106-108).u32per transcript (tr << 4 | bits) in one flat store, and the detected cells are a bitset. That's 12 bytes for a one-transcript read, kept for the whole run, instead of a 56-byte struct plus two heap allocations.readInfo per feature
STAR keeps a readInfo per feature:
CB/UBread the first feature's (samAttrFeature), Velocyto the Gene feature's (ParametersSolo.cpp:420). E2 kept one, for the first feature; it's now a slot per feature.--outSAMtype None.CB/UBpass.Refusals
--soloFeatures VelocytowithoutGene: STAR segfaults, since it indexes the Gene feature's readInfo unconditionally; we refuse it. Before, we silently added a Gene feature and wrote aGene/directory nobody asked for.--soloType SmartSeq: refused with STAR's message (ParametersSolo.cpp:238-241).Validation against STARsolo 2.7.11b (10x v2 mouse chr19 fixture)
Raw and filtered
spliced/unspliced/ambiguous.mtx,features.tsvandbarcodes.tsvare byte-identical in all 10 configurations:--soloStrand Unstranded, andReverse;--soloCBmatchWLtype 1MM_multi;--soloFeatures GeneFull Gene Velocyto, so the two readInfos differ;CB UB GX GNin a sorted BAM; the BAM is identical too;--soloUMIdedup 1MM_Directional, andExact;--soloCellFilter EmptyDrops_CR;In every run, Gene, GeneFull and SJ are unchanged and identical to STARsolo's.
E2's comparisons are re-run and unchanged: every tag configuration (
CB_samTagOutincluded) is identical to STARsolo. Non-solo yeast SE/PE output is byte-identical to main.--soloVelocytoAmbiguousremovedA rustar-only option, from #90 via #133, that folded ambiguous molecules into spliced. It rested on the old rule putting exon-only reads in "ambiguous"; under STAR's model they are spliced, and "ambiguous" means exonic in one isoform and intronic in another. It had no STAR equivalent and no DIVERGENCE entry, so it's gone; anyone who wants the old merge can add spliced and ambiguous downstream.
Stats files as STAR writes them
Missing before this PR:
Barcodes.stats;Features.statsandUMIperCellSorted.txt;Summary.csv.The Gene/GeneFull
Summary.csvwas there, but it lacked the Q30 and "Unique+Multiple" lines, printed six fixed decimals, and computed several values its own way.What's ported:
Barcodes.statsis STAR'sSoloReadBarcodeStats. Each read counts once under its finalcbMatchcode, with a UMI rejection replacing the barcode's code (addStats,SoloReadBarcode_getCBandUMI.cpp:93-130); codes STAR doesn't list fall to itsdefault. With--soloCBwhitelist NoneSTAR bins nothing (:95-96) and the file is all zeros; it's now written in that mode too, though our no-whitelist matrices are still unimplemented. A missing adapter or UMI is counted directly, as STAR counts it (:340-350). Extraction now reports why there's no barcode instead of a bareNone.Features.statsis STAR'sSoloReadFeatureStats, from its three stages:SoloReadFeature::record): unmapped, no feature, multi-feature;inputRecords): exact, oneExact and 1MM_multi posterior rejections. For SJ, these count only records whose junction is a matrix row, as STAR skips the others first (SoloReadFeature_inputRecords.cpp:23-27);Velocyto keeps only the UMIs and cells: STAR's
countVelocytonever sums the per-read counts into the feature (onlycountCBgeneUMIcallsaddStats).Summary.csvis STAR'sstatsOutput. Each line's definition and arithmetic follow STAR's:NoMultinCells/2ostreamformat (0.0357143,1,-inf)UMIperCellSorted.txt: written when cells are called.CB_samTagOutwritesBarcodes.stats, as STAR does.CB_UMI_Complex: two kinds of read that both tools reject can land in differentBarcodes.statsbins, because our Complex matching uses the product of the segment whitelists rather than STAR's per-segment matching. Recorded as DIVERGENCE §3.4; nothing else changes.More STAR differences fixed along the way:
MATCH_CellRangerbuild counts the others too; the default build doesn't).UniqueAndMult-*.mtxwrote0.50000where STAR writes0.5. E1's comparison was numeric and didn't catch it.noNoFeaturewhatever its barcode match; a 1MM_multi read with junctions was counted there too.--soloCellFilter TopCells Ntook the N barcodes with the most UMIs. STAR keeps every barcode with at least the UMIs of the one at index N, so ties are kept (SoloFeature_cellFiltering.cpp:46-59). WithTopCells 100on the fixture STAR calls 106 cells and we called 100; now identical. This was already wrong on main.Validation: STAR's own recorded command line was replayed for 30 STARsolo configurations of the fixture. They cover all barcode match types, every multimapper method, both dedups, all strands, EmptyDrops, MultiGeneUMI_CR, CellRanger4, two
CB_UMI_Complexadapter setups,CB_samTagOut, the sorted-BAM tags, Velocyto, and paired-end.453 of 457
Solo.outfiles are byte-identical to STARsolo's. The other four are inCB_UMI_Complex, where DIVERGENCE §1.6 rejects homopolymer UMIs of every base and STAR only poly-A. 43 reads land innoUMIhomopolymerinstead of STAR's bins; the matrices are unchanged. §1.6 now says so.Seven more configurations, all byte-identical (112 files):
--soloFeatures Gene SJwith1MM_multi, and with1MM_multi_pseudocounts;--soloCellFilter TopCells 100, andNone;--outSAMtype None;test_starsolo_stats_files(below), run through STAR: all 14Solo.outfiles;--soloCBwhitelist None --soloCBmatchWLtype Exact:Barcodes.stats, the only file we write in that mode.The fixture has only 39 SJ reads, so the synthetic test is what exercises SJ's 1MM_multi path.
Yeast SE/PE alignments and
SJ.out.tabare byte-identical to main.CellRanger.summary.csvis opt-inA rustar-only extension, from #90 via #133. It was written whenever Gene and GeneFull both ran, had no STAR equivalent and no DIVERGENCE entry. It's now written only with the new
--soloCellRangerSummary Yes, and is documented in DIVERGENCE §1.8 and the CLI reference. By defaultSolo.outholds only STARsolo's files; a test checks both ways.Not in this PR (all already the case on main)
filtered/, which we skip, and our Gene counts differ (same 315 entries, different values). That path needs a port of its own.--soloCBwhitelist None: no matrices, and it requires--soloCBmatchWLtype Exactwhere STAR accepts the default.sMand theCR/URtags forCB_UMI_Complexreads with no adapter, UMI or CB.Tests
filtered/are both checked, once with Gene alone and once with GeneFull first andCB/UB, so the tags and Velocyto use different readInfos;test_starsolo_stats_files: exactBarcodes.statsand SJFeatures.statscontents for a fixture with a 1MM_multi read, an exact barcode with an N in its UMI, a barcode off the whitelist, and a read with no junction. If the bad-UMI read counted as an exact match, the posterior would drop the multi read. STAR gives the same files;soloCellFilteringwith TopCells now expects STAR's threshold.--soloCellRangerSummaryvalidation.src/io/sam.rsandsrc/chimeric/bam.rs, files this PR doesn't touch; they're on main too.