From 152259df8fc862036b8f00e74ccc234b0dcef367 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Tue, 16 Jun 2026 21:41:03 +0100 Subject: [PATCH 01/24] Create angsd/dosaf process --- modules/nf-core/angsd/dosaf/main.nf | 154 ++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 modules/nf-core/angsd/dosaf/main.nf diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf new file mode 100644 index 000000000000..1bd435eb520f --- /dev/null +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -0,0 +1,154 @@ +process ANGSD_DOSAF { + tag "$meta.id" + label 'process_medium' + + conda "${moduleDir}/environment.yml" + container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ? + 'https://depot.galaxyproject.org/singularity/angsd:0.940--h13024bc_4': + 'quay.io/biocontainers/angsd:0.940--h13024bc_4' }" + + input: + tuple val(meta), path(bams), path(bam_indices) + tuple val(meta2), path(reference_fasta), path(reference_fai) + tuple val(meta3), path(ancestral_fasta), path(ancestral_fai) // Optional. Provides ancestral state for unfolded SFS. + tuple val(meta4), path(error_file) // Optional. Required for SYK model (-GL 4) only. + tuple val(meta5), path(inbreeding_coefficients) // Optional. Required for -doSAF 2 (inbreeding-aware mode). + + output: + tuple val(meta), path("*.saf.idx"), path("*.saf.pos.gz"), path("*.saf.gz"), emit: saf + tuple val("${task.process}"), val('angsd'), eval("angsd 2>&1 | sed '1!d;s/.*version: //;s/ .*//'"), emit: versions_angsd, topic: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + + // Validate GL model + def gl_model = args.contains("-GL 1") ? 1 : + args.contains("-GL 2") ? 2 : + args.contains("-GL 3") ? 3 : + args.contains("-GL 4") ? 4 : 0 + if (gl_model == 0) { + error( + "ANGSD_DOSAF: No valid GL model selected. Please specify one of: -GL 1, -GL 2, -GL 3, or -GL 4 in ext.args." + ) + } + + // Validate doSAF mode + def dosaf_mode = args.contains("-doSAF 1") ? 1 : + args.contains("-doSAF 2") ? 2 : 0 + if (dosaf_mode == 0) { + error( + "ANGSD_DOSAF: No valid doSAF mode selected. Please specify -doSAF 1 or -doSAF 2 in ext.args." + ) + } + + // Validate doSAF 2 has inbreeding coefficients + if (dosaf_mode == 2 && !inbreeding_coefficients) { + error( + "ANGSD_DOSAF: -doSAF 2 requires inbreeding coefficients (indF). Please supply an inbreeding_coefficients file." + ) + } + + // Validate GL 4 has error file + if (gl_model == 4 && !error_file) { + error( + "ANGSD_DOSAF: -GL 4 (SYK model) requires an error file. Please supply an error_file." + ) + } + + // Compute -minInd dynamically as a fraction of the population's BAM list size + def frac = (task.ext.args2 ?: '0.5') as Double + def n_samples = bams instanceof List ? bams.size() : 1 + def min_ind_arg = frac > 0 ? "-minInd ${Math.ceil(n_samples * frac).toInteger()}" : '' + + // Touch fai indices to ensure they are newer than their fasta (ANGSD requirement) + def touch_ref = reference_fai ? "sleep 1 && touch ${reference_fai}" : '' + def touch_anc = ancestral_fai ? "sleep 1 && touch ${ancestral_fai}" : '' + + // Reference / ancestral args. + // If ancestral_fasta supplied: use as -anc and pass reference as -ref. + // If not supplied: use reference as -anc and -ref (suitable for folded SFS via realSFS -fold 1). + def ref = ancestral_fasta ? "-anc ${ancestral_fasta} -ref ${reference_fasta}" : "-anc ${reference_fasta} -ref ${reference_fasta}" + + // Optional args + def indF_arg = inbreeding_coefficients ? "-indF ${inbreeding_coefficients}" : "" + def errors_arg = error_file ? "-errors ${error_file}" : "" + + // Shared preamble + def preamble = """ + ${touch_ref} + ${touch_anc} + printf '%s\\n' ${bams} > bamlist.txt + """ + + if (gl_model == 3) { + // SOAPsnp requires a two-step process: + // 1. Calibration step with -minQ 0 to generate the calibration matrix in angsd_tmpdir/ + // 2. doSAF step using the calibration matrix + // -GL 3 is hardcoded in the calibration step to avoid passing all other args + """ + ${preamble} + + angsd \\ + -nThreads ${task.cpus} \\ + -bam bamlist.txt \\ + -minQ 0 \\ + -GL 3 \\ + -ref ${reference_fasta} \\ + -out ${prefix} + + angsd \\ + -nThreads ${task.cpus} \\ + -bam bamlist.txt \\ + ${ref} \\ + ${indF_arg} \\ + ${args} \\ + ${min_ind_arg} \\ + -out ${prefix} + """ + + } else if (gl_model == 4) { + // SYK model requires an error file and -doCounts 1 + """ + ${preamble} + + angsd \\ + -nThreads ${task.cpus} \\ + -bam bamlist.txt \\ + ${ref} \\ + ${indF_arg} \\ + ${errors_arg} \\ + -doCounts 1 \\ + ${args} \\ + ${min_ind_arg} \\ + -out ${prefix} + """ + + } else { + // GL 1 (SAMtools) or GL 2 (GATK) - single angsd call + """ + ${preamble} + + angsd \\ + -nThreads ${task.cpus} \\ + -bam bamlist.txt \\ + ${ref} \\ + ${indF_arg} \\ + ${args} \\ + ${min_ind_arg} \\ + -out ${prefix} + """ + } + + stub: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + """ + touch ${prefix}.saf.idx + echo "" | gzip > ${prefix}.saf.pos.gz + echo "" | gzip > ${prefix}.saf.gz + """ +} From fa308b751a02a9b06e924c8a1cef1f890600561f Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Fri, 19 Jun 2026 13:59:24 +0100 Subject: [PATCH 02/24] Update default value for minInd fraction to match angsd default --- modules/nf-core/angsd/dosaf/main.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index 1bd435eb520f..f519b22c6ada 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -60,7 +60,8 @@ process ANGSD_DOSAF { } // Compute -minInd dynamically as a fraction of the population's BAM list size - def frac = (task.ext.args2 ?: '0.5') as Double + // Default set to 0 as this mimics angsd default for minInd + def frac = (task.ext.args2 ?: '0') as Double def n_samples = bams instanceof List ? bams.size() : 1 def min_ind_arg = frac > 0 ? "-minInd ${Math.ceil(n_samples * frac).toInteger()}" : '' From f3e3c24777095a9b128c7b8b2fe57d2019b545d0 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Wed, 24 Jun 2026 22:45:54 +0100 Subject: [PATCH 03/24] Update stub --- modules/nf-core/angsd/dosaf/main.nf | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index f519b22c6ada..056c4d030657 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -145,7 +145,6 @@ process ANGSD_DOSAF { } stub: - def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" """ touch ${prefix}.saf.idx From 3a4f54530f70da9769e0b30e79192501ebe3c16b Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Wed, 24 Jun 2026 22:49:23 +0100 Subject: [PATCH 04/24] Add tests for angsd/dosaf --- .../nf-core/angsd/dosaf/tests/main.nf.test | 475 ++++++++++++++++++ .../nf-core/angsd/dosaf/tests/nextflow.config | 6 + 2 files changed, 481 insertions(+) create mode 100644 modules/nf-core/angsd/dosaf/tests/main.nf.test create mode 100644 modules/nf-core/angsd/dosaf/tests/nextflow.config diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test b/modules/nf-core/angsd/dosaf/tests/main.nf.test new file mode 100644 index 000000000000..962f46ebabaa --- /dev/null +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test @@ -0,0 +1,475 @@ +nextflow_process { + + name "Test Process ANGSD_DOSAF" + script "../main.nf" + process "ANGSD_DOSAF" + + tag "modules" + tag "modules_nfcore" + tag "angsd" + tag "angsd/dosaf" + + + // ------------------------------------------------------------------------- + // SUCCESS CASE 1: GL 1; doSAF 1; no ancestral + // ------------------------------------------------------------------------- + + test("angsd - GL 1 - doSAF 1") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 1 -doSAF 1' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.saf }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + + // ------------------------------------------------------------------------- + // SUCCESS CASE 2: GL 3; doSAF 1; no ancestral + // ------------------------------------------------------------------------- + + test("angsd - GL3 - two steps") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 3 -doSAF 1' + min_ind_frac = 0 + } + + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.saf }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + + // ------------------------------------------------------------------------- + // SUCCESS CASE 3: GL 4 (requires error file) + // ------------------------------------------------------------------------- + + test("angsd - GL4") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 4 -doSAF 1' + min_ind_frac = 0 + } + + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ + [ id: 'errors' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/resources/angsd/angsd_syk.errors') + ] + input[4] = [ [], [] ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.saf }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + + // ------------------------------------------------------------------------- + // FAILURE CASE 1: Missing inbreeding coefficients file (needed for doSAF 2) + // ------------------------------------------------------------------------- + + test("angsd - GL1 - doSAF2 - missing inbreeding coefficients") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 1 -doSAF 2' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + def caused = process.errorReport + .split("Source block:")[0] + .split("Caused by:")[1] + .trim() + + assertAll( + { assert process.failed }, + { assert caused.contains("-doSAF 2 requires inbreeding coefficients") } + ) + } + } + + + // ------------------------------------------------------------------------- + // FAILURE CASE 2: Missing doSAF flag + // ------------------------------------------------------------------------- + + test("angsd - missing -doSAF flag") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 1' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + def caused = process.errorReport + .split("Source block:")[0] + .split("Caused by:")[1] + .trim() + + assertAll( + { assert process.failed }, + { assert caused.contains("No valid doSAF mode selected") } + ) + } + } + + + // ------------------------------------------------------------------------- + // FAILURE CASE 3: Missing GL flag + // ------------------------------------------------------------------------- + + test("angsd - missing -GL flag") { + config "./nextflow.config" + + when { + params { + angsd_args = '-doSAF 1' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + def caused = process.errorReport + .split("Source block:")[0] + .split("Caused by:")[1] + .trim() + + assertAll( + { assert process.failed }, + { assert caused.contains("No valid GL model selected") } + ) + } + } + + + // ------------------------------------------------------------------------- + // FAILURE CASE 4: Invalid GL value + // ------------------------------------------------------------------------- + + test("angsd - invalid -GL value") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 5 -doSAF 1' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + def caused = process.errorReport + .split("Source block:")[0] + .split("Caused by:")[1] + .trim() + + assertAll( + { assert process.failed }, + { assert caused.contains("No valid GL model selected") } + ) + } + } + + + // ------------------------------------------------------------------------- + // FAILURE CASE 5: Missing error file (required by -GL 4) + // ------------------------------------------------------------------------- + + test("angsd - GL4 - missing error file") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 4 -doSAF 1' + min_ind_frac = 0 + } + process {""" + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """} + } + + then { + def caused = process.errorReport + .split("Source block:")[0] + .split("Caused by:")[1] + .trim() + + assertAll( + { assert process.failed }, + { assert caused.contains("-GL 4 (SYK model) requires an error file") } + ) + } + } + +} diff --git a/modules/nf-core/angsd/dosaf/tests/nextflow.config b/modules/nf-core/angsd/dosaf/tests/nextflow.config new file mode 100644 index 000000000000..3d058758fcf0 --- /dev/null +++ b/modules/nf-core/angsd/dosaf/tests/nextflow.config @@ -0,0 +1,6 @@ +process { + withName: ANGSD_DOSAF { + ext.args = params.angsd_args + ext.args2 = params.min_ind_frac + } +} From c4174299976a5e9db71856d102ce8b56e10f5504 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Thu, 25 Jun 2026 20:59:15 +0100 Subject: [PATCH 05/24] Add environment configuration for angsd/dosaf --- modules/nf-core/angsd/dosaf/environment.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 modules/nf-core/angsd/dosaf/environment.yml diff --git a/modules/nf-core/angsd/dosaf/environment.yml b/modules/nf-core/angsd/dosaf/environment.yml new file mode 100644 index 000000000000..8700495b8876 --- /dev/null +++ b/modules/nf-core/angsd/dosaf/environment.yml @@ -0,0 +1,8 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json +channels: + - conda-forge + - bioconda +dependencies: + - bioconda::angsd=0.940 + - bioconda::htslib=1.23.1 From 9858417213e6529aaf0ba7ad37d3f4723a831335 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Thu, 25 Jun 2026 21:00:59 +0100 Subject: [PATCH 06/24] Add test snapshot for angsd/dosaf --- .../angsd/dosaf/tests/main.nf.test.snap | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 modules/nf-core/angsd/dosaf/tests/main.nf.test.snap diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap new file mode 100644 index 000000000000..a4310c4e3376 --- /dev/null +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap @@ -0,0 +1,177 @@ +{ + "angsd - GL1 - doSAF1 - no anc": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", + "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", + "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-06-19T15:53:53.808325", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "angsd - GL 1 - doSAF 1": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", + "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", + "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-06-24T22:38:48.132228", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "angsd - GL3 - two steps": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", + "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", + "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-06-24T22:41:04.740319", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "angsd - GL 1 - doSAF 1 - no anc": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", + "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", + "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-06-22T16:32:30.375434", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "angsd - GL4": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", + "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", + "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-06-24T22:44:08.314653", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + } +} \ No newline at end of file From b604f0e1377628232f6f7a6fd0f1c997a9c16bdf Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 28 Jun 2026 12:46:36 +0100 Subject: [PATCH 07/24] Add meta configuration for angsd_dosaf module --- modules/nf-core/angsd/dosaf/meta.yml | 126 +++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 modules/nf-core/angsd/dosaf/meta.yml diff --git a/modules/nf-core/angsd/dosaf/meta.yml b/modules/nf-core/angsd/dosaf/meta.yml new file mode 100644 index 000000000000..551a00b566df --- /dev/null +++ b/modules/nf-core/angsd/dosaf/meta.yml @@ -0,0 +1,126 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json +name: "angsd_dosaf" +description: Estimate site allele frequencies from BAM files. +keywords: + - angsd + - genotype likelihood + - genomics +tools: + - "angsd": + description: "ANGSD: Analysis of next generation Sequencing Data" + homepage: "http://www.popgen.dk/angsd/" + documentation: "http://www.popgen.dk/angsd/" + tool_dev_url: "https://github.com/ANGSD/angsd" + doi: "10.1186/s12859-014-0356-4" + licence: ["GPL v3", "MIT"] + identifier: biotools:angsd +input: + - - meta: + type: map + description: | + Groovy Map containing population information + e.g. [ id:'test', population:'population id', samples:'sample IDs' ] + - bam: + type: file + description: A list of BAM or CRAM files + pattern: "*.{bam,cram}" + ontologies: + - edam: "http://edamontology.org/format_2572" # BAM + - edam: "http://edamontology.org/format_3462" # CRAM + - bai: + type: file + description: A list of BAM or CRAM indices + pattern: "*.{bam.bai,cram.crai}" + ontologies: + - edam: "http://edamontology.org/format_3327" # BAI + - edam: "http://edamontology.org/format_3462" # CRAM (no dedicated CRAI term in EDAM) + - - meta2: + type: map + description: | + Groovy Map containing reference information + e.g. [ id:'test' ] + - fasta: + type: file + description: A reference genome in FASTA format + pattern: "*.fasta" + ontologies: + - edam: "http://edamontology.org/format_1929" # FASTA + - fai: + type: file + description: Index of the reference genome FASTA file + pattern: "*.{fasta,fa}.fai" + ontologies: + - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) + - - meta3: + type: map + description: | + Groovy Map containing ancestral state information + e.g. [ id:'test' ] + - fasta: + type: file + description: A ancestral state genome in FASTA format + pattern: "*.fasta" + ontologies: + - edam: "http://edamontology.org/format_1929" # FASTA + - fai: + type: file + description: Index of the ancestral state genome FASTA file + pattern: "*.{fasta,fa}.fai" + ontologies: + - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) + - - meta4: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - error_file: + type: file + description: A file containing information about type specific errors. + pattern: "*.error" + ontologies: [] + - - meta5: + type: map + description: | + Groovy Map containing sample information + e.g. [ id:'test', single_end:false ] + - inbreeding_coefficient_file: + type: file + description: A file containing estimates of individual inbreeding coefficients + pattern: "*.txt" + ontologies: [] +output: + saf: + - - meta: + type: map + description: Groovy Map containing population information. e.g. `[ + id:'test', population:'population id', samples:'sample IDs' ]` + - "*.saf.idx": + type: file + description: ANGSD site allele frequency index file + pattern: "*.saf.idx" + ontologies: [] + - "*.saf.pos.gz": + type: file + description: Gzipped file containing genomic positions of sites in the SAF + pattern: "*.saf.idx" + ontologies: [] + - "*.saf.pos.gz": + type: file + description: Gzipped binary file containing per-site sample allele frequency likelihoods + pattern: "*.saf.gz" + ontologies: [] +topics: + versions: + - - ${task.process}: + type: string + description: The name of the process + - angsd: + type: string + description: The name of the tool + - "angsd 2>&1 | sed '1!d;s/.*version: //;s/ .*//'": + type: eval + description: The expression to obtain the version of the tool +authors: + - "@ASendellPrice" +maintainers: + - "@ASendellPrice" From 11a172455c35f9500ae12cc95563b396de83a730 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 5 Jul 2026 11:25:33 +0100 Subject: [PATCH 08/24] Add validation step to check -doMajorMinor and -doMaf included in ext.args when using doSAF 2 --- modules/nf-core/angsd/dosaf/main.nf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index 056c4d030657..f16bfa37c58d 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -52,6 +52,18 @@ process ANGSD_DOSAF { ) } + // Validate doSAF 2 called alongside -doMajoMinor and -doMaf + if (dosaf_mode == 2 && !(args.contains("-doMajorMinor"))) { + error( + "ANGSD_DOSAF: -doSAF 2 requires -doMajorMinor to be specified. Please include in ext.args." + ) + } + if (dosaf_mode == 2 && !(args.contains("-doMaf"))) { + error( + "ANGSD_DOSAF: -doSAF 2 requires -doMaf to be specified. Please include in ext.args." + ) + } + // Validate GL 4 has error file if (gl_model == 4 && !error_file) { error( From 22b55742c18fce6d81aa4667820e1f6a105492d8 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 5 Jul 2026 11:38:41 +0100 Subject: [PATCH 09/24] Add new test cases for dosaf 2 (missing -doMAF and -doMajorMinor), plus add within test generation of angsd_syk.errors and angsd_FIN.indF --- .../nf-core/angsd/dosaf/tests/main.nf.test | 566 +++++++++++++++--- .../angsd/dosaf/tests/main.nf.test.snap | 223 ++++++- 2 files changed, 684 insertions(+), 105 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test b/modules/nf-core/angsd/dosaf/tests/main.nf.test index 962f46ebabaa..552c04606b56 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test @@ -8,8 +8,8 @@ nextflow_process { tag "modules_nfcore" tag "angsd" tag "angsd/dosaf" - - + + // ------------------------------------------------------------------------- // SUCCESS CASE 1: GL 1; doSAF 1; no ancestral // ------------------------------------------------------------------------- @@ -19,7 +19,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 1' + angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -31,22 +31,22 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [], [] ] @@ -64,9 +64,75 @@ nextflow_process { } } + + // ------------------------------------------------------------------------- + // SUCCESS CASE 2: GL 1; doSAF 2; no ancestral + // ------------------------------------------------------------------------- + + test("angsd - GL 1 - doSAF 2") { + config "./nextflow.config" + + setup{ + new File("${launchDir}/angsd_FIN.indF").text = "0.0\n0.0\n0.01\n0.017\n" + } + + when { + params { + angsd_args = '-GL 1 -doSAF 2 -doMajorMinor 1 -doMaf 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + file("${launchDir}/angsd_FIN.indF", checkIfExists: true) + ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.saf }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + // ------------------------------------------------------------------------- - // SUCCESS CASE 2: GL 3; doSAF 1; no ancestral + // SUCCESS CASE 3: GL 3; doSAF 1; no ancestral // ------------------------------------------------------------------------- test("angsd - GL3 - two steps") { @@ -74,7 +140,7 @@ nextflow_process { when { params { - angsd_args = '-GL 3 -doSAF 1' + angsd_args = '-GL 3 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } @@ -87,22 +153,22 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [], [] ] @@ -122,15 +188,19 @@ nextflow_process { // ------------------------------------------------------------------------- - // SUCCESS CASE 3: GL 4 (requires error file) + // SUCCESS CASE 4: GL 4 (requires error file) // ------------------------------------------------------------------------- test("angsd - GL4") { config "./nextflow.config" + setup { + new File("${launchDir}/angsd_syk.errors").text = "0.000000\t0.005488\t0.003847\t0.003137\t0.006807\t0.000000\t0.001972\t0.002396\t0.002190\t0.001855\t0.000000\t0.008068\t0.002491\t0.004268\t0.005812\t0.000000\n" + } + when { params { - angsd_args = '-GL 4 -doSAF 1' + angsd_args = '-GL 4 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } @@ -143,27 +213,27 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [ id: 'errors' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/resources/angsd/angsd_syk.errors') + file("${launchDir}/angsd_syk.errors", checkIfExists: true) ] input[4] = [ [], [] ] """ @@ -180,6 +250,120 @@ nextflow_process { } + // ------------------------------------------------------------------------- + // SUCCESS CASE 5: GL 1; doSAF 1; with ancestral FASTA + // ------------------------------------------------------------------------- + + test("angsd - GL 1 - doSAF 1 - with ancestral fasta") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') + ] + input[2] = [ + [ id:'ancestral_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz.fai') + ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.saf }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + + // ------------------------------------------------------------------------- + // SUCCESS CASE 6: GL 1; doSAF 1; min_ind_frac > 0 + // ------------------------------------------------------------------------- + + test("angsd - GL 1 - doSAF 1 - min_ind_frac") { + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + min_ind_frac = 0.5 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.saf }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } + + // ------------------------------------------------------------------------- // FAILURE CASE 1: Missing inbreeding coefficients file (needed for doSAF 2) // ------------------------------------------------------------------------- @@ -189,7 +373,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 2' + angsd_args = '-GL 1 -doSAF 2 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -201,22 +385,22 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [], [] ] @@ -248,7 +432,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1' + angsd_args = '-GL 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -260,22 +444,22 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [], [] ] @@ -307,7 +491,7 @@ nextflow_process { when { params { - angsd_args = '-doSAF 1' + angsd_args = '-doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -319,22 +503,22 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [], [] ] @@ -366,7 +550,7 @@ nextflow_process { when { params { - angsd_args = '-GL 5 -doSAF 1' + angsd_args = '-GL 5 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -378,22 +562,22 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [], [] ] @@ -425,7 +609,7 @@ nextflow_process { when { params { - angsd_args = '-GL 4 -doSAF 1' + angsd_args = '-GL 4 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process {""" @@ -436,22 +620,22 @@ nextflow_process { samples: ["HG00349", "HG00358", "HG00350", "HG00351"] ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") ], [ - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.FIN.chr20.test.bam.bai"), - file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.FIN.chr20.test.bam.bai") + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") ] ] input[1] = [ [ id:'reference_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20.fa.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ [], [], [] ] input[3] = [ [], [] ] @@ -472,4 +656,200 @@ nextflow_process { } } + + // ------------------------------------------------------------------------- + // FAILURE CASE 6: doSAF 2 called without -doMajorMinor + // ------------------------------------------------------------------------- + + test("angsd - GL 1 - doSAF 2 - missing -doMajorMinor") { + config "./nextflow.config" + + setup{ + new File("${launchDir}/angsd_FIN.indF").text = "0.0\n0.0\n0.01\n0.017\n" + } + + when { + params { + angsd_args = '-GL 1 -doSAF 2 -doMaf 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + file("${launchDir}/angsd_FIN.indF", checkIfExists: true) + ] + """ + } + } + + then { + def caused = process.errorReport + .split("Source block:")[0] + .split("Caused by:")[1] + .trim() + + assertAll( + { assert process.failed }, + { assert caused.contains("-doSAF 2 requires -doMajorMinor to be specified. Please include in ext.args.") } + ) + } + } + + + // ------------------------------------------------------------------------- + // FAILURE CASE 7: doSAF 2 called without -doMaf + // ------------------------------------------------------------------------- + + test("angsd - GL 1 - doSAF 2 - missing -doMajorMinor") { + config "./nextflow.config" + + setup{ + new File("${launchDir}/angsd_FIN.indF").text = "0.0\n0.0\n0.01\n0.017\n" + } + + when { + params { + angsd_args = '-GL 1 -doSAF 2 -doMajorMinor 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + file("${launchDir}/angsd_FIN.indF", checkIfExists: true) + ] + """ + } + } + + then { + def caused = process.errorReport + .split("Source block:")[0] + .split("Caused by:")[1] + .trim() + + assertAll( + { assert process.failed }, + { assert caused.contains("-doSAF 2 requires -doMaf to be specified. Please include in ext.args.") } + ) + } + } + + + // ------------------------------------------------------------------------- + // STUB + // ------------------------------------------------------------------------- + + test("angsd - GL 1 - doSAF 1 - stub") { + options "-stub" + config "./nextflow.config" + + when { + params { + angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + min_ind_frac = 0 + } + process { + """ + input[0] = [ + [ + id: "FIN", + population: "FIN", + samples: ["HG00349", "HG00358", "HG00350", "HG00351"] + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam") + ], + [ + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00349.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00350.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00351.chr20_1400000-1500000.bam.bai"), + file(params.modules_testdata_base_path + "genomics/homo_sapiens/illumina/bam/HG00358.chr20_1400000-1500000.bam.bai") + ] + ] + input[1] = [ + [ id:'reference_fa' ], + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') + ] + input[2] = [ [], [], [] ] + input[3] = [ [], [] ] + input[4] = [ [], [] ] + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + } + diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap index a4310c4e3376..d506c4366461 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap @@ -34,6 +34,41 @@ "nextflow": "26.04.1" } }, + "angsd - GL 1 - doSAF 2": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,f825a57ec037dd03127fced8c11c1f84", + "FIN.saf.pos.gz:md5,bbdf128514097d6faa7c71031af7b97b", + "FIN.saf.gz:md5,5b8d21df08479f96405d430758937977" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-07-05T11:00:24.005563", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, "angsd - GL 1 - doSAF 1": { "content": [ { @@ -49,9 +84,79 @@ "HG00351" ] }, - "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", - "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", - "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + "FIN.saf.idx:md5,c2a21e30aacb59091931c3651ea69ccd", + "FIN.saf.pos.gz:md5,bbdf128514097d6faa7c71031af7b97b", + "FIN.saf.gz:md5,8ca7bbf4f93b7aa09cb6da8f7c87c132" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-07-01T21:06:18.021816", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "angsd - GL 1 - doSAF 1 - with ancestral fasta": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,c2a21e30aacb59091931c3651ea69ccd", + "FIN.saf.pos.gz:md5,bbdf128514097d6faa7c71031af7b97b", + "FIN.saf.gz:md5,29eb0ee312740e0aa6de230e6405e44e" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-07-01T21:06:38.622819", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "angsd - GL 2 - doSAF 1": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,8676edf92221ff8c895abd1d4943029e", + "FIN.saf.pos.gz:md5,bbdf128514097d6faa7c71031af7b97b", + "FIN.saf.gz:md5,ff89cc44bc149a5e3f88917ef206b6ff" ] ], "versions_angsd": [ @@ -63,7 +168,7 @@ ] } ], - "timestamp": "2026-06-24T22:38:48.132228", + "timestamp": "2026-07-05T10:55:49.175165", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -84,9 +189,9 @@ "HG00351" ] }, - "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", - "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", - "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + "FIN.saf.idx:md5,ed87cdf671b5b11137b5082f05e3ce6a", + "FIN.saf.pos.gz:md5,bbdf128514097d6faa7c71031af7b97b", + "FIN.saf.gz:md5,095fc8b1763ae7be00218e0d52e1a1b4" ] ], "versions_angsd": [ @@ -98,7 +203,7 @@ ] } ], - "timestamp": "2026-06-24T22:41:04.740319", + "timestamp": "2026-07-01T21:06:30.349544", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -139,6 +244,65 @@ "nextflow": "26.04.1" } }, + "angsd - GL 1 - doSAF 1 - stub": { + "content": [ + { + "0": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,d41d8cd98f00b204e9800998ecf8427e", + "FIN.saf.pos.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "FIN.saf.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "1": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ], + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,d41d8cd98f00b204e9800998ecf8427e", + "FIN.saf.pos.gz:md5,68b329da9893e34099c7d8ad5cb9c940", + "FIN.saf.gz:md5,68b329da9893e34099c7d8ad5cb9c940" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-06-28T19:13:44.743397", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, "angsd - GL4": { "content": [ { @@ -154,9 +318,44 @@ "HG00351" ] }, - "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", - "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", - "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" + "FIN.saf.idx:md5,821d582655745d035cd963012e04684e", + "FIN.saf.pos.gz:md5,bbdf128514097d6faa7c71031af7b97b", + "FIN.saf.gz:md5,e21b7f5dfdcdeec7bd59a3c203a95c7c" + ] + ], + "versions_angsd": [ + [ + "ANGSD_DOSAF", + "angsd", + "0.940-dirty" + ] + ] + } + ], + "timestamp": "2026-07-02T20:05:23.416482", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.1" + } + }, + "angsd - GL 1 - doSAF 1 - min_ind_frac": { + "content": [ + { + "saf": [ + [ + { + "id": "FIN", + "population": "FIN", + "samples": [ + "HG00349", + "HG00358", + "HG00350", + "HG00351" + ] + }, + "FIN.saf.idx:md5,4fc612eb149887c6238af1d4239ffc7e", + "FIN.saf.pos.gz:md5,12f398f2c01708e40b32da38931ffd68", + "FIN.saf.gz:md5,5692b34cf0807dcbb92eca36f970b975" ] ], "versions_angsd": [ @@ -168,7 +367,7 @@ ] } ], - "timestamp": "2026-06-24T22:44:08.314653", + "timestamp": "2026-07-01T21:06:43.224456", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" From 558000caa1a09a8a203902507edef4a6fae3275b Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 5 Jul 2026 11:49:08 +0100 Subject: [PATCH 10/24] Update test name for Failure Case 7 --- modules/nf-core/angsd/dosaf/tests/main.nf.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test b/modules/nf-core/angsd/dosaf/tests/main.nf.test index 552c04606b56..30a71fdc685f 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test @@ -731,7 +731,7 @@ nextflow_process { // FAILURE CASE 7: doSAF 2 called without -doMaf // ------------------------------------------------------------------------- - test("angsd - GL 1 - doSAF 2 - missing -doMajorMinor") { + test("angsd - GL 1 - doSAF 2 - missing -doMaf") { config "./nextflow.config" setup{ From eea9676faea61feaea10d0575464b1e889eec4d8 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 5 Jul 2026 11:52:11 +0100 Subject: [PATCH 11/24] Fix syntax for ext.args and ext.args2 in ANGSD_DOSAF process --- modules/nf-core/angsd/dosaf/tests/nextflow.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/tests/nextflow.config b/modules/nf-core/angsd/dosaf/tests/nextflow.config index 3d058758fcf0..10a06e4c1b6a 100644 --- a/modules/nf-core/angsd/dosaf/tests/nextflow.config +++ b/modules/nf-core/angsd/dosaf/tests/nextflow.config @@ -1,6 +1,6 @@ process { withName: ANGSD_DOSAF { - ext.args = params.angsd_args - ext.args2 = params.min_ind_frac + ext.args = { params.angsd_args } + ext.args2 = { params.min_ind_frac } } } From b368eb66b48091f0a5bd8eaedde85d92f8c2c2f4 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 5 Jul 2026 12:19:52 +0100 Subject: [PATCH 12/24] Update meta --- modules/nf-core/angsd/dosaf/meta.yml | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/meta.yml b/modules/nf-core/angsd/dosaf/meta.yml index 551a00b566df..d2e1ee7b6a77 100644 --- a/modules/nf-core/angsd/dosaf/meta.yml +++ b/modules/nf-core/angsd/dosaf/meta.yml @@ -37,62 +37,62 @@ input: - - meta2: type: map description: | - Groovy Map containing reference information - e.g. [ id:'test' ] + Groovy Map containing reference genome information + e.g. [ id:'GRCh38' ] - fasta: type: file description: A reference genome in FASTA format - pattern: "*.fasta" + pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA - fai: type: file description: Index of the reference genome FASTA file - pattern: "*.{fasta,fa}.fai" + pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) - - meta3: type: map description: | - Groovy Map containing ancestral state information - e.g. [ id:'test' ] + Groovy Map containing ancestral genome information + e.g. [ id:'homo_sapiens_ancestor_GRCh38' ] - fasta: type: file - description: A ancestral state genome in FASTA format - pattern: "*.fasta" + description: An ancestral state genome in FASTA format + pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA - fai: type: file description: Index of the ancestral state genome FASTA file - pattern: "*.{fasta,fa}.fai" + pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) - - meta4: type: map description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] + Groovy Map containing error model information + e.g. [ id:'test' ] - error_file: type: file - description: A file containing information about type specific errors. - pattern: "*.error" + description: A file containing per-base substitution error rates for use with the Sykes genotype likelihood model (-GL 4). + pattern: "*.errors" ontologies: [] - - meta5: type: map description: | - Groovy Map containing sample information - e.g. [ id:'test', single_end:false ] + Groovy Map containing inbreeding coefficient information + e.g. [ id:'test', population:'population id', samples:'sample IDs' ] - inbreeding_coefficient_file: type: file description: A file containing estimates of individual inbreeding coefficients - pattern: "*.txt" + pattern: "*.indF" ontologies: [] output: saf: - - meta: type: map - description: Groovy Map containing population information. e.g. `[ + description: Groovy Map containing population information. e.g. `[ id:'test', population:'population id', samples:'sample IDs' ]` - "*.saf.idx": type: file @@ -102,9 +102,9 @@ output: - "*.saf.pos.gz": type: file description: Gzipped file containing genomic positions of sites in the SAF - pattern: "*.saf.idx" + pattern: "*.saf.pos.gz" ontologies: [] - - "*.saf.pos.gz": + - "*.saf.gz": type: file description: Gzipped binary file containing per-site sample allele frequency likelihoods pattern: "*.saf.gz" @@ -123,4 +123,4 @@ topics: authors: - "@ASendellPrice" maintainers: - - "@ASendellPrice" + - "@ASendellPrice" \ No newline at end of file From 8dc4f173989463c22e33f4cdc026a5912b45ff59 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Tue, 14 Jul 2026 16:34:29 +0100 Subject: [PATCH 13/24] Switch test data path back to nf-core test-datasets repo --- modules/nf-core/angsd/dosaf/tests/main.nf.test | 4 ++-- modules/nf-core/angsd/dosaf/tests/main.nf.test.snap | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test b/modules/nf-core/angsd/dosaf/tests/main.nf.test index 30a71fdc685f..7438d56749d8 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test @@ -290,8 +290,8 @@ nextflow_process { ] input[2] = [ [ id:'ancestral_fa' ], - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz'), - file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz.fai') + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/resources/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz'), + file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/resources/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz.fai') ] input[3] = [ [], [] ] input[4] = [ [], [] ] diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap index d506c4366461..d1fb68211c66 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap @@ -63,7 +63,7 @@ ] } ], - "timestamp": "2026-07-05T11:00:24.005563", + "timestamp": "2026-07-14T16:31:50.111897", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -98,7 +98,7 @@ ] } ], - "timestamp": "2026-07-01T21:06:18.021816", + "timestamp": "2026-07-14T16:31:44.837344", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -133,7 +133,7 @@ ] } ], - "timestamp": "2026-07-01T21:06:38.622819", + "timestamp": "2026-07-14T16:32:16.336297", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -203,7 +203,7 @@ ] } ], - "timestamp": "2026-07-01T21:06:30.349544", + "timestamp": "2026-07-14T16:32:04.293571", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -332,7 +332,7 @@ ] } ], - "timestamp": "2026-07-02T20:05:23.416482", + "timestamp": "2026-07-14T16:32:09.624486", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -367,7 +367,7 @@ ] } ], - "timestamp": "2026-07-01T21:06:43.224456", + "timestamp": "2026-07-14T16:32:22.902973", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" From d26e0227529547098bb26c506a33c8696d7f86d3 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Tue, 14 Jul 2026 16:46:17 +0100 Subject: [PATCH 14/24] Bump hstlib version to v1.24 --- modules/nf-core/angsd/dosaf/environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nf-core/angsd/dosaf/environment.yml b/modules/nf-core/angsd/dosaf/environment.yml index 8700495b8876..f73b33dd20a9 100644 --- a/modules/nf-core/angsd/dosaf/environment.yml +++ b/modules/nf-core/angsd/dosaf/environment.yml @@ -5,4 +5,4 @@ channels: - bioconda dependencies: - bioconda::angsd=0.940 - - bioconda::htslib=1.23.1 + - bioconda::htslib=1.24 From 3ae9d85fbbd029a0af269ce64808f62a5bac06cf Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Tue, 14 Jul 2026 17:00:51 +0100 Subject: [PATCH 15/24] Fix meta.yml issues identified during linting --- modules/nf-core/angsd/dosaf/meta.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/meta.yml b/modules/nf-core/angsd/dosaf/meta.yml index d2e1ee7b6a77..b549ab14613c 100644 --- a/modules/nf-core/angsd/dosaf/meta.yml +++ b/modules/nf-core/angsd/dosaf/meta.yml @@ -20,14 +20,14 @@ input: description: | Groovy Map containing population information e.g. [ id:'test', population:'population id', samples:'sample IDs' ] - - bam: + - bams: type: file description: A list of BAM or CRAM files pattern: "*.{bam,cram}" ontologies: - edam: "http://edamontology.org/format_2572" # BAM - edam: "http://edamontology.org/format_3462" # CRAM - - bai: + - bam_indices: type: file description: A list of BAM or CRAM indices pattern: "*.{bam.bai,cram.crai}" @@ -39,13 +39,13 @@ input: description: | Groovy Map containing reference genome information e.g. [ id:'GRCh38' ] - - fasta: + - reference_fasta: type: file description: A reference genome in FASTA format pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA - - fai: + - reference_fai: type: file description: Index of the reference genome FASTA file pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" @@ -56,13 +56,13 @@ input: description: | Groovy Map containing ancestral genome information e.g. [ id:'homo_sapiens_ancestor_GRCh38' ] - - fasta: + - ancestral_fasta: type: file description: An ancestral state genome in FASTA format pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA - - fai: + - ancestral_fai: type: file description: Index of the ancestral state genome FASTA file pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" @@ -83,7 +83,7 @@ input: description: | Groovy Map containing inbreeding coefficient information e.g. [ id:'test', population:'population id', samples:'sample IDs' ] - - inbreeding_coefficient_file: + - inbreeding_coefficients: type: file description: A file containing estimates of individual inbreeding coefficients pattern: "*.indF" @@ -109,9 +109,19 @@ output: description: Gzipped binary file containing per-site sample allele frequency likelihoods pattern: "*.saf.gz" ontologies: [] + versions_angsd: + - - "${task.process}": + type: string + description: The name of the process + - angsd: + type: string + description: The name of the tool + - "angsd 2>&1 | sed '1!d;s/.*version: //;s/ .*//'": + type: eval + description: The expression to obtain the version of the tool topics: versions: - - - ${task.process}: + - - "${task.process}": type: string description: The name of the process - angsd: From 52c0366f491a7ca880da7e53bfcb5dbfd3c289f2 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Tue, 14 Jul 2026 21:53:44 +0100 Subject: [PATCH 16/24] rollback htslib to version compatible with angsd 0.940 --- modules/nf-core/angsd/dosaf/environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nf-core/angsd/dosaf/environment.yml b/modules/nf-core/angsd/dosaf/environment.yml index f73b33dd20a9..2e83f3f2ca8f 100644 --- a/modules/nf-core/angsd/dosaf/environment.yml +++ b/modules/nf-core/angsd/dosaf/environment.yml @@ -5,4 +5,4 @@ channels: - bioconda dependencies: - bioconda::angsd=0.940 - - bioconda::htslib=1.24 + - bioconda::htslib=1.23 From 802a9b95c75e3f3973fc509bf267aba673486296 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Wed, 15 Jul 2026 16:22:05 +0100 Subject: [PATCH 17/24] Move gl_model and dosaf_mode from ext.args to input channels, remove unnecessary meta maps, update meta.yml and tests accordingly. --- modules/nf-core/angsd/dosaf/main.nf | 32 +-- modules/nf-core/angsd/dosaf/meta.yml | 50 ++--- .../nf-core/angsd/dosaf/tests/main.nf.test | 210 +++++++++--------- .../angsd/dosaf/tests/main.nf.test.snap | 119 +--------- 4 files changed, 142 insertions(+), 269 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index f16bfa37c58d..c3aa9b9e0508 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -9,10 +9,12 @@ process ANGSD_DOSAF { input: tuple val(meta), path(bams), path(bam_indices) - tuple val(meta2), path(reference_fasta), path(reference_fai) - tuple val(meta3), path(ancestral_fasta), path(ancestral_fai) // Optional. Provides ancestral state for unfolded SFS. - tuple val(meta4), path(error_file) // Optional. Required for SYK model (-GL 4) only. - tuple val(meta5), path(inbreeding_coefficients) // Optional. Required for -doSAF 2 (inbreeding-aware mode). + tuple path(reference_fasta), path(reference_fai) + tuple path(ancestral_fasta), path(ancestral_fai) // Optional. Provides ancestral state for unfolded SFS. + path(error_file) // Optional. Required for SYK model (-GL 4) only. + path(inbreeding_coefficients) // Optional. Required for -doSAF 2 (inbreeding-aware mode). + val(gl_model) + val(dosaf_mode) output: tuple val(meta), path("*.saf.idx"), path("*.saf.pos.gz"), path("*.saf.gz"), emit: saf @@ -26,22 +28,16 @@ process ANGSD_DOSAF { def prefix = task.ext.prefix ?: "${meta.id}" // Validate GL model - def gl_model = args.contains("-GL 1") ? 1 : - args.contains("-GL 2") ? 2 : - args.contains("-GL 3") ? 3 : - args.contains("-GL 4") ? 4 : 0 - if (gl_model == 0) { + if (!(gl_model in [1, 2, 3, 4])) { error( - "ANGSD_DOSAF: No valid GL model selected. Please specify one of: -GL 1, -GL 2, -GL 3, or -GL 4 in ext.args." + "ANGSD_DOSAF: Invalid GL model '${gl_model}'. Please pass one of 1, 2, 3, or 4 as the gl_model input." ) } // Validate doSAF mode - def dosaf_mode = args.contains("-doSAF 1") ? 1 : - args.contains("-doSAF 2") ? 2 : 0 - if (dosaf_mode == 0) { + if (!(dosaf_mode in [1, 2])) { error( - "ANGSD_DOSAF: No valid doSAF mode selected. Please specify -doSAF 1 or -doSAF 2 in ext.args." + "ANGSD_DOSAF: Invalid doSAF mode '${dosaf_mode}'. Please pass 1 or 2 as the dosaf_mode input." ) } @@ -109,13 +105,15 @@ process ANGSD_DOSAF { -nThreads ${task.cpus} \\ -bam bamlist.txt \\ -minQ 0 \\ - -GL 3 \\ + -GL ${gl_model} \\ -ref ${reference_fasta} \\ -out ${prefix} angsd \\ -nThreads ${task.cpus} \\ -bam bamlist.txt \\ + -GL ${gl_model} \\ + -doSAF ${dosaf_mode} \\ ${ref} \\ ${indF_arg} \\ ${args} \\ @@ -131,6 +129,8 @@ process ANGSD_DOSAF { angsd \\ -nThreads ${task.cpus} \\ -bam bamlist.txt \\ + -GL ${gl_model} \\ + -doSAF ${dosaf_mode} \\ ${ref} \\ ${indF_arg} \\ ${errors_arg} \\ @@ -148,6 +148,8 @@ process ANGSD_DOSAF { angsd \\ -nThreads ${task.cpus} \\ -bam bamlist.txt \\ + -GL ${gl_model} \\ + -doSAF ${dosaf_mode} \\ ${ref} \\ ${indF_arg} \\ ${args} \\ diff --git a/modules/nf-core/angsd/dosaf/meta.yml b/modules/nf-core/angsd/dosaf/meta.yml index b549ab14613c..c697eaa25754 100644 --- a/modules/nf-core/angsd/dosaf/meta.yml +++ b/modules/nf-core/angsd/dosaf/meta.yml @@ -22,72 +22,60 @@ input: e.g. [ id:'test', population:'population id', samples:'sample IDs' ] - bams: type: file - description: A list of BAM or CRAM files + description: A list of BAM or CRAM files. pattern: "*.{bam,cram}" ontologies: - edam: "http://edamontology.org/format_2572" # BAM - edam: "http://edamontology.org/format_3462" # CRAM - bam_indices: type: file - description: A list of BAM or CRAM indices + description: A list of BAM or CRAM indices. pattern: "*.{bam.bai,cram.crai}" ontologies: - edam: "http://edamontology.org/format_3327" # BAI - edam: "http://edamontology.org/format_3462" # CRAM (no dedicated CRAI term in EDAM) - - - meta2: - type: map - description: | - Groovy Map containing reference genome information - e.g. [ id:'GRCh38' ] - - reference_fasta: + - - reference_fasta: type: file - description: A reference genome in FASTA format + description: A reference genome in FASTA format. pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA - reference_fai: type: file - description: Index of the reference genome FASTA file + description: Index of the reference genome FASTA file. pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) - - - meta3: - type: map - description: | - Groovy Map containing ancestral genome information - e.g. [ id:'homo_sapiens_ancestor_GRCh38' ] - - ancestral_fasta: + - - ancestral_fasta: type: file - description: An ancestral state genome in FASTA format + description: An ancestral state genome in FASTA format. pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA - ancestral_fai: type: file - description: Index of the ancestral state genome FASTA file + description: Index of the ancestral state genome FASTA file. pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" ontologies: - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) - - - meta4: - type: map - description: | - Groovy Map containing error model information - e.g. [ id:'test' ] - - error_file: + - - error_file: type: file description: A file containing per-base substitution error rates for use with the Sykes genotype likelihood model (-GL 4). pattern: "*.errors" ontologies: [] - - - meta5: - type: map - description: | - Groovy Map containing inbreeding coefficient information - e.g. [ id:'test', population:'population id', samples:'sample IDs' ] - - inbreeding_coefficients: + - - inbreeding_coefficients: type: file - description: A file containing estimates of individual inbreeding coefficients + description: A file containing estimates of individual inbreeding coefficients. pattern: "*.indF" ontologies: [] + - - gl_model: + type: integer + description: | + Genotype likelihood model to use (angsd -GL). 1=SAMtools, 2=GATK, 3=SOAPsnp, 4=SYK. + - - dosaf_mode: + type: integer + description: | + Site allele frequency likelihood estimation mode (angsd -doSAF). 1=standard, 2=inbreeding-aware (requires indF). output: saf: - - meta: diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test b/modules/nf-core/angsd/dosaf/tests/main.nf.test index 7438d56749d8..e8bf55d1a314 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test @@ -8,8 +8,8 @@ nextflow_process { tag "modules_nfcore" tag "angsd" tag "angsd/dosaf" - - + + // ------------------------------------------------------------------------- // SUCCESS CASE 1: GL 1; doSAF 1; no ancestral // ------------------------------------------------------------------------- @@ -19,7 +19,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -44,13 +44,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 1 + input[6] = 1 """ } } @@ -78,7 +79,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 2 -doMajorMinor 1 -doMaf 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-doMajorMinor 1 -doMaf 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -103,20 +104,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ - [ - id: "FIN", - population: "FIN", - samples: ["HG00349", "HG00358", "HG00350", "HG00351"] - ], - file("${launchDir}/angsd_FIN.indF", checkIfExists: true) - ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = file("${launchDir}/angsd_FIN.indF", checkIfExists: true) + input[5] = 1 + input[6] = 2 """ } } @@ -130,7 +125,7 @@ nextflow_process { } } - + // ------------------------------------------------------------------------- // SUCCESS CASE 3: GL 3; doSAF 1; no ancestral // ------------------------------------------------------------------------- @@ -140,10 +135,10 @@ nextflow_process { when { params { - angsd_args = '-GL 3 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } - + process { """ input[0] = [ @@ -166,13 +161,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 3 + input[6] = 1 """ } } @@ -197,13 +193,13 @@ nextflow_process { setup { new File("${launchDir}/angsd_syk.errors").text = "0.000000\t0.005488\t0.003847\t0.003137\t0.006807\t0.000000\t0.001972\t0.002396\t0.002190\t0.001855\t0.000000\t0.008068\t0.002491\t0.004268\t0.005812\t0.000000\n" } - + when { params { - angsd_args = '-GL 4 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } - + process { """ input[0] = [ @@ -226,16 +222,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ - [ id: 'errors' ], - file("${launchDir}/angsd_syk.errors", checkIfExists: true) - ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = file("${launchDir}/angsd_syk.errors", checkIfExists: true) + input[4] = [] + input[5] = 4 + input[6] = 1 """ } } @@ -259,7 +253,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -284,17 +278,17 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] input[2] = [ - [ id:'ancestral_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/resources/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/resources/homo_sapiens_ancestor_chr20_1_2000000.fasta.gz.fai') ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 1 + input[6] = 1 """ } } @@ -318,7 +312,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0.5 } process { @@ -343,13 +337,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 1 + input[6] = 1 """ } } @@ -362,8 +357,8 @@ nextflow_process { ) } } - - + + // ------------------------------------------------------------------------- // FAILURE CASE 1: Missing inbreeding coefficients file (needed for doSAF 2) // ------------------------------------------------------------------------- @@ -373,7 +368,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 2 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -398,13 +393,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 1 + input[6] = 2 """ } } @@ -424,15 +420,15 @@ nextflow_process { // ------------------------------------------------------------------------- - // FAILURE CASE 2: Missing doSAF flag + // FAILURE CASE 2: Missing doSAF mode (not supplied) // ------------------------------------------------------------------------- - test("angsd - missing -doSAF flag") { + test("angsd - missing doSAF mode") { config "./nextflow.config" when { params { - angsd_args = '-GL 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -457,13 +453,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 1 + input[6] = [] """ } } @@ -476,22 +473,22 @@ nextflow_process { assertAll( { assert process.failed }, - { assert caused.contains("No valid doSAF mode selected") } + { assert caused.contains("Invalid doSAF mode") } ) } } // ------------------------------------------------------------------------- - // FAILURE CASE 3: Missing GL flag + // FAILURE CASE 3: Missing GL model (not supplied) // ------------------------------------------------------------------------- - test("angsd - missing -GL flag") { + test("angsd - missing GL model") { config "./nextflow.config" when { params { - angsd_args = '-doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -516,13 +513,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = [] + input[6] = 1 """ } } @@ -535,7 +533,7 @@ nextflow_process { assertAll( { assert process.failed }, - { assert caused.contains("No valid GL model selected") } + { assert caused.contains("Invalid GL model") } ) } } @@ -550,7 +548,7 @@ nextflow_process { when { params { - angsd_args = '-GL 5 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -575,13 +573,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 5 + input[6] = 1 """ } } @@ -594,12 +593,12 @@ nextflow_process { assertAll( { assert process.failed }, - { assert caused.contains("No valid GL model selected") } + { assert caused.contains("Invalid GL model") } ) } } - + // ------------------------------------------------------------------------- // FAILURE CASE 5: Missing error file (required by -GL 4) // ------------------------------------------------------------------------- @@ -609,7 +608,7 @@ nextflow_process { when { params { - angsd_args = '-GL 4 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process {""" @@ -633,13 +632,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 4 + input[6] = 1 """} } @@ -670,7 +670,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 2 -doMaf 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-doMaf 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -695,20 +695,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ - [ - id: "FIN", - population: "FIN", - samples: ["HG00349", "HG00358", "HG00350", "HG00351"] - ], - file("${launchDir}/angsd_FIN.indF", checkIfExists: true) - ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = file("${launchDir}/angsd_FIN.indF", checkIfExists: true) + input[5] = 1 + input[6] = 2 """ } } @@ -740,7 +734,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 2 -doMajorMinor 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-doMajorMinor 1 -r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -765,20 +759,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ - [ - id: "FIN", - population: "FIN", - samples: ["HG00349", "HG00358", "HG00350", "HG00351"] - ], - file("${launchDir}/angsd_FIN.indF", checkIfExists: true) - ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = file("${launchDir}/angsd_FIN.indF", checkIfExists: true) + input[5] = 1 + input[6] = 2 """ } } @@ -807,7 +795,7 @@ nextflow_process { when { params { - angsd_args = '-GL 1 -doSAF 1 -r chr20:1400000-1500000 -checkBamHeaders 0' + angsd_args = '-r chr20:1400000-1500000 -checkBamHeaders 0' min_ind_frac = 0 } process { @@ -832,13 +820,14 @@ nextflow_process { ] ] input[1] = [ - [ id:'reference_fa' ], file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz'), file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/chr20/sequence/GRCh38_chr20_1_2000000.fasta.gz.fai') ] - input[2] = [ [], [], [] ] - input[3] = [ [], [] ] - input[4] = [ [], [] ] + input[2] = [ [], [] ] + input[3] = [] + input[4] = [] + input[5] = 1 + input[6] = 1 """ } } @@ -852,4 +841,3 @@ nextflow_process { } } - diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap index d1fb68211c66..0d98c75aeb87 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap @@ -1,39 +1,4 @@ { - "angsd - GL1 - doSAF1 - no anc": { - "content": [ - { - "saf": [ - [ - { - "id": "FIN", - "population": "FIN", - "samples": [ - "HG00349", - "HG00358", - "HG00350", - "HG00351" - ] - }, - "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", - "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", - "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" - ] - ], - "versions_angsd": [ - [ - "ANGSD_DOSAF", - "angsd", - "0.940-dirty" - ] - ] - } - ], - "timestamp": "2026-06-19T15:53:53.808325", - "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.1" - } - }, "angsd - GL 1 - doSAF 2": { "content": [ { @@ -63,7 +28,7 @@ ] } ], - "timestamp": "2026-07-14T16:31:50.111897", + "timestamp": "2026-07-15T16:18:45.373959", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -98,7 +63,7 @@ ] } ], - "timestamp": "2026-07-14T16:31:44.837344", + "timestamp": "2026-07-15T16:18:39.225032", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -133,42 +98,7 @@ ] } ], - "timestamp": "2026-07-14T16:32:16.336297", - "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.1" - } - }, - "angsd - GL 2 - doSAF 1": { - "content": [ - { - "saf": [ - [ - { - "id": "FIN", - "population": "FIN", - "samples": [ - "HG00349", - "HG00358", - "HG00350", - "HG00351" - ] - }, - "FIN.saf.idx:md5,8676edf92221ff8c895abd1d4943029e", - "FIN.saf.pos.gz:md5,bbdf128514097d6faa7c71031af7b97b", - "FIN.saf.gz:md5,ff89cc44bc149a5e3f88917ef206b6ff" - ] - ], - "versions_angsd": [ - [ - "ANGSD_DOSAF", - "angsd", - "0.940-dirty" - ] - ] - } - ], - "timestamp": "2026-07-05T10:55:49.175165", + "timestamp": "2026-07-15T16:19:13.058938", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -203,42 +133,7 @@ ] } ], - "timestamp": "2026-07-14T16:32:04.293571", - "meta": { - "nf-test": "0.9.5", - "nextflow": "26.04.1" - } - }, - "angsd - GL 1 - doSAF 1 - no anc": { - "content": [ - { - "saf": [ - [ - { - "id": "FIN", - "population": "FIN", - "samples": [ - "HG00349", - "HG00358", - "HG00350", - "HG00351" - ] - }, - "FIN.saf.idx:md5,d7161a2d9cf945296037c4a283f7fe43", - "FIN.saf.pos.gz:md5,17bd455cc31f7a40c60738a5839a87d3", - "FIN.saf.gz:md5,17bd455cc31f7a40c60738a5839a87d3" - ] - ], - "versions_angsd": [ - [ - "ANGSD_DOSAF", - "angsd", - "0.940-dirty" - ] - ] - } - ], - "timestamp": "2026-06-22T16:32:30.375434", + "timestamp": "2026-07-15T16:18:59.939055", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -297,7 +192,7 @@ ] } ], - "timestamp": "2026-06-28T19:13:44.743397", + "timestamp": "2026-07-15T16:19:43.788466", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -332,7 +227,7 @@ ] } ], - "timestamp": "2026-07-14T16:32:09.624486", + "timestamp": "2026-07-15T16:19:05.721228", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -367,7 +262,7 @@ ] } ], - "timestamp": "2026-07-14T16:32:22.902973", + "timestamp": "2026-07-15T16:19:19.302796", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" From 79a615370f2eb47b422f4b30bac1b792f92e40e2 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Wed, 15 Jul 2026 16:52:57 +0100 Subject: [PATCH 18/24] Fix linting errors --- modules/nf-core/angsd/dosaf/meta.yml | 73 +++++++++++++++------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/meta.yml b/modules/nf-core/angsd/dosaf/meta.yml index c697eaa25754..d62fe6724dae 100644 --- a/modules/nf-core/angsd/dosaf/meta.yml +++ b/modules/nf-core/angsd/dosaf/meta.yml @@ -1,4 +1,3 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: "angsd_dosaf" description: Estimate site allele frequencies from BAM files. keywords: @@ -12,7 +11,9 @@ tools: documentation: "http://www.popgen.dk/angsd/" tool_dev_url: "https://github.com/ANGSD/angsd" doi: "10.1186/s12859-014-0356-4" - licence: ["GPL v3", "MIT"] + licence: + - "GPL v3" + - "MIT" identifier: biotools:angsd input: - - meta: @@ -25,57 +26,59 @@ input: description: A list of BAM or CRAM files. pattern: "*.{bam,cram}" ontologies: - - edam: "http://edamontology.org/format_2572" # BAM - - edam: "http://edamontology.org/format_3462" # CRAM + - edam: "http://edamontology.org/format_2572" + - edam: "http://edamontology.org/format_3462" - bam_indices: type: file description: A list of BAM or CRAM indices. pattern: "*.{bam.bai,cram.crai}" ontologies: - - edam: "http://edamontology.org/format_3327" # BAI - - edam: "http://edamontology.org/format_3462" # CRAM (no dedicated CRAI term in EDAM) + - edam: "http://edamontology.org/format_3327" + - edam: "http://edamontology.org/format_3462" - - reference_fasta: type: file description: A reference genome in FASTA format. pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - - edam: "http://edamontology.org/format_1929" # FASTA + - edam: "http://edamontology.org/format_1929" - reference_fai: type: file description: Index of the reference genome FASTA file. pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" ontologies: - - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) + - edam: "http://edamontology.org/format_1929" - - ancestral_fasta: type: file description: An ancestral state genome in FASTA format. pattern: "*.{fasta,fa,fasta.gz,fa.gz}" ontologies: - - edam: "http://edamontology.org/format_1929" # FASTA + - edam: "http://edamontology.org/format_1929" - ancestral_fai: type: file description: Index of the ancestral state genome FASTA file. pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" ontologies: - - edam: "http://edamontology.org/format_1929" # FASTA (no dedicated FAI term in EDAM) - - - error_file: - type: file - description: A file containing per-base substitution error rates for use with the Sykes genotype likelihood model (-GL 4). - pattern: "*.errors" - ontologies: [] - - - inbreeding_coefficients: - type: file - description: A file containing estimates of individual inbreeding coefficients. - pattern: "*.indF" - ontologies: [] - - - gl_model: - type: integer - description: | - Genotype likelihood model to use (angsd -GL). 1=SAMtools, 2=GATK, 3=SOAPsnp, 4=SYK. - - - dosaf_mode: - type: integer - description: | - Site allele frequency likelihood estimation mode (angsd -doSAF). 1=standard, 2=inbreeding-aware (requires indF). + - edam: "http://edamontology.org/format_1929" + - error_file: + type: file + description: A file containing per-base substitution error rates for use + with the Sykes genotype likelihood model (-GL 4). + pattern: "*.errors" + ontologies: [] + - inbreeding_coefficients: + type: file + description: A file containing estimates of individual inbreeding + coefficients. + pattern: "*.indF" + ontologies: [] + - gl_model: + type: integer + description: | + Genotype likelihood model to use (angsd -GL). 1=SAMtools, 2=GATK, 3=SOAPsnp, 4=SYK. + - dosaf_mode: + type: integer + description: | + Site allele frequency likelihood estimation mode (angsd -doSAF). 1=standard, 2=inbreeding-aware (requires indF). output: saf: - - meta: @@ -89,14 +92,18 @@ output: ontologies: [] - "*.saf.pos.gz": type: file - description: Gzipped file containing genomic positions of sites in the SAF + description: Gzipped file containing genomic positions of sites in the + SAF pattern: "*.saf.pos.gz" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3989 - "*.saf.gz": type: file - description: Gzipped binary file containing per-site sample allele frequency likelihoods + description: Gzipped binary file containing per-site sample allele + frequency likelihoods pattern: "*.saf.gz" - ontologies: [] + ontologies: + - edam: http://edamontology.org/format_3989 versions_angsd: - - "${task.process}": type: string @@ -121,4 +128,4 @@ topics: authors: - "@ASendellPrice" maintainers: - - "@ASendellPrice" \ No newline at end of file + - "@ASendellPrice" From b9140fafc95ba7661f7e035cbc77c56becbbd048 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price <36015770+ASendellPrice@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:18:26 +0100 Subject: [PATCH 19/24] rename ref to ref_anc_arg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- modules/nf-core/angsd/dosaf/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index c3aa9b9e0508..32899da721e8 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -80,7 +80,7 @@ process ANGSD_DOSAF { // Reference / ancestral args. // If ancestral_fasta supplied: use as -anc and pass reference as -ref. // If not supplied: use reference as -anc and -ref (suitable for folded SFS via realSFS -fold 1). - def ref = ancestral_fasta ? "-anc ${ancestral_fasta} -ref ${reference_fasta}" : "-anc ${reference_fasta} -ref ${reference_fasta}" + def ref_anc_arg = ancestral_fasta ? "-anc ${ancestral_fasta} -ref ${reference_fasta}" : "-anc ${reference_fasta} -ref ${reference_fasta}" // Optional args def indF_arg = inbreeding_coefficients ? "-indF ${inbreeding_coefficients}" : "" From a8c1c1ddc5c825a517a67dfc8dcdbe80e9cb8092 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price <36015770+ASendellPrice@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:20:45 +0100 Subject: [PATCH 20/24] Apply suggestion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Hörtenhuber --- modules/nf-core/angsd/dosaf/main.nf | 98 ++++++++++------------------- 1 file changed, 34 insertions(+), 64 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index 32899da721e8..384c81acad10 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -93,70 +93,40 @@ process ANGSD_DOSAF { printf '%s\\n' ${bams} > bamlist.txt """ - if (gl_model == 3) { - // SOAPsnp requires a two-step process: - // 1. Calibration step with -minQ 0 to generate the calibration matrix in angsd_tmpdir/ - // 2. doSAF step using the calibration matrix - // -GL 3 is hardcoded in the calibration step to avoid passing all other args - """ - ${preamble} - - angsd \\ - -nThreads ${task.cpus} \\ - -bam bamlist.txt \\ - -minQ 0 \\ - -GL ${gl_model} \\ - -ref ${reference_fasta} \\ - -out ${prefix} - - angsd \\ - -nThreads ${task.cpus} \\ - -bam bamlist.txt \\ - -GL ${gl_model} \\ - -doSAF ${dosaf_mode} \\ - ${ref} \\ - ${indF_arg} \\ - ${args} \\ - ${min_ind_arg} \\ - -out ${prefix} - """ - - } else if (gl_model == 4) { - // SYK model requires an error file and -doCounts 1 - """ - ${preamble} - - angsd \\ - -nThreads ${task.cpus} \\ - -bam bamlist.txt \\ - -GL ${gl_model} \\ - -doSAF ${dosaf_mode} \\ - ${ref} \\ - ${indF_arg} \\ - ${errors_arg} \\ - -doCounts 1 \\ - ${args} \\ - ${min_ind_arg} \\ - -out ${prefix} - """ - - } else { - // GL 1 (SAMtools) or GL 2 (GATK) - single angsd call - """ - ${preamble} - - angsd \\ - -nThreads ${task.cpus} \\ - -bam bamlist.txt \\ - -GL ${gl_model} \\ - -doSAF ${dosaf_mode} \\ - ${ref} \\ - ${indF_arg} \\ - ${args} \\ - ${min_ind_arg} \\ - -out ${prefix} - """ - } +// SOAPsnp (-GL 3) needs a calibration pass first to generate the matrix +// angsd reads back in during the doSAF step. -GL 3 is hardcoded here +// since no other args should reach the calibration call. +def calibration = '' +if (gl_model == 3) { + calibration = """ + angsd \\ + -nThreads ${task.cpus} \\ + -bam bamlist.txt \\ + -minQ 0 \\ + -GL ${gl_model} \\ + -ref ${reference_fasta} \\ + -out ${prefix} + """ +} + +// SYK model (-GL 4) needs an error file and -doCounts 1 +def gl4_args = gl_model == 4 ? "${errors_arg} -doCounts 1" : '' + +""" +${preamble} +${calibration} +angsd \\ + -nThreads ${task.cpus} \\ + -bam bamlist.txt \\ + -GL ${gl_model} \\ + -doSAF ${dosaf_mode} \\ + ${ref} \\ + ${indF_arg} \\ + ${gl4_args} \\ + ${args} \\ + ${min_ind_arg} \\ + -out ${prefix} +""" stub: def prefix = task.ext.prefix ?: "${meta.id}" From d0391cd818aa8c88f482996de3322520bff5176b Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Thu, 16 Jul 2026 12:40:25 +0100 Subject: [PATCH 21/24] Refactor calibration comments and update reference argument to ref_anc_arg --- modules/nf-core/angsd/dosaf/main.nf | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index 384c81acad10..14ceb77fbd2d 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -94,8 +94,7 @@ process ANGSD_DOSAF { """ // SOAPsnp (-GL 3) needs a calibration pass first to generate the matrix -// angsd reads back in during the doSAF step. -GL 3 is hardcoded here -// since no other args should reach the calibration call. +// angsd reads back in during the doSAF step. def calibration = '' if (gl_model == 3) { calibration = """ @@ -120,7 +119,7 @@ angsd \\ -bam bamlist.txt \\ -GL ${gl_model} \\ -doSAF ${dosaf_mode} \\ - ${ref} \\ + ${ref_anc_arg} \\ ${indF_arg} \\ ${gl4_args} \\ ${args} \\ From 38400e3b49cb15a77bc6eb09e3bddc6727fbca9f Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Thu, 16 Jul 2026 12:42:26 +0100 Subject: [PATCH 22/24] Update test snapshot --- .../nf-core/angsd/dosaf/tests/main.nf.test.snap | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap index 0d98c75aeb87..8394d92a34db 100644 --- a/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap +++ b/modules/nf-core/angsd/dosaf/tests/main.nf.test.snap @@ -28,7 +28,7 @@ ] } ], - "timestamp": "2026-07-15T16:18:45.373959", + "timestamp": "2026-07-16T12:41:01.480791", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -63,7 +63,7 @@ ] } ], - "timestamp": "2026-07-15T16:18:39.225032", + "timestamp": "2026-07-16T12:40:55.726472", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -98,7 +98,7 @@ ] } ], - "timestamp": "2026-07-15T16:19:13.058938", + "timestamp": "2026-07-16T12:41:27.922853", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -133,7 +133,7 @@ ] } ], - "timestamp": "2026-07-15T16:18:59.939055", + "timestamp": "2026-07-16T12:41:15.856922", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -192,7 +192,7 @@ ] } ], - "timestamp": "2026-07-15T16:19:43.788466", + "timestamp": "2026-07-16T12:41:57.125426", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -227,7 +227,7 @@ ] } ], - "timestamp": "2026-07-15T16:19:05.721228", + "timestamp": "2026-07-16T12:41:21.255121", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" @@ -262,7 +262,7 @@ ] } ], - "timestamp": "2026-07-15T16:19:19.302796", + "timestamp": "2026-07-16T12:41:34.159609", "meta": { "nf-test": "0.9.5", "nextflow": "26.04.1" From 9c050a826c5ad55bb86306e6df3b434e31745bae Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 26 Jul 2026 22:15:55 +0100 Subject: [PATCH 23/24] Restrucure so that soapsnp calibration step is removed, and instead passed as an input. --- modules/nf-core/angsd/dosaf/main.nf | 61 ++++++++++++++--------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index 14ceb77fbd2d..931c3e155c3a 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -13,6 +13,7 @@ process ANGSD_DOSAF { tuple path(ancestral_fasta), path(ancestral_fai) // Optional. Provides ancestral state for unfolded SFS. path(error_file) // Optional. Required for SYK model (-GL 4) only. path(inbreeding_coefficients) // Optional. Required for -doSAF 2 (inbreeding-aware mode). + tuple val(meta2), path(soapsnp_calibration) // Optional. Required for -GL 3. val(gl_model) val(dosaf_mode) @@ -60,6 +61,20 @@ process ANGSD_DOSAF { ) } + // Validate soapsnp calibration directory provided when using -GL 3 + if (gl_model == 3 && !soapsnp_calibration) { + error( + "ANGSD_DOSAF: -GL 3 (soapSNP model) requires calibration directory. Please supply directory." + ) + } + + // Check meta (bams) and meta2 (soapsnp_calibration) are identical to ensure sample order matches + if (gl_model == 3 && meta != meta2) { + error( + "ANGSD_DOSAF: bam metadata and soap calibration metadata do not match!" + ) + } + // Validate GL 4 has error file if (gl_model == 4 && !error_file) { error( @@ -86,46 +101,30 @@ process ANGSD_DOSAF { def indF_arg = inbreeding_coefficients ? "-indF ${inbreeding_coefficients}" : "" def errors_arg = error_file ? "-errors ${error_file}" : "" - // Shared preamble - def preamble = """ + // SOAPsnp model (-GL 3) needs to know the name of the temp directory + def gl3_args = gl_model == 3 ? "-tmpdir ${soapsnp_calibration}" : "" + + // SYK model (-GL 4) needs an error file and -doCounts 1 + def gl4_args = gl_model == 4 ? "${errors_arg} -doCounts 1" : "" + + """ ${touch_ref} ${touch_anc} printf '%s\\n' ${bams} > bamlist.txt - """ - -// SOAPsnp (-GL 3) needs a calibration pass first to generate the matrix -// angsd reads back in during the doSAF step. -def calibration = '' -if (gl_model == 3) { - calibration = """ + angsd \\ -nThreads ${task.cpus} \\ -bam bamlist.txt \\ - -minQ 0 \\ -GL ${gl_model} \\ - -ref ${reference_fasta} \\ + -doSAF ${dosaf_mode} \\ + ${ref_anc_arg} \\ + ${indF_arg} \\ + ${gl3_args} \\ + ${gl4_args} \\ + ${args} \\ + ${min_ind_arg} \\ -out ${prefix} """ -} - -// SYK model (-GL 4) needs an error file and -doCounts 1 -def gl4_args = gl_model == 4 ? "${errors_arg} -doCounts 1" : '' - -""" -${preamble} -${calibration} -angsd \\ - -nThreads ${task.cpus} \\ - -bam bamlist.txt \\ - -GL ${gl_model} \\ - -doSAF ${dosaf_mode} \\ - ${ref_anc_arg} \\ - ${indF_arg} \\ - ${gl4_args} \\ - ${args} \\ - ${min_ind_arg} \\ - -out ${prefix} -""" stub: def prefix = task.ext.prefix ?: "${meta.id}" From f5a53273afc57bf33857a7ead059a57a75e50071 Mon Sep 17 00:00:00 2001 From: Ash Sendell-Price Date: Sun, 26 Jul 2026 22:40:05 +0100 Subject: [PATCH 24/24] Remove meta2 map (not needed). Update meta.yml to match new inputs. --- modules/nf-core/angsd/dosaf/main.nf | 9 +-------- modules/nf-core/angsd/dosaf/meta.yml | 11 ++++++++++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/nf-core/angsd/dosaf/main.nf b/modules/nf-core/angsd/dosaf/main.nf index 931c3e155c3a..2bdbea697f65 100644 --- a/modules/nf-core/angsd/dosaf/main.nf +++ b/modules/nf-core/angsd/dosaf/main.nf @@ -13,7 +13,7 @@ process ANGSD_DOSAF { tuple path(ancestral_fasta), path(ancestral_fai) // Optional. Provides ancestral state for unfolded SFS. path(error_file) // Optional. Required for SYK model (-GL 4) only. path(inbreeding_coefficients) // Optional. Required for -doSAF 2 (inbreeding-aware mode). - tuple val(meta2), path(soapsnp_calibration) // Optional. Required for -GL 3. + path(soapsnp_calibration) // Optional. Required for -GL 3. val(gl_model) val(dosaf_mode) @@ -67,13 +67,6 @@ process ANGSD_DOSAF { "ANGSD_DOSAF: -GL 3 (soapSNP model) requires calibration directory. Please supply directory." ) } - - // Check meta (bams) and meta2 (soapsnp_calibration) are identical to ensure sample order matches - if (gl_model == 3 && meta != meta2) { - error( - "ANGSD_DOSAF: bam metadata and soap calibration metadata do not match!" - ) - } // Validate GL 4 has error file if (gl_model == 4 && !error_file) { diff --git a/modules/nf-core/angsd/dosaf/meta.yml b/modules/nf-core/angsd/dosaf/meta.yml index d62fe6724dae..f43dd766c45c 100644 --- a/modules/nf-core/angsd/dosaf/meta.yml +++ b/modules/nf-core/angsd/dosaf/meta.yml @@ -58,7 +58,7 @@ input: description: Index of the ancestral state genome FASTA file. pattern: "*.{fasta,fa,fasta.gz,fa.gz}.fai" ontologies: - - edam: "http://edamontology.org/format_1929" + - edam: "http://edamontology.org/format_1929" - error_file: type: file description: A file containing per-base substitution error rates for use @@ -71,6 +71,15 @@ input: coefficients. pattern: "*.indF" ontologies: [] + - soapsnp_calibration: + type: directory + description: | + Directory of soapSNP calibration files. Required for use with the SOAPsnp + genotype likelihood model (-GL 3), passed to ANGSD via -tmpdir. + Contains (per sample), a *.counts* file of per-position base/allele + counts and a *.qual* file of recalibrated quality score information. + pattern: "*_calibration_matrix" + ontologies: [] - gl_model: type: integer description: |