seqforge 2026.7.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- seqforge/__init__.py +16 -0
- seqforge/cli/__init__.py +38 -0
- seqforge/cli/__main__.py +8 -0
- seqforge/cli/_common.py +105 -0
- seqforge/cli/compose.py +119 -0
- seqforge/cli/eval.py +103 -0
- seqforge/cli/harvest.py +417 -0
- seqforge/cli/hook.py +247 -0
- seqforge/cli/io.py +502 -0
- seqforge/cli/kb.py +348 -0
- seqforge/cli/manifest.py +536 -0
- seqforge/cli/probe.py +43 -0
- seqforge/cli/processing.py +192 -0
- seqforge/cli/project.py +52 -0
- seqforge/cli/resolve.py +55 -0
- seqforge/cli/root.py +66 -0
- seqforge/cli/run.py +463 -0
- seqforge/cli/schema.py +41 -0
- seqforge/compose/__init__.py +28 -0
- seqforge/compose/core.py +515 -0
- seqforge/compose/gates.py +113 -0
- seqforge/compose/params.py +447 -0
- seqforge/e2e.py +1926 -0
- seqforge/evals/__init__.py +78 -0
- seqforge/evals/case.py +382 -0
- seqforge/evals/grade.py +300 -0
- seqforge/evals/run.py +420 -0
- seqforge/harvest/__init__.py +121 -0
- seqforge/harvest/extract.py +319 -0
- seqforge/harvest/fields.py +212 -0
- seqforge/harvest/normalize.py +537 -0
- seqforge/harvest/prep.py +41 -0
- seqforge/harvest/providers.py +321 -0
- seqforge/harvest/verify.py +251 -0
- seqforge/hooks/__init__.py +33 -0
- seqforge/hooks/guards.py +214 -0
- seqforge/io/__init__.py +61 -0
- seqforge/io/archive.py +450 -0
- seqforge/io/attributes.py +190 -0
- seqforge/io/biosample/attributes.json +6341 -0
- seqforge/io/efo/labels.json +55 -0
- seqforge/io/efo.py +138 -0
- seqforge/io/onlist.py +661 -0
- seqforge/io/onlists/3M-february-2018.codes.gz +0 -0
- seqforge/io/onlists/737K-arc-v1.codes.gz +0 -0
- seqforge/io/onlists/737K-august-2016.codes.gz +0 -0
- seqforge/io/onlists/bd-rhapsody-cls1-384.codes.gz +0 -0
- seqforge/io/onlists/bd-rhapsody-cls1.codes.gz +0 -0
- seqforge/io/onlists/bd-rhapsody-cls2-384.codes.gz +0 -0
- seqforge/io/onlists/bd-rhapsody-cls2.codes.gz +0 -0
- seqforge/io/onlists/bd-rhapsody-cls3-384.codes.gz +0 -0
- seqforge/io/onlists/bd-rhapsody-cls3.codes.gz +0 -0
- seqforge/io/onlists/index.json +74 -0
- seqforge/io/remote.py +659 -0
- seqforge/io/taxonomy.py +194 -0
- seqforge/kb/__init__.py +62 -0
- seqforge/kb/anchor.py +169 -0
- seqforge/kb/generate.py +147 -0
- seqforge/kb/loader.py +152 -0
- seqforge/kb/roundtrip.py +112 -0
- seqforge/kb/schema.py +422 -0
- seqforge/kb/specs/10x-3p-gex/spec.yaml +62 -0
- seqforge/kb/specs/10x-3p-gex-v2/README.md +41 -0
- seqforge/kb/specs/10x-3p-gex-v2/spec.yaml +83 -0
- seqforge/kb/specs/10x-3p-gex-v3/README.md +56 -0
- seqforge/kb/specs/10x-3p-gex-v3/spec.yaml +118 -0
- seqforge/kb/specs/10x-3p-gex-v3.1/README.md +56 -0
- seqforge/kb/specs/10x-3p-gex-v3.1/spec.yaml +124 -0
- seqforge/kb/specs/bd-rhapsody-wta/README.md +103 -0
- seqforge/kb/specs/bd-rhapsody-wta/spec.yaml +130 -0
- seqforge/kb/specs/bd-rhapsody-wta-enhanced/spec.yaml +99 -0
- seqforge/kb/specs/bd-rhapsody-wta-enhanced-v1/spec.yaml +93 -0
- seqforge/kb/specs/bd-rhapsody-wta-enhanced-v2/spec.yaml +81 -0
- seqforge/kb/specs/bulk-rnaseq-pe/README.md +35 -0
- seqforge/kb/specs/bulk-rnaseq-pe/spec.yaml +97 -0
- seqforge/kb/specs/splitseq/README.md +51 -0
- seqforge/kb/specs/splitseq/spec.yaml +157 -0
- seqforge/manifest/__init__.py +61 -0
- seqforge/manifest/fill.py +531 -0
- seqforge/manifest/hash.py +77 -0
- seqforge/manifest/instruct.py +114 -0
- seqforge/manifest/policy.py +409 -0
- seqforge/manifest/validate.py +274 -0
- seqforge/models/__init__.py +268 -0
- seqforge/models/assertion.py +68 -0
- seqforge/models/base.py +100 -0
- seqforge/models/blocker.py +71 -0
- seqforge/models/conflict.py +47 -0
- seqforge/models/dataset.py +320 -0
- seqforge/models/evidenced.py +54 -0
- seqforge/models/observation.py +157 -0
- seqforge/models/processing.py +231 -0
- seqforge/models/records.py +145 -0
- seqforge/models/resolve.py +216 -0
- seqforge/probe/__init__.py +46 -0
- seqforge/probe/core.py +232 -0
- seqforge/probe/signals.py +250 -0
- seqforge/probe/streaming.py +118 -0
- seqforge/project.py +177 -0
- seqforge/py.typed +0 -0
- seqforge/resolve/__init__.py +98 -0
- seqforge/resolve/assign.py +204 -0
- seqforge/resolve/cache.py +119 -0
- seqforge/resolve/confuse.py +215 -0
- seqforge/resolve/engine.py +646 -0
- seqforge/resolve/escalate.py +668 -0
- seqforge/resolve/evaluators.py +306 -0
- seqforge/resolve/geometry.py +89 -0
- seqforge/resolve/group.py +85 -0
- seqforge/resolve/records.py +550 -0
- seqforge/resolve/scoring.py +373 -0
- seqforge/resolve/window.py +206 -0
- seqforge/workflows/__init__.py +234 -0
- seqforge/workflows/cram.py +117 -0
- seqforge/workflows/h5ad.py +368 -0
- seqforge/workflows/map/star.smk +101 -0
- seqforge/workflows/map/starsolo.smk +360 -0
- seqforge/workflows/qc.py +157 -0
- seqforge/workspace.py +125 -0
- seqforge-2026.7.1.dist-info/METADATA +125 -0
- seqforge-2026.7.1.dist-info/RECORD +124 -0
- seqforge-2026.7.1.dist-info/WHEEL +4 -0
- seqforge-2026.7.1.dist-info/entry_points.txt +2 -0
- seqforge-2026.7.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
|
|
3
|
+
# ============================================================================================
|
|
4
|
+
# BD RHAPSODY WTA (Whole Transcriptome Analysis) — the ORIGINAL fixed-offset cell-label bead.
|
|
5
|
+
#
|
|
6
|
+
# Read structure, linkers, whitelists and strand pinned from primary sources (never memory):
|
|
7
|
+
# - scg_lib_structs (CC-BY): https://teichlab.github.io/scg_lib_structs/methods_html/BD_Rhapsody.html
|
|
8
|
+
# - seqspec assay example: docs/examples/assays/bd_rhapsody_v1.spec.yaml (pachterlab/seqspec)
|
|
9
|
+
# - STARsolo maintainer-endorsed position string: github.com/alexdobin/STAR/issues/1111, #1607
|
|
10
|
+
# - EFO term verified live on EBI OLS4.
|
|
11
|
+
#
|
|
12
|
+
# Read 1 (the BEAD read), 5'->3' [structural length 60 bp; R1 is sequenced longer, into poly(T)/cDNA]:
|
|
13
|
+
# [CLS1 9bp][linker1 12bp][CLS2 9bp][linker2 13bp][CLS3 9bp][UMI 8bp]
|
|
14
|
+
# offsets: CLS1 [0,9) linker1 [9,21) CLS2 [21,30) linker2 [30,43) CLS3 [43,52) UMI [52,60)
|
|
15
|
+
# Read 2 = the cDNA read (top strand as template — sense to the mRNA, see soloStrand).
|
|
16
|
+
# The three cell-label sets (CLS1/CLS2/CLS3) are 97 x 9 bp EACH (BD publishes 97 per pool, not 96 —
|
|
17
|
+
# verified by downloading the shipped lists; see README). soloCBwhitelist order == CB-position order.
|
|
18
|
+
#
|
|
19
|
+
# THE VARIANT DISCRIMINATOR (the thing most likely to be silently mismatched): this entry is the
|
|
20
|
+
# ORIGINAL cell-label bead, whose CLS/UMI sit at FIXED offsets. The 2022 "Enhanced" bead prepends a
|
|
21
|
+
# VARIABLE-length diversity insert (0-3 bp) before CLS1 and shortens both linkers to 4 bp
|
|
22
|
+
# (GTGA / GACA) — that shifts every downstream offset and is NOT a fixed CB_UMI_Complex. seqforge
|
|
23
|
+
# models fixed-offset elements only, so the Enhanced bead needs anchored-element support first and is
|
|
24
|
+
# deliberately OUT OF SCOPE here — a separate future entry, never conflated with this one.
|
|
25
|
+
# ============================================================================================
|
|
26
|
+
|
|
27
|
+
identity:
|
|
28
|
+
id: bd-rhapsody-wta
|
|
29
|
+
version: v1-cell-label # the original fixed-offset bead (NOT the Enhanced variable bead)
|
|
30
|
+
name: "BD Rhapsody WTA (3' whole-transcriptome, original cell-label bead)"
|
|
31
|
+
aliases: ["BD Rhapsody", "Rhapsody", "BD Rhapsody WTA", "BD Rhapsody Whole Transcriptome Analysis",
|
|
32
|
+
"Rhapsody WTA", "BD Rhapsody Single-Cell"]
|
|
33
|
+
assay_ontology: ["EFO:0700003"] # "BD Rhapsody Whole Transcriptome Analysis" — verified via
|
|
34
|
+
# EBI OLS4 (obo_id=EFO:0700003). NB EFO:0700004 is the
|
|
35
|
+
# Targeted-mRNA panel, a different assay — never this one.
|
|
36
|
+
modality: rna
|
|
37
|
+
|
|
38
|
+
reads:
|
|
39
|
+
# Read 2 (cDNA). BD/STARsolo pass cDNA first (--readFilesIn R2 R1); the role is decided by the
|
|
40
|
+
# elements here, not by the read id, so declaring cdna on R2 is all that is needed.
|
|
41
|
+
- id: cdna
|
|
42
|
+
seqspec_read_id: R2
|
|
43
|
+
file_hint: "_R2_"
|
|
44
|
+
strand: pos
|
|
45
|
+
min_len: 25
|
|
46
|
+
max_len: null
|
|
47
|
+
elements:
|
|
48
|
+
- {type: cdna, name: cdna, start: 0, end: null, seqspec_region_type: cdna}
|
|
49
|
+
# Read 1 (the bead read): three fixed 9 bp cell-label blocks split by two fixed linkers, then an
|
|
50
|
+
# 8 bp UMI. `max_len: null` because R1 is over-sequenced past byte 60 into poly(T)/cDNA — CB/UMI are
|
|
51
|
+
# read from their fixed offsets and the tail is ignored (the two constant linkers are the signature,
|
|
52
|
+
# so no segment_length gate is needed to stay separable).
|
|
53
|
+
- id: bc
|
|
54
|
+
seqspec_read_id: R1
|
|
55
|
+
file_hint: "_R1_"
|
|
56
|
+
strand: pos
|
|
57
|
+
min_len: 60
|
|
58
|
+
max_len: null
|
|
59
|
+
elements:
|
|
60
|
+
- {type: barcode, name: cls1, start: 0, end: 9, onlist: cls1, seqspec_region_type: barcode}
|
|
61
|
+
# linker1 = the CLS1->CLS2 spacer (verbatim from scg_lib_structs / seqspec bd_rhapsody_v1)
|
|
62
|
+
- {type: linker, name: linker1, start: 9, end: 21, seqspec_region_type: linker,
|
|
63
|
+
sequence: "ACTGGCCTGCGA"}
|
|
64
|
+
- {type: barcode, name: cls2, start: 21, end: 30, onlist: cls2, seqspec_region_type: barcode}
|
|
65
|
+
# linker2 = the CLS2->CLS3 spacer (verbatim from scg_lib_structs / seqspec bd_rhapsody_v1)
|
|
66
|
+
- {type: linker, name: linker2, start: 30, end: 43, seqspec_region_type: linker,
|
|
67
|
+
sequence: "GGTAGCGGTGACA"}
|
|
68
|
+
- {type: barcode, name: cls3, start: 43, end: 52, onlist: cls3, seqspec_region_type: barcode}
|
|
69
|
+
- {type: umi, name: UMI, start: 52, end: 60, seqspec_region_type: umi}
|
|
70
|
+
|
|
71
|
+
onlists:
|
|
72
|
+
cls1: {registry: bd-rhapsody-cls1, role: cell_barcode, expected_orientation: forward} # 97 x 9 bp
|
|
73
|
+
cls2: {registry: bd-rhapsody-cls2, role: cell_barcode, expected_orientation: forward}
|
|
74
|
+
cls3: {registry: bd-rhapsody-cls3, role: cell_barcode, expected_orientation: forward}
|
|
75
|
+
tenx_probe: {registry: 3M-february-2018, role: cell_barcode, expected_orientation: forward} # exclude only
|
|
76
|
+
|
|
77
|
+
signature:
|
|
78
|
+
requires: # the two FIXED linkers are the structural signature
|
|
79
|
+
- {test: read_count, roles: 2}
|
|
80
|
+
- {test: has_segment, read: bc, start: 9, end: 21, kind: constant} # linker1 (12 bp)
|
|
81
|
+
- {test: has_segment, read: bc, start: 30, end: 43, kind: constant} # linker2 (13 bp)
|
|
82
|
+
supports: # each CLS block hits its own 97 x 9 bp whitelist
|
|
83
|
+
- when: {test: onlist_hit_rate, read: bc, element: cls1, onlist: cls1, orientation: forward, min: 0.5}
|
|
84
|
+
weight: 3.0
|
|
85
|
+
- when: {test: onlist_hit_rate, read: bc, element: cls2, onlist: cls2, orientation: forward, min: 0.5}
|
|
86
|
+
weight: 3.0
|
|
87
|
+
- when: {test: onlist_hit_rate, read: bc, element: cls3, onlist: cls3, orientation: forward, min: 0.5}
|
|
88
|
+
weight: 3.0
|
|
89
|
+
- when: {test: distinct_ratio, read: bc, start: 52, end: 60, expect: high} # UMI ~unique
|
|
90
|
+
weight: 1.0
|
|
91
|
+
- when: {test: distinct_ratio, read: cdna, start: 0, end: 20, expect: high} # cDNA role is scored too
|
|
92
|
+
weight: 1.0
|
|
93
|
+
excludes: # a 16 bp 10x CB at read start => not BD Rhapsody
|
|
94
|
+
- {test: onlist_hit_rate, read: bc, start: 0, end: 16, onlist: tenx_probe, orientation: forward, min: 0.6}
|
|
95
|
+
|
|
96
|
+
backend:
|
|
97
|
+
module: map/starsolo
|
|
98
|
+
params:
|
|
99
|
+
soloType: CB_UMI_Complex
|
|
100
|
+
soloCBwhitelist: ["{onlist:cls1}", "{onlist:cls2}", "{onlist:cls3}"] # order == CB-position order
|
|
101
|
+
# soloStrand: DERIVED, not pattern-matched (a wrong strand leaves most reads unassigned while
|
|
102
|
+
# STARsolo exits 0 and emits a matrix that merely looks thin — neither gate can catch it).
|
|
103
|
+
# DERIVATION: the bead oligo terminates in (dT)18 at its 3' end; that poly(dT) primes reverse
|
|
104
|
+
# transcription off the mRNA poly(A) tail, so R2 sequences the cDNA in the SAME orientation as the
|
|
105
|
+
# original mRNA — a standard 3' poly-dT capture library, exactly like 10x Chromium 3'. STARsolo
|
|
106
|
+
# defines Forward as "read strand same as the original RNA molecule" -> Forward (also its default).
|
|
107
|
+
# CORROBORATION: a full working BD Rhapsody STARsolo command sets --soloStrand Forward
|
|
108
|
+
# (github.com/alexdobin/STAR/issues/1607), and scg_lib_structs runs BD with STARsolo's Forward
|
|
109
|
+
# default. No source claims Reverse.
|
|
110
|
+
soloStrand: Forward
|
|
111
|
+
# soloCBposition / soloUMIposition are DERIVED from the element coordinates at compose time
|
|
112
|
+
# (compose/params.py::derived_params) -> "0_0_0_8 0_21_0_29 0_43_0_51" and UMI "0_52_0_59", with
|
|
113
|
+
# soloUMIlen 8. That quadruple set is byte-identical to the maintainer-endorsed STARsolo string
|
|
114
|
+
# on issue #1111, which is an independent cross-check on the geometry above. Never hand-enter it.
|
|
115
|
+
# soloFeatures is NOT here: it says what to COUNT (cells vs nuclei is sample prep, not chemistry),
|
|
116
|
+
# and lives in the processing manifest where a user may instruct it.
|
|
117
|
+
|
|
118
|
+
# The combinatorial CLS geometry + the two fixed linkers separate this from 10x / SPLiT-seq (different
|
|
119
|
+
# linker sequences and positions). What it does NOT separate itself from is the generic paired-end
|
|
120
|
+
# fallback, which forbids so little it accepts these two files at rungs 0-2 — the confusion runs in
|
|
121
|
+
# that direction, the relation is symmetric, so it is declared on both sides (see bulk-rnaseq-pe).
|
|
122
|
+
confusable_with:
|
|
123
|
+
- id: bulk-rnaseq-pe
|
|
124
|
+
relationship: processing_divergent
|
|
125
|
+
distinguishable_by: [onlist]
|
|
126
|
+
note: >
|
|
127
|
+
The generic paired-end fallback accepts cdna+bc on geometry alone. Rung 3 decides it: the three
|
|
128
|
+
CLS whitelists hit, and bulk has no whitelist to hit. Maximally divergent downstream
|
|
129
|
+
(map/starsolo with three cell-label rounds vs map/star with none), so a silent preference would
|
|
130
|
+
emit a bulk gene-count matrix for a single-cell library and exit 0.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
|
|
3
|
+
# ============================================================================================
|
|
4
|
+
# BD RHAPSODY WTA — ENHANCED CELL CAPTURE BEAD (2022, "v2.0"): the ABSTRACT FAMILY NODE.
|
|
5
|
+
#
|
|
6
|
+
# The Enhanced bead prepends a VARIABLE-LENGTH 0-3 bp diversity insert to Read 1, so every cell-label
|
|
7
|
+
# block downstream STAGGERS per read — the fixed-offset original bead (`bd-rhapsody-wta`) cannot express
|
|
8
|
+
# this. Read 1 (5'->3'):
|
|
9
|
+
# [VB 0-3bp][CLS1 9][GTGA][CLS2 9][GACA][CLS3 9][UMI 8](dT)... (R1 over-sequenced into poly(T))
|
|
10
|
+
# The two 4 bp linkers GTGA / GACA (vs the original bead's 12/13 bp linkers) at their staggered
|
|
11
|
+
# positions are the byte signature. It recognises the bead by phase-locking that GTGA...GACA frame
|
|
12
|
+
# (`motif_present`, tolerant of the 0-3 bp stagger + 2 substitutions), exactly as rhapsodist does by
|
|
13
|
+
# Hamming-matching the linkers across a range(4) offset scan (workflow/src/workflow_functions.py).
|
|
14
|
+
#
|
|
15
|
+
# This node is a FAMILY, not a runnable chemistry: the two Enhanced sub-versions differ ONLY in
|
|
16
|
+
# whitelist size (96 vs 384 sequences per block) — an ONLIST-decided split, exactly like 10x v2/v3 — so
|
|
17
|
+
# there is no single recipe here. Descent resolves to a leaf:
|
|
18
|
+
# bd-rhapsody-wta-enhanced-v1 (97 x 3 cell-label lists, == the original bead's lists)
|
|
19
|
+
# bd-rhapsody-wta-enhanced-v2 (384 x 3 cell-label lists)
|
|
20
|
+
# It is NEVER scored as a candidate (the scorer skips backend-less nodes) and self-tests by RECOGNITION
|
|
21
|
+
# (test_a_family_node_recognizes_its_children_and_no_one_else), not `kb roundtrip`.
|
|
22
|
+
#
|
|
23
|
+
# Sources (never memory): read structure + linkers from the BD Rhapsody Enhanced v2.0 protocol and
|
|
24
|
+
# rhapsodist (imallona/rhapsodist, Moro & Mallona 2025); STARsolo adapter-anchor recipe endorsed by
|
|
25
|
+
# @alexdobin on github.com/alexdobin/STAR/issues/1607.
|
|
26
|
+
# ============================================================================================
|
|
27
|
+
|
|
28
|
+
identity:
|
|
29
|
+
id: bd-rhapsody-wta-enhanced
|
|
30
|
+
version: enhanced-family
|
|
31
|
+
name: "BD Rhapsody WTA — Enhanced Cell Capture Bead (family)"
|
|
32
|
+
aliases: ["BD Rhapsody Enhanced", "Rhapsody Enhanced", "BD Rhapsody Enhanced Beads",
|
|
33
|
+
"BD Enhanced Cell Capture Beads", "BD Rhapsody WTA Enhanced"]
|
|
34
|
+
assay_ontology: ["EFO:0700003"] # BD Rhapsody WTA — the assay the whole family instantiates
|
|
35
|
+
modality: rna
|
|
36
|
+
|
|
37
|
+
node_kind: family
|
|
38
|
+
# The children (96 / 384) share the byte-identical Enhanced geometry and are told apart ONLY by which
|
|
39
|
+
# cell-label whitelist their CLS blocks hit — the two pools are DISJOINT (0 shared 9-mers), so the
|
|
40
|
+
# onlist separates them cleanly at rung 3, exactly the v2/v3 pattern.
|
|
41
|
+
children_decided_by: [onlist]
|
|
42
|
+
|
|
43
|
+
reads:
|
|
44
|
+
# Read 2 = the cDNA (open-ended, sense to the mRNA — 3' poly-dT capture, like the original bead).
|
|
45
|
+
- id: cdna
|
|
46
|
+
seqspec_read_id: R2
|
|
47
|
+
file_hint: "_R2_"
|
|
48
|
+
strand: pos
|
|
49
|
+
min_len: 25
|
|
50
|
+
max_len: null
|
|
51
|
+
elements:
|
|
52
|
+
- {type: cdna, name: cdna, start: 0, end: null, seqspec_region_type: cdna}
|
|
53
|
+
# Read 1 = the bead read. The leading `vb` diversity insert is variable-length (0-3 bp); every element
|
|
54
|
+
# after it is ANCHORED to the previous one (a sequential chain), so the whole cell label FLOATS by the
|
|
55
|
+
# per-read insert length. The resolver phase-locks the frame on the GTGA/GACA linkers. `max_len: null`
|
|
56
|
+
# because R1 is over-sequenced past the ~43 bp structure into poly(T)/cDNA. The family's CLS blocks
|
|
57
|
+
# carry NO onlist — which whitelist they hit is exactly what descent decides.
|
|
58
|
+
- id: bc
|
|
59
|
+
seqspec_read_id: R1
|
|
60
|
+
file_hint: "_R1_"
|
|
61
|
+
strand: pos
|
|
62
|
+
min_len: 43
|
|
63
|
+
max_len: null
|
|
64
|
+
elements:
|
|
65
|
+
- {type: diversity, name: vb, min_len: 0, max_len: 3, seqspec_region_type: linker}
|
|
66
|
+
- {type: barcode, name: cls1, min_len: 9, max_len: 9, seqspec_region_type: barcode,
|
|
67
|
+
anchor: {relative_to: element, ref_element: vb, ref_side: end, offset: 0}}
|
|
68
|
+
- {type: linker, name: linker1, sequence: "GTGA", seqspec_region_type: linker,
|
|
69
|
+
anchor: {relative_to: element, ref_element: cls1, ref_side: end, offset: 0, max_mismatch: 1}}
|
|
70
|
+
- {type: barcode, name: cls2, min_len: 9, max_len: 9, seqspec_region_type: barcode,
|
|
71
|
+
anchor: {relative_to: element, ref_element: linker1, ref_side: end, offset: 0}}
|
|
72
|
+
- {type: linker, name: linker2, sequence: "GACA", seqspec_region_type: linker,
|
|
73
|
+
anchor: {relative_to: element, ref_element: cls2, ref_side: end, offset: 0, max_mismatch: 1}}
|
|
74
|
+
- {type: barcode, name: cls3, min_len: 9, max_len: 9, seqspec_region_type: barcode,
|
|
75
|
+
anchor: {relative_to: element, ref_element: linker2, ref_side: end, offset: 0}}
|
|
76
|
+
- {type: umi, name: UMI, min_len: 8, max_len: 8, seqspec_region_type: umi,
|
|
77
|
+
anchor: {relative_to: element, ref_element: cls3, ref_side: end, offset: 0}}
|
|
78
|
+
|
|
79
|
+
onlists: {}
|
|
80
|
+
|
|
81
|
+
signature:
|
|
82
|
+
# Coarse recognition only — enough to admit either Enhanced child at rungs 0-2 and reject everything
|
|
83
|
+
# else (the original fixed bead, 10x, bulk). The GTGA...GACA composite is the structural signature:
|
|
84
|
+
# `GTGANNNNNNNNNGACA` = GTGA + CLS2(9N) + GACA, searched across the 0-3 bp insert stagger (start
|
|
85
|
+
# positions 8-13), tolerating 2 substitutions. NO onlist here (that is the children's job).
|
|
86
|
+
requires:
|
|
87
|
+
- {test: read_count, roles: 2}
|
|
88
|
+
- {test: motif_present, read: bc, motif: "GTGANNNNNNNNNGACA", where: window,
|
|
89
|
+
search_start: 8, search_end: 13, max_mismatch: 2, min_rate: 0.5}
|
|
90
|
+
supports:
|
|
91
|
+
# the cell label recurs (low distinct-ratio, resolved at the anchored frame); UMI ~unique; cDNA diverse
|
|
92
|
+
- {when: {test: distinct_ratio, read: bc, element: cls1, expect: low}, weight: 2.0}
|
|
93
|
+
- {when: {test: distinct_ratio, read: bc, element: UMI, expect: high}, weight: 1.0}
|
|
94
|
+
- {when: {test: distinct_ratio, read: cdna, start: 0, end: 20, expect: high}, weight: 1.0}
|
|
95
|
+
excludes: []
|
|
96
|
+
|
|
97
|
+
# no backend: abstract classifier. no parent: a root family (distinct from the original-bead root
|
|
98
|
+
# `bd-rhapsody-wta` — the two beads are byte-separable by their linker structure, so they are not kin).
|
|
99
|
+
confusable_with: []
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
|
|
3
|
+
# ============================================================================================
|
|
4
|
+
# BD RHAPSODY WTA — ENHANCED bead v1, 96(/97) x 3 cell-label lists (rhapsodist class `enhanced`).
|
|
5
|
+
#
|
|
6
|
+
# A leaf of `bd-rhapsody-wta-enhanced`. "v1" is the FIRST Enhanced generation (96-plex), as against the
|
|
7
|
+
# `-v2` sibling (384-plex) — not the original fixed-offset bead, which is `bd-rhapsody-wta`. Byte-
|
|
8
|
+
# identical Enhanced geometry (0-3 bp diversity insert + GTGA/GACA linkers); what makes it THIS leaf is
|
|
9
|
+
# that its three CLS blocks hit the ORIGINAL 97 x 9 bp cell-label pools — the very same
|
|
10
|
+
# `bd-rhapsody-cls1/2/3` whitelists the original fixed-offset bead uses (verified: the shipped lists are
|
|
11
|
+
# byte-identical to rhapsodist's whitelist_96x3, 97 entries each). The `-v2` sibling uses the disjoint
|
|
12
|
+
# 384 x 3 pools; the two share 0 barcodes, so the onlist decides.
|
|
13
|
+
#
|
|
14
|
+
# The layout (reads/elements) is inherited verbatim from the family and is what the round-trip and the
|
|
15
|
+
# adapter-anchored `compose` derivation read; see the family node for the annotated read structure.
|
|
16
|
+
# ============================================================================================
|
|
17
|
+
|
|
18
|
+
identity:
|
|
19
|
+
id: bd-rhapsody-wta-enhanced-v1
|
|
20
|
+
version: enhanced-v1
|
|
21
|
+
name: "BD Rhapsody WTA — Enhanced bead v1 (96-plex cell labels)"
|
|
22
|
+
aliases: ["BD Rhapsody Enhanced 96", "Rhapsody Enhanced 96x3", "BD Rhapsody Enhanced v1"]
|
|
23
|
+
assay_ontology: ["EFO:0700003"]
|
|
24
|
+
modality: rna
|
|
25
|
+
|
|
26
|
+
parent: bd-rhapsody-wta-enhanced
|
|
27
|
+
|
|
28
|
+
reads:
|
|
29
|
+
- id: cdna
|
|
30
|
+
seqspec_read_id: R2
|
|
31
|
+
file_hint: "_R2_"
|
|
32
|
+
strand: pos
|
|
33
|
+
min_len: 25
|
|
34
|
+
max_len: null
|
|
35
|
+
elements:
|
|
36
|
+
- {type: cdna, name: cdna, start: 0, end: null, seqspec_region_type: cdna}
|
|
37
|
+
- id: bc
|
|
38
|
+
seqspec_read_id: R1
|
|
39
|
+
file_hint: "_R1_"
|
|
40
|
+
strand: pos
|
|
41
|
+
min_len: 43
|
|
42
|
+
max_len: null
|
|
43
|
+
elements:
|
|
44
|
+
- {type: diversity, name: vb, min_len: 0, max_len: 3, seqspec_region_type: linker}
|
|
45
|
+
- {type: barcode, name: cls1, min_len: 9, max_len: 9, onlist: cls1, seqspec_region_type: barcode,
|
|
46
|
+
anchor: {relative_to: element, ref_element: vb, ref_side: end, offset: 0}}
|
|
47
|
+
- {type: linker, name: linker1, sequence: "GTGA", seqspec_region_type: linker,
|
|
48
|
+
anchor: {relative_to: element, ref_element: cls1, ref_side: end, offset: 0, max_mismatch: 1}}
|
|
49
|
+
- {type: barcode, name: cls2, min_len: 9, max_len: 9, onlist: cls2, seqspec_region_type: barcode,
|
|
50
|
+
anchor: {relative_to: element, ref_element: linker1, ref_side: end, offset: 0}}
|
|
51
|
+
- {type: linker, name: linker2, sequence: "GACA", seqspec_region_type: linker,
|
|
52
|
+
anchor: {relative_to: element, ref_element: cls2, ref_side: end, offset: 0, max_mismatch: 1}}
|
|
53
|
+
- {type: barcode, name: cls3, min_len: 9, max_len: 9, onlist: cls3, seqspec_region_type: barcode,
|
|
54
|
+
anchor: {relative_to: element, ref_element: linker2, ref_side: end, offset: 0}}
|
|
55
|
+
- {type: umi, name: UMI, min_len: 8, max_len: 8, seqspec_region_type: umi,
|
|
56
|
+
anchor: {relative_to: element, ref_element: cls3, ref_side: end, offset: 0}}
|
|
57
|
+
|
|
58
|
+
onlists:
|
|
59
|
+
cls1: {registry: bd-rhapsody-cls1, role: cell_barcode, expected_orientation: forward} # 97 x 9 bp
|
|
60
|
+
cls2: {registry: bd-rhapsody-cls2, role: cell_barcode, expected_orientation: forward}
|
|
61
|
+
cls3: {registry: bd-rhapsody-cls3, role: cell_barcode, expected_orientation: forward}
|
|
62
|
+
|
|
63
|
+
signature:
|
|
64
|
+
requires: # the GTGA...GACA frame is the byte signature (stagger-tolerant)
|
|
65
|
+
- {test: read_count, roles: 2}
|
|
66
|
+
- {test: motif_present, read: bc, motif: "GTGANNNNNNNNNGACA", where: window,
|
|
67
|
+
search_start: 8, search_end: 13, max_mismatch: 2, min_rate: 0.5}
|
|
68
|
+
supports: # each CLS block hits its own 97 x 9 bp pool, resolved per-read
|
|
69
|
+
- {when: {test: onlist_hit_rate, read: bc, element: cls1, onlist: cls1, orientation: forward, min: 0.5}, weight: 3.0}
|
|
70
|
+
- {when: {test: onlist_hit_rate, read: bc, element: cls2, onlist: cls2, orientation: forward, min: 0.5}, weight: 3.0}
|
|
71
|
+
- {when: {test: onlist_hit_rate, read: bc, element: cls3, onlist: cls3, orientation: forward, min: 0.5}, weight: 3.0}
|
|
72
|
+
- {when: {test: distinct_ratio, read: bc, element: UMI, expect: high}, weight: 1.0}
|
|
73
|
+
- {when: {test: distinct_ratio, read: cdna, start: 0, end: 20, expect: high}, weight: 1.0}
|
|
74
|
+
excludes: []
|
|
75
|
+
|
|
76
|
+
backend:
|
|
77
|
+
module: map/starsolo
|
|
78
|
+
params:
|
|
79
|
+
soloType: CB_UMI_Complex
|
|
80
|
+
soloCBwhitelist: ["{onlist:cls1}", "{onlist:cls2}", "{onlist:cls3}"] # order == CB-position order
|
|
81
|
+
# soloStrand Forward: the bead oligo ends in poly(dT) priming off the mRNA poly(A), so R2 is sense to
|
|
82
|
+
# the transcript — a 3' poly-dT capture library like the original bead (STAR #1607 sets Forward).
|
|
83
|
+
soloStrand: Forward
|
|
84
|
+
# soloAdapterSequence, soloCBposition, soloUMIposition are DERIVED from the anchored element model at
|
|
85
|
+
# compose time (compose/params.py) -> "NNNNNNNNNGTGANNNNNNNNNGACA" + "2_0_2_8 2_13_2_21 3_1_3_9" +
|
|
86
|
+
# "3_10_3_17", byte-identical to the maintainer-endorsed STARsolo string on issue #1607. Never
|
|
87
|
+
# hand-entered: the adapter anchor is where STARsolo absorbs the variable diversity insert.
|
|
88
|
+
|
|
89
|
+
# Siblings under the family are decided by onlist (parent.children_decided_by), so no per-sibling edge.
|
|
90
|
+
# Nothing else is confusable: the GTGA...GACA `requires` motif rejects the original bead, 10x and bulk
|
|
91
|
+
# outright, and the >43 bp bc read is length-infeasible for 10x. (The generic bulk fallback accepts THIS
|
|
92
|
+
# on read-count alone, so the edge is declared on `bulk-rnaseq-pe`, mirroring the original bead.)
|
|
93
|
+
confusable_with: []
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
|
|
3
|
+
# ============================================================================================
|
|
4
|
+
# BD RHAPSODY WTA — ENHANCED bead, 384 x 3 cell-label lists (rhapsodist class `enhanced_v2`).
|
|
5
|
+
#
|
|
6
|
+
# A leaf of `bd-rhapsody-wta-enhanced`, identical to `-96` in every byte-decided way (0-3 bp diversity
|
|
7
|
+
# insert, GTGA/GACA linkers, 9/9/9 CLS + 8 bp UMI). The ONLY difference is the whitelist: 384 x 9 bp per
|
|
8
|
+
# CLS block instead of 97 — the higher-plexity "Enhanced v2" bead. The 384 and 97 pools are DISJOINT
|
|
9
|
+
# (0 shared 9-mers), so a real dataset hits exactly one set at rung 3 and the sibling tie resolves.
|
|
10
|
+
#
|
|
11
|
+
# The 384 x 3 lists ship pre-packed as `bd-rhapsody-cls{1,2,3}-384` (source: imallona/rhapsodist
|
|
12
|
+
# workflow/data/whitelist_384x3, Moro & Mallona 2025).
|
|
13
|
+
# ============================================================================================
|
|
14
|
+
|
|
15
|
+
identity:
|
|
16
|
+
id: bd-rhapsody-wta-enhanced-v2
|
|
17
|
+
version: enhanced-384
|
|
18
|
+
name: "BD Rhapsody WTA — Enhanced bead v2 (384-plex cell labels)"
|
|
19
|
+
aliases: ["BD Rhapsody Enhanced v2", "Rhapsody Enhanced 384x3", "BD Rhapsody Enhanced 384"]
|
|
20
|
+
assay_ontology: ["EFO:0700003"]
|
|
21
|
+
modality: rna
|
|
22
|
+
|
|
23
|
+
parent: bd-rhapsody-wta-enhanced
|
|
24
|
+
|
|
25
|
+
reads:
|
|
26
|
+
- id: cdna
|
|
27
|
+
seqspec_read_id: R2
|
|
28
|
+
file_hint: "_R2_"
|
|
29
|
+
strand: pos
|
|
30
|
+
min_len: 25
|
|
31
|
+
max_len: null
|
|
32
|
+
elements:
|
|
33
|
+
- {type: cdna, name: cdna, start: 0, end: null, seqspec_region_type: cdna}
|
|
34
|
+
- id: bc
|
|
35
|
+
seqspec_read_id: R1
|
|
36
|
+
file_hint: "_R1_"
|
|
37
|
+
strand: pos
|
|
38
|
+
min_len: 43
|
|
39
|
+
max_len: null
|
|
40
|
+
elements:
|
|
41
|
+
- {type: diversity, name: vb, min_len: 0, max_len: 3, seqspec_region_type: linker}
|
|
42
|
+
- {type: barcode, name: cls1, min_len: 9, max_len: 9, onlist: cls1, seqspec_region_type: barcode,
|
|
43
|
+
anchor: {relative_to: element, ref_element: vb, ref_side: end, offset: 0}}
|
|
44
|
+
- {type: linker, name: linker1, sequence: "GTGA", seqspec_region_type: linker,
|
|
45
|
+
anchor: {relative_to: element, ref_element: cls1, ref_side: end, offset: 0, max_mismatch: 1}}
|
|
46
|
+
- {type: barcode, name: cls2, min_len: 9, max_len: 9, onlist: cls2, seqspec_region_type: barcode,
|
|
47
|
+
anchor: {relative_to: element, ref_element: linker1, ref_side: end, offset: 0}}
|
|
48
|
+
- {type: linker, name: linker2, sequence: "GACA", seqspec_region_type: linker,
|
|
49
|
+
anchor: {relative_to: element, ref_element: cls2, ref_side: end, offset: 0, max_mismatch: 1}}
|
|
50
|
+
- {type: barcode, name: cls3, min_len: 9, max_len: 9, onlist: cls3, seqspec_region_type: barcode,
|
|
51
|
+
anchor: {relative_to: element, ref_element: linker2, ref_side: end, offset: 0}}
|
|
52
|
+
- {type: umi, name: UMI, min_len: 8, max_len: 8, seqspec_region_type: umi,
|
|
53
|
+
anchor: {relative_to: element, ref_element: cls3, ref_side: end, offset: 0}}
|
|
54
|
+
|
|
55
|
+
onlists:
|
|
56
|
+
cls1: {registry: bd-rhapsody-cls1-384, role: cell_barcode, expected_orientation: forward} # 384 x 9 bp
|
|
57
|
+
cls2: {registry: bd-rhapsody-cls2-384, role: cell_barcode, expected_orientation: forward}
|
|
58
|
+
cls3: {registry: bd-rhapsody-cls3-384, role: cell_barcode, expected_orientation: forward}
|
|
59
|
+
|
|
60
|
+
signature:
|
|
61
|
+
requires:
|
|
62
|
+
- {test: read_count, roles: 2}
|
|
63
|
+
- {test: motif_present, read: bc, motif: "GTGANNNNNNNNNGACA", where: window,
|
|
64
|
+
search_start: 8, search_end: 13, max_mismatch: 2, min_rate: 0.5}
|
|
65
|
+
supports:
|
|
66
|
+
- {when: {test: onlist_hit_rate, read: bc, element: cls1, onlist: cls1, orientation: forward, min: 0.5}, weight: 3.0}
|
|
67
|
+
- {when: {test: onlist_hit_rate, read: bc, element: cls2, onlist: cls2, orientation: forward, min: 0.5}, weight: 3.0}
|
|
68
|
+
- {when: {test: onlist_hit_rate, read: bc, element: cls3, onlist: cls3, orientation: forward, min: 0.5}, weight: 3.0}
|
|
69
|
+
- {when: {test: distinct_ratio, read: bc, element: UMI, expect: high}, weight: 1.0}
|
|
70
|
+
- {when: {test: distinct_ratio, read: cdna, start: 0, end: 20, expect: high}, weight: 1.0}
|
|
71
|
+
excludes: []
|
|
72
|
+
|
|
73
|
+
backend:
|
|
74
|
+
module: map/starsolo
|
|
75
|
+
params:
|
|
76
|
+
soloType: CB_UMI_Complex
|
|
77
|
+
soloCBwhitelist: ["{onlist:cls1}", "{onlist:cls2}", "{onlist:cls3}"]
|
|
78
|
+
soloStrand: Forward
|
|
79
|
+
# soloAdapterSequence / soloCBposition / soloUMIposition DERIVED from the anchored elements (see -96).
|
|
80
|
+
|
|
81
|
+
confusable_with: []
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Bulk paired-end RNA-seq
|
|
2
|
+
|
|
3
|
+
Standard bulk RNA-seq on an Illumina sequencer: two paired-end cDNA reads, **no cell barcode and no
|
|
4
|
+
UMI**. Every base is transcript sequence — there's nothing to demultiplex into cells. seqforge aligns
|
|
5
|
+
these with plain STAR and counts genes, rather than STARsolo.
|
|
6
|
+
|
|
7
|
+
## How it's read
|
|
8
|
+
|
|
9
|
+
- **R1** and **R2** are the two ends of the same cDNA fragment (a mate pair). Both are transcript
|
|
10
|
+
sequence, typically 75–150 bp.
|
|
11
|
+
- No barcode, no UMI, no whitelist.
|
|
12
|
+
|
|
13
|
+
## How seqforge tells it apart from single-cell
|
|
14
|
+
|
|
15
|
+
It's the **absence** of a barcode that identifies bulk. seqforge looks for a short, low-diversity
|
|
16
|
+
technical read — the tell-tale of a cell barcode — and finds none, just two long, near-unique cDNA
|
|
17
|
+
mates. A single-cell barcode read is short (26–28 bp) and repeats the same 16 bp prefix across reads;
|
|
18
|
+
a bulk mate is long and near-unique from the first base, so a barcode read can never be mistaken for
|
|
19
|
+
bulk cDNA.
|
|
20
|
+
|
|
21
|
+
Because this entry demands so little, it also serves as the **fallback** for any paired-end data.
|
|
22
|
+
That's deliberate: when a real single-cell library (BD Rhapsody, SPLiT-seq) happens to share this
|
|
23
|
+
loose shape, seqforge falls back to the barcode-list check to make sure it never quietly treats a
|
|
24
|
+
single-cell library as bulk.
|
|
25
|
+
|
|
26
|
+
## Coverage note
|
|
27
|
+
|
|
28
|
+
This is the paired-end, poly-A branch. Single-end bulk and explicit strand-protocol handling aren't
|
|
29
|
+
modeled yet.
|
|
30
|
+
|
|
31
|
+
## References
|
|
32
|
+
|
|
33
|
+
The exact, machine-readable definition seqforge uses lives in this entry's `spec.yaml`.
|
|
34
|
+
(scg_lib_structs documents single-cell library structures; plain bulk RNA-seq isn't one of them, so
|
|
35
|
+
there's no page to link.)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
|
|
3
|
+
identity:
|
|
4
|
+
id: bulk-rnaseq-pe
|
|
5
|
+
version: illumina-pe
|
|
6
|
+
name: "Bulk Illumina paired-end RNA-seq (no cell barcode)"
|
|
7
|
+
aliases: ["bulk RNA-seq", "paired-end RNA-seq", "Illumina PE RNA-seq", "polyA RNA-seq PE", "RNA-seq PE"]
|
|
8
|
+
assay_ontology: ["EFO:0008896"] # "RNA-Seq" (generic bulk) — verified against live EFO (EBI OLS)
|
|
9
|
+
modality: rna
|
|
10
|
+
|
|
11
|
+
reads:
|
|
12
|
+
# Two symmetric cDNA mates, no cell barcode / UMI. The min_len gate (>=40) is what excludes a short
|
|
13
|
+
# single-cell barcode read (26/28 bp) from ever filling a bulk role.
|
|
14
|
+
- id: R1
|
|
15
|
+
seqspec_read_id: R1
|
|
16
|
+
file_hint: "_R1_"
|
|
17
|
+
strand: pos
|
|
18
|
+
min_len: 40
|
|
19
|
+
max_len: null
|
|
20
|
+
elements:
|
|
21
|
+
- {type: cdna, name: cdna_r1, start: 0, end: null, seqspec_region_type: cdna}
|
|
22
|
+
- id: R2
|
|
23
|
+
seqspec_read_id: R2
|
|
24
|
+
file_hint: "_R2_"
|
|
25
|
+
strand: neg # the reverse mate
|
|
26
|
+
min_len: 40
|
|
27
|
+
max_len: null
|
|
28
|
+
elements:
|
|
29
|
+
- {type: cdna, name: cdna_r2, start: 0, end: null, seqspec_region_type: cdna}
|
|
30
|
+
|
|
31
|
+
onlists: {}
|
|
32
|
+
|
|
33
|
+
signature:
|
|
34
|
+
requires:
|
|
35
|
+
- {test: read_count, roles: 2} # two reads, both biological; no barcode role to fill
|
|
36
|
+
supports: # diverse cDNA => high distinct-ratio (not a repeated barcode)
|
|
37
|
+
- when: {test: distinct_ratio, read: R1, start: 0, end: 25, expect: high}
|
|
38
|
+
weight: 2.0
|
|
39
|
+
- when: {test: distinct_ratio, read: R2, start: 0, end: 25, expect: high}
|
|
40
|
+
weight: 2.0
|
|
41
|
+
- when: {test: header_index, present: true} # real Illumina headers carry the sample index
|
|
42
|
+
weight: 0.5
|
|
43
|
+
excludes: []
|
|
44
|
+
|
|
45
|
+
backend:
|
|
46
|
+
module: map/star # plain STAR (no solo): bulk has no barcode/UMI demultiplex
|
|
47
|
+
params: {}
|
|
48
|
+
# EMPTY, and meaningfully so — not degenerate. Bulk paired-end RNA-seq has nothing byte-decided to
|
|
49
|
+
# pass: no barcode, no UMI, no whitelist, no offsets. Every knob that used to live here was on the
|
|
50
|
+
# wrong side of the parse/count line:
|
|
51
|
+
# - quantMode: GeneCounts -> COUNTING. Now processing.quantification (BulkQuant.mode).
|
|
52
|
+
# - outSAMtype: [BAM, Sorted..] -> an OUTPUT FORMAT: neither parse nor count. It is a module
|
|
53
|
+
# implementation detail, and the proof was already in this repo — starsolo.smk hardcoded
|
|
54
|
+
# `--outSAMtype BAM Unsorted` in its shell block while star.smk read the same knob from config.
|
|
55
|
+
# Two hand-written modules, two answers, one detail. star.smk now hardcodes it too.
|
|
56
|
+
#
|
|
57
|
+
# There is also no strandedness knob, and none is needed. This file used to promise that "library
|
|
58
|
+
# strandedness is resolved at compose from processing policy" — no code ever implemented it, because
|
|
59
|
+
# there was never a decision to make: `--quantMode GeneCounts` already emits ALL THREE strand columns
|
|
60
|
+
# in ReadsPerGene.out.tab. Same law as soloFeatures: when the aligner computes every alternative in
|
|
61
|
+
# one pass and the outputs are small, compute them all and let the consumer choose.
|
|
62
|
+
|
|
63
|
+
confusable_with:
|
|
64
|
+
- id: splitseq
|
|
65
|
+
relationship: processing_divergent
|
|
66
|
+
distinguishable_by: [onlist]
|
|
67
|
+
note: >
|
|
68
|
+
This entry is the GENERIC PAIRED-END FALLBACK: it requires two reads and forbids very little,
|
|
69
|
+
so at rungs 0-2 it accepts SPLiT-seq's cdna+bc pair as readily as real bulk data. Computed, not
|
|
70
|
+
assumed — `rung02_separable(bulk, splitseq)` is False, which is what forced this declaration.
|
|
71
|
+
The two are maximally divergent downstream (map/star vs map/starsolo: no barcodes at all vs
|
|
72
|
+
three rounds of them), so silently preferring the alphabetically-luckier entry would emit a
|
|
73
|
+
bulk gene-count matrix for a single-cell library and exit 0. Only the onlist separates them:
|
|
74
|
+
SPLiT-seq's round1/2/3 barcodes hit their whitelists at rung 3 and bulk has no whitelist to
|
|
75
|
+
hit, which is why the resolver reaches rung 3 here rather than deciding at rung 2.
|
|
76
|
+
- id: bd-rhapsody-wta
|
|
77
|
+
relationship: processing_divergent
|
|
78
|
+
distinguishable_by: [onlist]
|
|
79
|
+
note: >
|
|
80
|
+
Same story as SPLiT-seq: the generic paired-end fallback accepts BD Rhapsody's cdna+bc pair on
|
|
81
|
+
geometry alone (`rung02_separable(bulk, bd-rhapsody-wta)` is False), so silently preferring bulk
|
|
82
|
+
would emit a gene-count matrix for a single-cell library and exit 0. Only the onlist separates
|
|
83
|
+
them — BD's three CLS whitelists hit at rung 3, and bulk has none.
|
|
84
|
+
- id: bd-rhapsody-wta-enhanced-v1
|
|
85
|
+
relationship: processing_divergent
|
|
86
|
+
distinguishable_by: [onlist]
|
|
87
|
+
note: >
|
|
88
|
+
The BD Rhapsody Enhanced bead (v1, 96-plex). Identical story to the original bead: this fallback
|
|
89
|
+
requires only two reads, so it accepts the Enhanced cdna+bc pair on read-count alone. Enhanced
|
|
90
|
+
REJECTS bulk (its GTGA...GACA `requires` motif is absent from bulk cDNA), but the acceptance is
|
|
91
|
+
one-directional, so the edge is declared here. The three CLS whitelists hit at rung 3; bulk has none.
|
|
92
|
+
- id: bd-rhapsody-wta-enhanced-v2
|
|
93
|
+
relationship: processing_divergent
|
|
94
|
+
distinguishable_by: [onlist]
|
|
95
|
+
note: >
|
|
96
|
+
The BD Rhapsody Enhanced bead (v2, 384-plex) — same reasoning as `-enhanced-v1`. Separated at rung
|
|
97
|
+
3 by the 384 x 3 CLS whitelists (disjoint from both the 96 pools and from anything bulk could hit).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# SPLiT-seq (split-pool combinatorial barcoding)
|
|
2
|
+
|
|
3
|
+
A single-cell RNA-seq method that needs no special instrument. Instead of one droplet per cell, cells
|
|
4
|
+
are barcoded by **splitting and pooling** them through several rounds of labeling; after three rounds
|
|
5
|
+
each cell carries a unique combination of three barcodes.
|
|
6
|
+
|
|
7
|
+
This entry covers the **original published SPLiT-seq** (Rosenberg et al., *Science* 2018). Parse
|
|
8
|
+
Biosciences' **Evercode** is a separate commercial descendant with different linkers and barcodes — a
|
|
9
|
+
different chemistry, not covered here.
|
|
10
|
+
|
|
11
|
+
## How it's read
|
|
12
|
+
|
|
13
|
+
- **Read 1 = the cDNA** (the transcript).
|
|
14
|
+
- **Read 2 = the barcode read**: a 10 bp UMI, then three 8 bp round-barcodes separated by two fixed
|
|
15
|
+
30 bp linkers.
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
[10 bp UMI] [8 bp round-3] --linker1-- [8 bp round-2] --linker2-- [8 bp round-1]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
A cell's identity is the combination of its round-1, round-2, and round-3 barcodes; each round draws
|
|
22
|
+
from a list of ~96 barcodes.
|
|
23
|
+
|
|
24
|
+
## How seqforge tells it apart
|
|
25
|
+
|
|
26
|
+
Like BD Rhapsody, the **two fixed linker sequences at known positions** are the signature, and each
|
|
27
|
+
round-barcode matches its own list. The exact linker lengths matter: the original 2018 chemistry puts
|
|
28
|
+
round-1 at a different position than the later Parse chemistry, so a position copied from the wrong
|
|
29
|
+
source silently mismatches. seqforge pins the original layout from the paper's own oligos.
|
|
30
|
+
|
|
31
|
+
## Status: not yet ready for real data
|
|
32
|
+
|
|
33
|
+
SPLiT-seq is the pilot's generalization test — it exercises machinery the 10x entries don't (8 bp
|
|
34
|
+
barcodes instead of 16, a barcode split combinatorially across a read). Two things must land before
|
|
35
|
+
it can process real data:
|
|
36
|
+
|
|
37
|
+
- **The barcode lists must ship.** The entry names three round-barcode lists that aren't bundled yet.
|
|
38
|
+
- **The strand must be confirmed on real data.** It's derived from the paper's oligos and the authors'
|
|
39
|
+
own pipeline (both point the same way), but the honest state is that most pipelines never explicitly
|
|
40
|
+
chose the strand — they inherited a default. The decisive check is to run the paper's own data both
|
|
41
|
+
ways; the correct strand assigns far more reads.
|
|
42
|
+
|
|
43
|
+
Until then this entry is intentionally inert.
|
|
44
|
+
|
|
45
|
+
## References
|
|
46
|
+
|
|
47
|
+
Read structure and linker sequences pinned from
|
|
48
|
+
**[scg_lib_structs — SPLiT-seq](https://teichlab.github.io/scg_lib_structs/methods_html/SPLiT-seq.html)**
|
|
49
|
+
(Teichmann Lab, CC-BY) and independently reconstructed from the paper's oligo tables
|
|
50
|
+
([Rosenberg et al., *Science* 2018](https://doi.org/10.1126/science.aam8999)). The exact,
|
|
51
|
+
machine-readable definition seqforge uses lives in this entry's `spec.yaml`.
|