Skip to content

feat(simpleaf): add simpleaf/multiplexquant module#11724

Open
an-altosian wants to merge 2 commits into
nf-core:masterfrom
an-altosian:feat/simpleaf-multiplexquant
Open

feat(simpleaf): add simpleaf/multiplexquant module#11724
an-altosian wants to merge 2 commits into
nf-core:masterfrom
an-altosian:feat/simpleaf-multiplexquant

Conversation

@an-altosian
Copy link
Copy Markdown
Contributor

Summary

Adds a new simpleaf/multiplexquant module wrapping simpleaf multiplex-quant for sample-multiplexed single-cell libraries (10x Chromium Fixed RNA Profiling / Flex). End-to-end: auto-resolves probe set + sample-BC TSV from a chemistry preset, optionally builds a piscem probe index, maps reads with piscem map-sc, performs hierarchical cell-BC + sample-BC correction, collates, and quantifies — emitting barcodes prefixed by demultiplexed sample name.

  • Module follows current nf-core conventions: Seqera Wave container, topic-channel versions output (alevin-fry, piscem, simpleaf), process_medium label, stub block, meta-merge across input channels.
  • Four input channels: (meta, chemistry, reads), (meta2, index, t2g_map), (meta3, probe_set, sample_bc_list, cell_bc_list), resolution. The middle two channels are fully optional ([] for any element) — empty inputs fall back to chemistry-preset auto-resolution.
  • simpleaf 0.25.0 / piscem 0.20.0 / alevin-fry 0.15.0 via community.wave.seqera.io/library/simpleaf:0.25.0--b9f96d8b71a01864.

Validation

  • nf-test: flex - auto (end-to-end via Wave container) and flex - auto - stub pass locally on Docker.
  • Real-data validation: ran against an internal 10x GEM-X Flex v2 mouse library (466M reads → 98.10% mapping → 36,859 cells across the expected sample-BC wells), matching cellranger output.

Test plan

an-altosian and others added 2 commits May 20, 2026 20:42
New module wrapping `simpleaf multiplex-quant` for sample-multiplexed single-cell
libraries (10x Chromium Fixed RNA Profiling / Flex). The subcommand auto-resolves
probe set + sample-BC TSV + cell-BC whitelist from the chemistry preset
(e.g. `10x-flexv1-gex-3p` + `--organism human`), builds a piscem probe index when
one is not supplied, maps reads, performs hierarchical cell+sample barcode
correction, collates, and quantifies — emitting a count matrix whose barcodes
are prefixed with the demultiplexed sample name.

- Inputs: reads + chemistry, optional pre-built index + t2g, optional probe-set
  / sample-BC TSV / cell-BC whitelist overrides, resolution mode.
- Outputs: af_map, af_quant, h5ad (optional), probe_t2g.tsv (optional),
  auto-built probe_index (optional), per-tool topic-channel versions for
  alevin-fry / piscem / simpleaf.
- Container: Seqera Wave simpleaf 0.25.0 (bundles alevin-fry 0.15.0,
  piscem 0.20.0). Matches the simpleaf/index and simpleaf/quant modules
  on the parallel Wave-migration branch.

Tests:
- Real test using auto-resolution path with the singleplex Flex Kidney FASTQs
  from nf-core/test-datasets (chr22 subset).
- Stub test exercising channel shape.

nf-core modules lint: 0 failures.
tuple val(meta), path("${prefix}/probe_index/index") , emit: probe_index, optional: true
tuple val("${task.process}"), val('alevin-fry'), eval("alevin-fry --version | sed 's/alevin-fry //'"), topic: versions, emit: versions_alevin_fry
tuple val("${task.process}"), val('piscem'), eval("piscem --version | sed 's/piscem //'"), topic: versions, emit: versions_piscem
tuple val("${task.process}"), val('simpleaf'), eval("ALEVIN_FRY_HOME=. simpleaf --version | sed 's/simpleaf //'"), topic: versions, emit: versions_simpleaf
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the ALEVIN_FRY_HOME environment variable should be inherited by this part as well.

Suggested change
tuple val("${task.process}"), val('simpleaf'), eval("ALEVIN_FRY_HOME=. simpleaf --version | sed 's/simpleaf //'"), topic: versions, emit: versions_simpleaf
tuple val("${task.process}"), val('simpleaf'), eval("simpleaf --version | sed 's/simpleaf //'"), topic: versions, emit: versions_simpleaf

Comment on lines +77 to +101
// `simpleaf multiplex-quant` requires both reads and a chemistry preset (or, with extra
// ext.args, a --geometry override + --cell-bc-list). Only the mainstream case is enforced
// here; non-default geometries can still be set via ext.args.
def mappingArgs(chemistry, reads) {
if (!reads) error "Missing read files; could not proceed."
if (!chemistry) error "Missing chemistry; could not proceed."

def (forward, reverse) = reads.collate(2).transpose()
return """--chemistry ${chemistry} \\
--reads1 ${forward.join(',')} \\
--reads2 ${reverse.join(',')}"""
}

// Build optional reference-override flags. With none of these set, simpleaf auto-downloads
// a probe set + sample BC TSV based on the chemistry preset and (if also provided in ext.args)
// `--organism`. Any combination of overrides is allowed.
def referenceArgs(index, probe_set, sample_bc_list, cell_bc_list, t2g_map) {
def parts = []
if (index) parts << "--index ${index}"
if (probe_set) parts << "--probe-set ${probe_set}"
if (sample_bc_list) parts << "--sample-bc-list ${sample_bc_list}"
if (cell_bc_list) parts << "--cell-bc-list ${cell_bc_list}"
if (t2g_map) parts << "--t2g-map ${t2g_map}"
return parts.join(' \\\n ')
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very non-standard, compared to just doing them one at a time.

def mapping_args = mappingArgs(chemistry, reads)
def reference_args = referenceArgs(index, probe_set, sample_bc_list, cell_bc_list, t2g_map)

meta = meta2 + meta3 + meta
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you doing this? We just take the first meta. I think this is pipeline-specific.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants