diff --git a/modules/nf-core/cellranger/multi/main.nf b/modules/nf-core/cellranger/multi/main.nf index 3cdad0da7a74..5f9d3a75a19e 100644 --- a/modules/nf-core/cellranger/multi/main.nf +++ b/modules/nf-core/cellranger/multi/main.nf @@ -6,12 +6,12 @@ process CELLRANGER_MULTI { input: val meta - tuple val(meta_gex) , path (gex_fastqs , stageAs: "fastqs/gex/fastq_???/*") - tuple val(meta_vdj) , path (vdj_fastqs , stageAs: "fastqs/vdj/fastq_???/*") - tuple val(meta_ab) , path (ab_fastqs , stageAs: "fastqs/ab/fastq_???/*") - tuple val(meta_beam) , path (beam_fastqs , stageAs: "fastqs/beam/fastq_???/*") - tuple val(meta_cmo) , path (cmo_fastqs , stageAs: "fastqs/cmo/fastq_???/*") - tuple val(meta_crispr) , path (crispr_fastqs, stageAs: "fastqs/crispr/fastq_???/*") + tuple val(meta2) , path (gex_fastqs , stageAs: "fastqs/gex/fastq_???/*") + tuple val(meta3) , path (vdj_fastqs , stageAs: "fastqs/vdj/fastq_???/*") + tuple val(meta4) , path (ab_fastqs , stageAs: "fastqs/ab/fastq_???/*") + tuple val(meta5) , path (beam_fastqs , stageAs: "fastqs/beam/fastq_???/*") + tuple val(meta6) , path (cmo_fastqs , stageAs: "fastqs/cmo/fastq_???/*") + tuple val(meta7) , path (crispr_fastqs, stageAs: "fastqs/crispr/fastq_???/*") path gex_reference , stageAs: "references/gex/*" path gex_frna_probeset , stageAs: "references/gex/probeset/*" path gex_targetpanel , stageAs: "references/gex/targetpanel/*" @@ -30,7 +30,7 @@ process CELLRANGER_MULTI { output: tuple val(meta), path("cellranger_multi_config.csv"), emit: config tuple val(meta), path("**/outs/**") , emit: outs - path "versions.yml" , emit: versions_cellranger, topic: versions + tuple val("${task.process}"), val('cellranger'), eval('cellranger --version | sed "s/.* //"'), emit: versions_cellranger, topic: versions when: task.ext.when == null || task.ext.when @@ -40,125 +40,138 @@ process CELLRANGER_MULTI { if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { error "CELLRANGER_MULTI module does not support Conda. Please use Docker / Singularity / Podman instead." } - // add mutually exclusive input checker - if ([ocm_barcodes, cmo_barcodes, frna_sampleinfo].count { input -> input } >= 2) { - error "The ocm barcodes; cmo barcodes and frna probes are mutually exclusive features. Please use only one per sample, or reach out in slack in case it is really intended." + + // Validate mutually exclusive barcode types + if ([ocm_barcodes, cmo_barcodes, frna_sampleinfo].findAll().size() >= 2) { + error "The ocm barcodes, cmo barcodes, and frna probes are mutually exclusive features. Please use only one per sample." + } + + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: meta.id + + // Determine which library types are present based on FASTQs and references + def has_gex = meta2 && gex_reference + def has_vdj = meta3 && vdj_reference + def has_ab = meta4 && fb_reference + def has_beam = meta5 && beam_control_panel + def has_cmo = meta6 && cmo_barcodes + def has_crispr = meta7 && fb_reference + def has_frna = gex_frna_probeset && frna_sampleinfo + def has_ocm = ocm_barcodes + + // Build [gene-expression] section + def gex_section = [] + if (has_gex) { + gex_section << '[gene-expression]' + gex_section << "reference,\$PWD/${gex_reference.name}" + if (gex_frna_probeset) gex_section << "probe-set,\$PWD/${gex_frna_probeset.name}" + + // GEX options from meta + def gex_has_opts = meta2?.options + def chemistry = gex_has_opts?.containsKey("chemistry") ? meta2.options["chemistry"] : "auto" + gex_section << "chemistry,${chemistry}" + + if (gex_has_opts?.containsKey("expect-cells")) { + gex_section << "expect-cells,${meta2.options["expect-cells"]}" + } + + def create_bam = gex_has_opts?.containsKey("create-bam") ? meta2.options["create-bam"] : "true" + gex_section << "create-bam,${create_bam}" + + if (gex_targetpanel) { + gex_section << "target-panel,\$PWD/${gex_targetpanel.name}" + } + } + + // Build [feature] section + def fb_section = [] + if (has_ab || has_crispr) { + fb_section << '[feature]' + fb_section << 'reference,\$PWD/fb_reference_copy.csv' + } + + // Build [vdj] section + def vdj_section = [] + if (has_vdj) { + vdj_section << '[vdj]' + vdj_section << "reference,\$PWD/${vdj_reference.name}" + if (vdj_primer_index) { + vdj_section << "inner-enrichment-primers,\$PWD/${vdj_primer_index.name}" + } } - args = task.ext.args ?: '' - prefix = task.ext.prefix ?: "${meta.id}" - force_include_frna = task.ext.force_include_frna ?: '' - - // if references + FASTQ are empty, then don't run corresponding analyses - // get names of references, if they exist - // empty reference channels (all under references/) can stage as "[]" when skipped by the workflow - // empty FASTQ channels stage as "fastqs" - gex_reference_name = gex_reference ? gex_reference.getName() : '' - gex_frna_probeset_name = gex_frna_probeset ? gex_frna_probeset.getName() : '' - gex_targetpanel_name = gex_targetpanel ? gex_targetpanel.getName() : '' - fb_reference_name = fb_reference ? fb_reference.getName() : '' - vdj_reference_name = vdj_reference ? vdj_reference.getName() : '' - cmo_reference_name = cmo_reference ? cmo_reference.getName() : '' - cmo_sample_assignment = cmo_barcode_assignment ? cmo_barcode_assignment.getName() : '' - beam_antigen_panel_name = beam_antigen_panel ? beam_antigen_panel.getName() : '' - - include_gex = gex_fastqs.first().getName() != 'fastqs' && gex_reference ? '[gene-expression]' : '' - include_vdj = vdj_fastqs.first().getName() != 'fastqs' && vdj_reference ? '[vdj]' : '' - include_beam = beam_fastqs.first().getName() != 'fastqs' && beam_control_panel ? '[antigen-specificity]' : '' - include_cmo = cmo_fastqs.first().getName() != 'fastqs' && cmo_barcodes ? '[samples]' : '' - include_fb = (ab_fastqs.first().getName() != 'fastqs' || crispr_fastqs.first().getName() != 'fastqs') && fb_reference ? '[feature]' : '' - include_frna = gex_frna_probeset_name && frna_sampleinfo ? '[samples]' : '' - include_ocm = ocm_barcodes ? '[samples]' : '' - - gex_reference_path = include_gex ? "reference,./${gex_reference_name}" : '' - fb_reference_path = include_fb ? "reference,./${fb_reference_name}" : '' - vdj_reference_path = include_vdj ? "reference,./${vdj_reference_name}" : '' - - // targeted GEX panel goes under GEX section, not its own - target_panel = gex_targetpanel_name != '' ? "target-panel,./$gex_targetpanel_name" : '' - - // fixed RNA reference (not sample info!) also goes under GEX section - frna_probeset = ( include_frna || force_include_frna ) && gex_frna_probeset_name != '' ? "probe-set,./$gex_frna_probeset_name" : '' - - // VDJ inner primer set - primer_index = vdj_primer_index ? "inner-enrichment-primers,./references/primers/${vdj_primer_index.getName()}" : '' - - // BEAM antigen list, remember that this is a Feature Barcode file - beam_antigen_csv = include_beam && beam_antigen_panel_name != '' ? "reference,./$beam_antigen_panel_name" : '' - - // pull CSV text from these reference panels - // these references get appended directly to config file - beam_csv_text = include_beam && beam_control_panel.size() > 0 ? beam_control_panel : '' - cmo_csv_text = include_cmo && cmo_barcodes.size() > 0 ? cmo_barcodes : '' - ocm_csv_text = include_ocm && ocm_barcodes.size() > 0 ? ocm_barcodes : '' - frna_csv_text = include_frna && frna_sampleinfo.size() > 0 ? frna_sampleinfo : '' - - // the feature barcodes section get options for either CRISPR or antibody capture assays - fb_options = ab_fastqs.first().getName() != 'fastqs' && meta_ab?.options ? meta_ab : - (crispr_fastqs.first().getName() != 'fastqs' && meta_crispr?.options ? meta_crispr : [:]) - - // collect options for each section - // these are pulled from the meta maps - gex_options_use = include_gex && meta_gex?.options ? 'true' : null - vdj_options_use = include_vdj && meta_vdj?.options ? 'true' : null - ab_options_use = include_fb && meta_ab?.options ? 'true' : null - beam_options_use = include_beam && meta_beam?.options ? 'true' : null - cmo_options_use = include_cmo && meta_cmo?.options ? 'true' : null - crispr_options_use = include_fb && meta_crispr?.options ? 'true' : null - fb_options_use = include_fb && fb_options?.options ? 'true' : null - - gex_options_filter_probes = gex_options_use && meta_gex.options.containsKey("filter-probes") ? "filter-probes,${meta_gex.options["filter-probes"]}" : '' - gex_options_r1_length = gex_options_use && meta_gex.options.containsKey("r1-length") ? "r1-length,${meta_gex.options["r1-length"]}" : '' - gex_options_r2_length = gex_options_use && meta_gex.options.containsKey("r2-length") ? "r2-length,${meta_gex.options["r2-length"]}" : '' - gex_options_chemistry = gex_options_use && meta_gex.options.containsKey("chemistry") ? "chemistry,${meta_gex.options["chemistry"]}" : '' - gex_options_expect_cells = gex_options_use && meta_gex.options.containsKey("expect-cells") ? "expect-cells,${meta_gex.options["expect-cells"]}" : '' - gex_options_force_cells = gex_options_use && meta_gex.options.containsKey("force-cells") ? "force-cells,${meta_gex.options["force-cells"]}" : '' - gex_options_no_secondary = gex_options_use && meta_gex.options.containsKey("no-secondary") ? "no-secondary,${meta_gex.options["no-secondary"]}" : '' - gex_options_no_bam = gex_options_use && meta_gex.options.containsKey("create-bam") ? "create-bam,${meta_gex.options["create-bam"]}" : '' - gex_options_no_target_umi_filter = gex_options_use && meta_gex.options.containsKey("no-target-umi-filter") ? "no-target-umi-filter,${meta_gex.options["no-target-umi-filter"]}" : '' - gex_options_include_introns = gex_options_use && meta_gex.options.containsKey("include-introns") ? "include-introns,${meta_gex.options["include-introns"]}" : '' - gex_options_check_library_compatibility = gex_options_use && meta_gex.options.containsKey("check-library-compatibility") ? "check-library-compatibility,${meta_gex.options["check-library-compatibility"]}" : '' - - cmo_reference_path = cmo_options_use && cmo_reference_name ? "cmo-set,./${cmo_reference_name}" : '' - cmo_barcode_path = cmo_options_use && cmo_sample_assignment ? "barcode-sample-assignment,./${cmo_sample_assignment}" : '' - cmo_options_min_assignment_confidence = cmo_options_use && meta_cmo.options.containsKey("min-assignment-confidence") ? "min-assignment-confidence,${meta_cmo.options["min-assignment-confidence"]}" : '' - - vdj_options_r1_length = vdj_options_use && meta_vdj.options.containsKey("r1-length") ? "r1-length,${meta_vdj.options["r1-length"]}" : '' - vdj_options_r2_length = vdj_options_use && meta_vdj.options.containsKey("r2-length") ? "r2-length,${meta_vdj.options["r2-length"]}" : '' - - fb_options_r1_length = fb_options_use && fb_options.options.containsKey("r1-length") ? "r1-length,${fb_options.options["r1-length"]}" : '' - fb_options_r2_length = fb_options_use && fb_options.options.containsKey("r2-length") ? "r2-length,${fb_options.options["r2-length"]}" : '' - - // point config to FASTQs - // After renaming it gets in 'fastq_all' folder - fastq_gex = include_gex ? "${meta_gex.id},./fastq_all/gex,,Gene Expression" : '' - fastq_vdj = include_vdj ? "${meta_vdj.id},./fastq_all/vdj,,VDJ" : '' - fastq_antibody = include_fb && ab_options_use ? "${meta_ab.id},./fastq_all/ab,,Antibody Capture" : '' - fastq_beam = include_beam ? "${meta_beam.id},./fastq_all/beam,,Antigen Capture" : '' - fastq_crispr = include_fb && crispr_options_use ? "${meta_crispr.id},./fastq_all/crispr,,CRISPR Guide Capture" : '' - fastq_cmo = include_cmo ? "${meta_cmo.id},./fastq_all/cmo,,Multiplexing Capture" : '' - - // name the config file - config = "cellranger_multi_config.csv" + // Build [libraries] section + def lib_section = ['[libraries]', 'fastq_id,fastqs,lanes,feature_types'] + if (has_gex) lib_section << "${meta2.id},\$PWD/fastq_all/gex,,Gene Expression" + if (has_vdj) lib_section << "${meta3.id},\$PWD/fastq_all/vdj,,VDJ" + if (has_ab) lib_section << "${meta4.id},\$PWD/fastq_all/ab,,Antibody Capture" + if (has_beam) lib_section << "${meta5.id},\$PWD/fastq_all/beam,,Antigen Capture" + if (has_crispr) lib_section << "${meta7.id},\$PWD/fastq_all/crispr,,CRISPR Guide Capture" + if (has_cmo) lib_section << "${meta6.id},\$PWD/fastq_all/cmo,,Multiplexing Capture" + + // Build config content by combining all sections + def config_lines = [] + config_lines.addAll(gex_section) + config_lines.addAll(fb_section) + config_lines.addAll(vdj_section) + config_lines.addAll(lib_section) + + // Append sample sections if present + if (has_cmo) { + config_lines << '[samples]' + config_lines << cmo_barcodes.text.trim() + } + if (has_frna) { + config_lines << '[samples]' + config_lines << frna_sampleinfo.text.trim() + } + if (has_ocm) { + config_lines << '[samples]' + config_lines << ocm_barcodes.text.trim() + } + def config_content = config_lines.findAll { line -> line }.join('\n ') """ - echo ${args} - echo ${gex_reference_path} ${fb_reference_path} ${vdj_reference_path} - echo ${target_panel} ${frna_probeset} ${primer_index} - echo ${beam_antigen_csv} ${beam_csv_text} ${cmo_csv_text} ${ocm_csv_text} ${frna_csv_text} - echo ${beam_options_use} ${gex_options_filter_probes} - echo ${gex_options_r1_length} ${gex_options_r2_length} - echo ${gex_options_chemistry} ${gex_options_expect_cells} ${gex_options_force_cells} - echo ${gex_options_no_secondary} ${gex_options_no_bam} ${gex_options_no_target_umi_filter} - echo ${gex_options_include_introns} ${gex_options_check_library_compatibility} - echo ${cmo_reference_path} ${cmo_barcode_path} ${cmo_options_min_assignment_confidence} - echo ${vdj_options_r1_length} ${vdj_options_r2_length} - echo ${fb_options_r1_length} ${fb_options_r2_length} - echo ${fastq_gex} ${fastq_vdj} ${fastq_antibody} ${fastq_beam} ${fastq_crispr} ${fastq_cmo} - echo ${config} + # + # Rename FASTQs to Cell Ranger naming convention + # Maintains R1/R2 pairing order by processing directories sequentially + # Output pattern: \${prefix}_S1_L001_R1_001.fastq.gz, L002_R1_001.fastq.gz, etc. + # + mkdir -p fastq_all/{gex,vdj,ab,beam,cmo,crispr} + + for modality in gex vdj ab beam cmo crispr; do + lane=1 + while IFS= read -r -d '' r1_dir && IFS= read -r -d '' r2_dir; do + r1=\$(find "\${r1_dir}" -maxdepth 1 -name "*_R1_*.fastq.gz" | head -1) + r2=\$(find "\${r2_dir}" -maxdepth 1 -name "*_R2_*.fastq.gz" | head -1) + + [ -z "\${r1}" ] || [ -z "\${r2}" ] && continue + + ln -sf "\$(readlink -f "\${r1}")" "fastq_all/\${modality}/${prefix}_S1_L\$(printf %03d \${lane})_R1_001.fastq.gz" + ln -sf "\$(readlink -f "\${r2}")" "fastq_all/\${modality}/${prefix}_S1_L\$(printf %03d \${lane})_R2_001.fastq.gz" + lane=\$((lane + 1)) + done < <(find fastqs/\${modality} -maxdepth 1 -type d -name "fastq_*" | sort | xargs -n1 printf '%s\\0') + done + + # + # Copy fb_reference to avoid symlink corruption + # Cell Ranger writes to this file during validation, which corrupts the symlinked original + # + if [ -n "${fb_reference}" ] && [ -f "${fb_reference}" ]; then + cp "${fb_reference}" "fb_reference_copy.csv" + fi + + cat > cellranger_multi_config.csv <<-CONFIG_EOF + ${config_content} + CONFIG_EOF + + cellranger multi \\ + --id=${prefix} \\ + --csv=cellranger_multi_config.csv \\ + --localcores=${task.cpus} \\ + --localmem=${task.memory.toGiga()} \\ + ${args} """ - template "cellranger_multi.py" - stub: prefix = task.ext.prefix ?: "${meta.id}" """ @@ -167,10 +180,5 @@ process CELLRANGER_MULTI { echo -n "" >> ${prefix}/outs/fake_file.txt touch cellranger_multi_config.csv echo -n "" >> cellranger_multi_config.csv - - cat <<-END_VERSIONS > versions.yml - "${task.process}": - cellranger: \$(echo \$( cellranger --version 2>&1) | sed 's/^.*[^0-9]\\([0-9]*\\.[0-9]*\\.[0-9]*\\).*\$/\\1/' ) - END_VERSIONS """ } diff --git a/modules/nf-core/cellranger/multi/meta.yml b/modules/nf-core/cellranger/multi/meta.yml index b969dbd0ca99..08267e07a066 100644 --- a/modules/nf-core/cellranger/multi/meta.yml +++ b/modules/nf-core/cellranger/multi/meta.yml @@ -1,8 +1,7 @@ name: "cellranger_multi" -description: Module to use Cell Ranger's pipelines to analyze sequencing data - produced from various Chromium technologies, including Single Cell Gene - Expression, Single Cell Immune Profiling, Feature Barcoding, and Cell - Multiplexing. +description: Module to use Cell Ranger's pipelines to analyze sequencing data produced + from various Chromium technologies, including Single Cell Gene Expression, Single + Cell Immune Profiling, Feature Barcoding, and Cell Multiplexing. keywords: - align - reference @@ -15,9 +14,9 @@ keywords: - crispr tools: - "cellranger": - description: Cell Ranger by 10x Genomics is a set of analysis pipelines that - process Chromium single-cell data to align reads, generate feature-barcode - matrices, perform clustering and other secondary analysis, and more. + description: Cell Ranger by 10x Genomics is a set of analysis pipelines that process + Chromium single-cell data to align reads, generate feature-barcode matrices, + perform clustering and other secondary analysis, and more. homepage: https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/what-is-cell-ranger documentation: https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/using/tutorial_cp tool_dev_url: https://support.10xgenomics.com/single-cell-gene-expression/software/pipelines/latest/using/tutorial_cp @@ -30,7 +29,7 @@ input: description: | Groovy Map containing sample information e.g. [ id:'test', single_end:false ] - - - meta_gex: + - - meta2: type: map description: | Groovy Map containing sample information @@ -39,8 +38,8 @@ input: description: FASTQ files pattern: "*.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - - - meta_vdj: + - edam: http://edamontology.org/format_3989 + - - meta3: type: map description: | Groovy Map containing sample information @@ -49,8 +48,8 @@ input: description: FASTQ files pattern: "*.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - - - meta_ab: + - edam: http://edamontology.org/format_3989 + - - meta4: type: map description: | Groovy Map containing sample information @@ -59,8 +58,8 @@ input: description: FASTQ files pattern: "*.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - - - meta_beam: + - edam: http://edamontology.org/format_3989 + - - meta5: type: map description: | Groovy Map containing sample information @@ -69,8 +68,8 @@ input: description: FASTQ files pattern: "*.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - - - meta_cmo: + - edam: http://edamontology.org/format_3989 + - - meta6: type: map description: | Groovy Map containing sample information @@ -79,8 +78,8 @@ input: description: FASTQ files pattern: "*.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - - - meta_crispr: + - edam: http://edamontology.org/format_3989 + - - meta7: type: map description: | Groovy Map containing sample information @@ -89,91 +88,88 @@ input: description: FASTQ files pattern: "*.fastq.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + - edam: http://edamontology.org/format_3989 - gex_reference: type: directory - description: Folder containing Cellranger gene expression reference. Can - also be a gzipped tarball + description: Folder containing Cellranger gene expression reference. Can also + be a gzipped tarball pattern: "*.tar.gz" - gex_frna_probeset: type: file - description: Fixed RNA profiling information containing custom probes in CSV - format + description: Fixed RNA profiling information containing custom probes in CSV format pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - gex_targetpanel: type: file - description: Declaration of the target panel for Targeted Gene Expression - analysis + description: Declaration of the target panel for Targeted Gene Expression analysis pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - vdj_reference: type: directory - description: Folder containing Cellranger V(D)J reference. Can also be a - gzipped tarball + description: Folder containing Cellranger V(D)J reference. Can also be a gzipped + tarball pattern: "*.tar.gz" - vdj_primer_index: type: file description: List of custom V(D)J inner enrichment primers pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - fb_reference: type: file - description: The Feature Barcodes used for reference in Feature Barcoding - Analysis + description: The Feature Barcodes used for reference in Feature Barcoding Analysis pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - beam_antigen_panel: type: file description: The BEAM manifest in Feature Barcode CSV format pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - beam_control_panel: type: file - description: The BEAM antigens set to control status, with corresponding MHC - alleles, in Feature Barcode CSV format + description: The BEAM antigens set to control status, with corresponding MHC alleles, + in Feature Barcode CSV format pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - cmo_reference: type: file - description: Path to a custom Cell Multiplexing CSV reference IDs, or the - `cmo-set` option in Cellranger + description: Path to a custom Cell Multiplexing CSV reference IDs, or the `cmo-set` + option in Cellranger pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - cmo_barcodes: type: file - description: A CSV file appended to the Cellranger multi config linking - samples to CMO IDs + description: A CSV file appended to the Cellranger multi config linking samples + to CMO IDs pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - cmo_barcode_assignment: type: file - description: A CSV file that specifies the barcode-sample assignment in Cell - Multiplexing analysis + description: A CSV file that specifies the barcode-sample assignment in Cell Multiplexing + analysis pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - frna_sampleinfo: type: file description: Sample information for fixed RNA analysis pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - ocm_barcodes: type: file - description: A CSV file appended to the Cellranger multi config linking - samples to OCM IDs + description: A CSV file appended to the Cellranger multi config linking samples + to OCM IDs pattern: "*.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 - skip_renaming: type: boolean description: Skip renaming @@ -187,7 +183,7 @@ output: description: The resolved Cellranger multi config used for analysis pattern: "cellranger_multi_config.csv" ontologies: - - edam: http://edamontology.org/format_3752 # CSV + - edam: http://edamontology.org/format_3752 outs: - - meta: type: map @@ -198,20 +194,26 @@ output: pattern: "${meta.id}/outs/*" ontologies: [] versions_cellranger: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - cellranger: + type: string + description: The name of the tool + - cellranger --version | sed "s/.* //": + type: eval + description: The expression to obtain the version of the tool topics: versions: - - versions.yml: - type: file - description: File containing software versions - pattern: "versions.yml" - ontologies: - - edam: http://edamontology.org/format_3750 # YAML + - - ${task.process}: + type: string + description: The name of the process + - cellranger: + type: string + description: The name of the tool + - cellranger --version | sed "s/.* //": + type: eval + description: The expression to obtain the version of the tool authors: - "@klkeys" maintainers: diff --git a/modules/nf-core/cellranger/multi/tests/main.nf.test b/modules/nf-core/cellranger/multi/tests/main.nf.test index 381da3509087..0f61a2501ef4 100644 --- a/modules/nf-core/cellranger/multi/tests/main.nf.test +++ b/modules/nf-core/cellranger/multi/tests/main.nf.test @@ -164,21 +164,15 @@ nextflow_process { /*** end stage VDJ reference ***/ /*******************************/ - - // make an empty dummy file, for FASTQs - empty_file = file("$workDir/EMPTY") - empty_file.append("") - - // create empty channels to fill unused cellranger multi arguments // fastqs need a [ meta, ref ] structure // references just need a path - ch_gex_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_vdj_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_ab_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_beam_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_cmo_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_crispr_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) + ch_gex_fastqs = [ [:], [] ] + ch_vdj_fastqs = [ [:], [] ] + ch_ab_fastqs = [ [:], [] ] + ch_beam_fastqs = [ [:], [] ] + ch_cmo_fastqs = [ [:], [] ] + ch_crispr_fastqs = [ [:], [] ] ch_gex_frna_probeset = [] ch_gex_targetpanel = [] ch_vdj_primer_index = [] @@ -391,21 +385,15 @@ nextflow_process { /*** end stage VDJ reference ***/ /*******************************/ - - // make an empty dummy file, for FASTQs - empty_file = file("$workDir/EMPTY") - empty_file.append("") - - // create empty channels to fill unused cellranger multi arguments // fastqs need a [ meta, ref ] structure // references just need a path - ch_gex_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_vdj_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_ab_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_beam_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_cmo_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_crispr_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) + ch_gex_fastqs = [ [:], [] ] + ch_vdj_fastqs = [ [:], [] ] + ch_ab_fastqs = [ [:], [] ] + ch_beam_fastqs = [ [:], [] ] + ch_cmo_fastqs = [ [:], [] ] + ch_crispr_fastqs = [ [:], [] ] ch_gex_frna_probeset = [] ch_gex_targetpanel = [] ch_vdj_primer_index = [] @@ -633,21 +621,15 @@ nextflow_process { /*** end stage VDJ reference ***/ /*******************************/ - - // make an empty dummy file, for FASTQs - empty_file = file("$workDir/EMPTY") - empty_file.append("") - - // create empty channels to fill unused cellranger multi arguments // fastqs need a [ meta, ref ] structure // references just need a path - ch_gex_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_vdj_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_ab_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_beam_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_cmo_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_crispr_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) + ch_gex_fastqs = [ [:], [] ] + ch_vdj_fastqs = [ [:], [] ] + ch_ab_fastqs = [ [:], [] ] + ch_beam_fastqs = [ [:], [] ] + ch_cmo_fastqs = [ [:], [] ] + ch_crispr_fastqs = [ [:], [] ] ch_gex_frna_probeset = [] ch_gex_targetpanel = [] ch_vdj_primer_index = [] @@ -794,19 +776,15 @@ nextflow_process { /*** end stage 5k A549 data ***/ /*******************************/ - // make an empty dummy file, for FASTQs - empty_file = file("$workDir/EMPTY") - empty_file.append("") - // create empty channels to fill unused cellranger multi arguments // fastqs need a [ meta, ref ] structure // references just need a path - ch_gex_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_vdj_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_ab_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_beam_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_cmo_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_crispr_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) + ch_gex_fastqs = [ [:], [] ] + ch_vdj_fastqs = [ [:], [] ] + ch_ab_fastqs = [ [:], [] ] + ch_beam_fastqs = [ [:], [] ] + ch_cmo_fastqs = [ [:], [] ] + ch_crispr_fastqs = [ [:], [] ] ch_gex_frna_probeset = [] ch_gex_targetpanel = [] ch_vdj_reference = [] @@ -869,7 +847,6 @@ nextflow_process { process.out.outs[0][1].findAll { file(it).name == 'raw_feature_bc_matrix.h5' }, process.out.outs[0][1].findAll { file(it).name == 'sample_filtered_feature_bc_matrix.h5' }, process.out.outs[0][1].findAll { file(it).name == 'protospacer_calls_per_cell.csv' }, - process.out.outs[0][1].findAll { file(it).name == 'perturbation_efficiencies_by_feature.csv' } ).match() }, { assert snapshot(process.out.versions_cellranger).match("versions-a549-crispr") } ) @@ -879,8 +856,6 @@ nextflow_process { } test("cellranger - multi - 10k - kidney - flex - singleplex") { - config "./singleplex_flex.config" - when { process { """ @@ -918,20 +893,15 @@ nextflow_process { probeset = file(params.modules_testdata_base_path + 'genomics/homo_sapiens/10xgenomics/cellranger/references/flex/Chromium_Human_Transcriptome_Probe_Set_v1.1.0_GRCh38-2024-A.chr22.csv', checkIfExists: true) - // make an empty dummy file, for FASTQs - empty_file = file("$workDir/EMPTY") - empty_file.append("") - - // create empty channels to fill unused cellranger multi arguments // fastqs need a [ meta, ref ] structure // references just need a path - ch_gex_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_vdj_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_ab_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_beam_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_cmo_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) - ch_crispr_fastqs = Channel.value( [ [ id:"EMPTY", options:[] ], empty_file ] ) + ch_gex_fastqs = [ [:], [] ] + ch_vdj_fastqs = [ [:], [] ] + ch_ab_fastqs = [ [:], [] ] + ch_beam_fastqs = [ [:], [] ] + ch_cmo_fastqs = [ [:], [] ] + ch_crispr_fastqs = [ [:], [] ] ch_gex_frna_probeset = [] ch_gex_targetpanel = [] ch_vdj_reference = [] diff --git a/modules/nf-core/cellranger/multi/tests/main.nf.test.snap b/modules/nf-core/cellranger/multi/tests/main.nf.test.snap index 69e4cd30dcb8..d8bd4eba21ea 100644 --- a/modules/nf-core/cellranger/multi/tests/main.nf.test.snap +++ b/modules/nf-core/cellranger/multi/tests/main.nf.test.snap @@ -2,14 +2,18 @@ "versions-flex-singleplex": { "content": [ [ - "versions.yml:md5,1e16f7d40ef563f7d0a24f8944374d4d" + [ + "CELLRANGER_MULTI", + "cellranger", + "10.0.0" + ] ] ], - "timestamp": "2026-03-16T17:20:25.065276862", "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.2", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-27T11:26:36.625032" }, "cellranger - multi - 10k - PBMC": { "content": [ @@ -34,23 +38,27 @@ "reference.json:md5,384f6efabad59f6da5c89b862aee71a8" ] ], - "timestamp": "2026-03-13T15:20:21.751016877", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-13T15:20:21.751016877" }, "versions-PBMC": { "content": [ [ - "versions.yml:md5,1e16f7d40ef563f7d0a24f8944374d4d" + [ + "CELLRANGER_MULTI", + "cellranger", + "10.0.0" + ] ] ], - "timestamp": "2026-03-13T15:20:21.797381186", "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.2", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-26T15:07:19.461509" }, "cellranger - multi - 10k - PBMC - with cmo": { "content": [ @@ -75,11 +83,11 @@ "reference.json:md5,384f6efabad59f6da5c89b862aee71a8" ] ], - "timestamp": "2026-03-13T15:21:51.02923865", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-13T15:21:51.02923865" }, "cellranger - multi - 10k - kidney - flex - singleplex": { "content": [ @@ -99,28 +107,32 @@ "sample_raw_feature_bc_matrix.h5:md5,45c0a4f2907c78b3aca295d0623e2163" ] ], - "timestamp": "2026-03-13T15:26:14.797582185", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-13T15:26:14.797582185" }, "versions-with-cmo": { "content": [ [ - "versions.yml:md5,1e16f7d40ef563f7d0a24f8944374d4d" + [ + "CELLRANGER_MULTI", + "cellranger", + "10.0.0" + ] ] ], - "timestamp": "2026-03-13T15:21:51.055006548", "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.2", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-26T15:21:12.016031" }, "cellranger - multi - 5k - a549 - sc3 v3 - gex + crispr": { "content": [ [ - "metrics_summary.csv:md5,a51dcadefdd5b76cee5c3d4340181a5a" + "metrics_summary.csv:md5,48b4fda512d9dba89c847207831ecdf3" ], [ "raw_feature_bc_matrix.h5:md5,01c558f6a5b96cd40b1ed41217164460" @@ -129,41 +141,46 @@ "sample_filtered_feature_bc_matrix.h5:md5,8903d36c96c4de869eba434c4722817d" ], [ - - ], - [ - + "protospacer_calls_per_cell.csv:md5,a94184bddcd8107421f62986b9e0984a" ] ], - "timestamp": "2026-03-13T15:24:54.664342753", "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.2", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-27T11:24:33.951852" }, "versions-a549-crispr": { "content": [ [ - "versions.yml:md5,1e16f7d40ef563f7d0a24f8944374d4d" + [ + "CELLRANGER_MULTI", + "cellranger", + "10.0.0" + ] ] ], - "timestamp": "2026-03-13T15:24:54.695962129", "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.2", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-27T11:24:33.96149" }, "versions-with-vdj": { "content": [ [ - "versions.yml:md5,1e16f7d40ef563f7d0a24f8944374d4d" + [ + "CELLRANGER_MULTI", + "cellranger", + "10.0.0" + ] ] ], - "timestamp": "2026-03-13T15:23:20.241947226", "meta": { - "nf-test": "0.9.4", + "nf-test": "0.9.2", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-26T15:28:10.710509" }, "cellranger - multi - 10k - PBMC - with vdj": { "content": [ @@ -188,10 +205,10 @@ "reference.json:md5,384f6efabad59f6da5c89b862aee71a8" ] ], - "timestamp": "2026-03-13T15:23:20.211799407", "meta": { "nf-test": "0.9.4", "nextflow": "25.10.4" - } + }, + "timestamp": "2026-03-13T15:23:20.211799407" } } \ No newline at end of file diff --git a/modules/nf-core/cellranger/multi/tests/singleplex_flex.config b/modules/nf-core/cellranger/multi/tests/singleplex_flex.config deleted file mode 100644 index 71402dd5998c..000000000000 --- a/modules/nf-core/cellranger/multi/tests/singleplex_flex.config +++ /dev/null @@ -1,8 +0,0 @@ -process { - - withName: CELLRANGER_MULTI { - stageInMode = 'copy' - ext.force_include_frna = true - } - -}