Repository: nf-core/modules
Pull request #7802: Clean up hifiasm module + add bin file input
Author: login: prototaxites
Created: 2025-03-14T15:29:20Z | Merged: 2025-03-17T16:03:18Z

- Tidy up hifiasm module code to have just a single script block, modifying inputs with variables
- Move `-o` option to directly before long_read input to ensure positional arguments are clearly separated from other arguments that can be lists of files
- Add optional input for .bin files to allow checkpointed resuming of a previous hifiasm run (e.g. to run in hi-c mode after running standard mode and reduce redundant computation)
- Reorganise output channels a bit
- Update nf-tests and add a test for resuming from bin files
- Add optional output channels for PAF and error-corrected FASTA, when requested

Questions:
- Is anyone using the separate .bin output channels? It might be cleaner to dump them out together but don't want to break anyone's workflow!

## PR checklist

Closes #XXX <!-- If this PR fixes an issue, please link it here! -->

- [x] This comment contains a description of changes (with reason).
- [x] If you've fixed a bug or added code that should be tested, add tests!
- [ ] If you've added a new tool - have you followed the module conventions in the [contribution docs](https://github.com/nf-core/modules/tree/master/.github/CONTRIBUTING.md)
- [ ] If necessary, include test data in your PR.
- [ ] Remove all TODO statements.
- [x] Emit the `versions.yml` file.
- [ ] Follow the naming conventions.
- [ ] Follow the parameters requirements.
- [ ] Follow the input/output options guidelines.
- [ ] Add a resource `label`
- [ ] Use BioConda and BioContainers if possible to fulfil software requirements.
- Ensure that the test works with either Docker / Singularity. Conda CI tests can be quite flaky:
  - For modules:
    - [x] `nf-core modules test <MODULE> --profile docker`
    - [ ] `nf-core modules test <MODULE> --profile singularity`
    - [ ] `nf-core modules test <MODULE> --profile conda`
  - For subworkflows:
    - [ ] `nf-core subworkflows test <SUBWORKFLOW> --profile docker`
    - [ ] `nf-core subworkflows test <SUBWORKFLOW> --profile singularity`
    - [ ] `nf-core subworkflows test <SUBWORKFLOW> --profile conda`



Diff:
diff --git a/modules/nf-core/hifiasm/main.nf b/modules/nf-core/hifiasm/main.nf
index b10978625130..b8f16e3fa997 100644
--- a/modules/nf-core/hifiasm/main.nf
+++ b/modules/nf-core/hifiasm/main.nf
@@ -11,114 +11,100 @@ process HIFIASM {
     tuple val(meta) , path(long_reads)        , path(ul_reads)
     tuple val(meta1), path(paternal_kmer_dump), path(maternal_kmer_dump)
     tuple val(meta2), path(hic_read1)         , path(hic_read2)
+    tuple val(meta3), path(bin_files)
 
     output:
-    tuple val(meta), path("*.r_utg.gfa")       , emit: raw_unitigs
-    tuple val(meta), path("*.ec.bin")          , emit: corrected_reads
-    tuple val(meta), path("*.ovlp.source.bin") , emit: source_overlaps
-    tuple val(meta), path("*.ovlp.reverse.bin"), emit: reverse_overlaps
-    tuple val(meta), path("*.bp.p_ctg.gfa")    , emit: processed_contigs, optional: true
-    tuple val(meta), path("*.p_utg.gfa")       , emit: processed_unitigs, optional: true
-    tuple val(meta), path("*.asm.p_ctg.gfa")   , emit: primary_contigs  , optional: true
-    tuple val(meta), path("*.asm.a_ctg.gfa")   , emit: alternate_contigs, optional: true
-    tuple val(meta), path("*.hap1.p_ctg.gfa")  , emit: paternal_contigs , optional: true
-    tuple val(meta), path("*.hap2.p_ctg.gfa")  , emit: maternal_contigs , optional: true
-    tuple val(meta), path("*.log")             , emit: log
-    path  "versions.yml"                       , emit: versions
+    tuple val(meta), path("*.r_utg.gfa")                             , emit: raw_unitigs
+    tuple val(meta), path("*.bin")                                   , emit: bin_files        , optional: true
+    tuple val(meta), path("*.p_utg.gfa")                             , emit: processed_unitigs, optional: true
+    tuple val(meta), path("${prefix}.{p_ctg,bp.p_ctg,hic.p_ctg}.gfa"), emit: primary_contigs  , optional: true
+    tuple val(meta), path("${prefix}.{a_ctg,hic.a_ctg}.gfa")         , emit: alternate_contigs, optional: true
+    tuple val(meta), path("${prefix}.*.hap1.p_ctg.gfa")              , emit: hap1_contigs     , optional: true
+    tuple val(meta), path("${prefix}.*.hap2.p_ctg.gfa")              , emit: hap2_contigs     , optional: true
+    tuple val(meta), path("*.ec.fa.gz")                              , emit: corrected_reads  , optional: true
+    tuple val(meta), path("*.ovlp.paf.gz")                           , emit: read_overlaps    , optional: true
+    tuple val(meta), path("${prefix}.stderr.log")                    , emit: log
+    path  "versions.yml"                                             , emit: versions
 
     when:
     task.ext.when == null || task.ext.when
 
     script:
     def args = task.ext.args ?: ''
-    def prefix = task.ext.prefix ?: "${meta.id}"
+    prefix = task.ext.prefix ?: "${meta.id}"
 
     def long_reads_sorted = long_reads instanceof List ? long_reads.sort{ it.name } : long_reads
     def ul_reads_sorted = ul_reads instanceof List ? ul_reads.sort{ it.name } : ul_reads
     def ultralong = ul_reads ? "--ul ${ul_reads_sorted}" : ""
 
-    if ((paternal_kmer_dump) && (maternal_kmer_dump) && (hic_read1) && (hic_read2)) {
-        error "Hifiasm Trio-binning and Hi-C integrated should not be used at the same time"
-    } else if ((paternal_kmer_dump) && !(maternal_kmer_dump)) {
-        error "Hifiasm Trio-binning requires maternal data"
-    } else if (!(paternal_kmer_dump) && (maternal_kmer_dump)) {
-        error "Hifiasm Trio-binning requires paternal data"
-    } else if ((paternal_kmer_dump) && (maternal_kmer_dump)) {
-        """
-        hifiasm \\
-            $args \\
-            -o ${prefix}.asm \\
-            -t $task.cpus \\
-            -1 $paternal_kmer_dump \\
-            -2 $maternal_kmer_dump \\
-            $ultralong \\
-            $long_reads_sorted \\
-            2> >( tee ${prefix}.stderr.log >&2 )
+    if([paternal_kmer_dump, maternal_kmer_dump].any() && [hic_read1, hic_read2].any()) {
+        log.error("ERROR: hifiasm trio binning mode and Hi-C phasing can not be used at the same time.")
+    }
 
+    def input_trio = ""
+    if([paternal_kmer_dump, maternal_kmer_dump].any()) {
+        if(![paternal_kmer_dump, maternal_kmer_dump].every()) {
+            log.error("ERROR: Either the maternal or paternal kmer dump is missing!")
+        } else {
+            input_trio = "-1 ${paternal_kmer_dump} -2 ${maternal_kmer_dump}"
+        }
+    }
 
-        cat <<-END_VERSIONS > versions.yml
-        "${task.process}":
-            hifiasm: \$(hifiasm --version 2>&1)
-        END_VERSIONS
-        """
-    } else if ((hic_read1) && !(hic_read2)) {
-        error "Hifiasm Hi-C integrated requires paired-end data (only R1 specified here)"
-    } else if (!(hic_read1) && (hic_read2)) {
-        error "Hifiasm Hi-C integrated requires paired-end data (only R2 specified here)"
-    } else if ((hic_read1) && (hic_read2)) {
-        """
-        hifiasm \\
-            $args \\
-            -o ${prefix}.asm \\
-            -t $task.cpus \\
-            --h1 $hic_read1 \\
-            --h2 $hic_read2 \\
-            $ultralong \\
-            $long_reads \\
-            2> >( tee ${prefix}.stderr.log >&2 )
+    def input_hic = ""
+    if([hic_read1, hic_read2].any()) {
+        if(![hic_read1, hic_read2].every()) {
+            log.error("ERROR: Either the forward or reverse Hi-C reads are missing!")
+        } else {
+            input_hic = "--h1 ${hic_read1} --h2 ${hic_read2}"
+        }
+    }
+    """
+    hifiasm \\
+        $args \\
+        -t ${task.cpus} \\
+        ${input_trio} \\
+        ${input_hic} \\
+        ${ultralong} \\
+        -o ${prefix} \\
+        ${long_reads_sorted} \\
+        2> >( tee ${prefix}.stderr.log >&2 )
 
+    if [ -f ${prefix}.ec.fa ]; then
+        gzip ${prefix}.ec.fa
+    fi
 
-        cat <<-END_VERSIONS > versions.yml
-        "${task.process}":
-            hifiasm: \$(hifiasm --version 2>&1)
-        END_VERSIONS
-        """
-    } else { // Phasing with Hi-C data is not supported yet
-        """
-        hifiasm \\
-            $args \\
-            -o ${prefix}.asm \\
-            -t $task.cpus \\
-            $ultralong \\
-            $long_reads \\
-            2> >( tee ${prefix}.stderr.log >&2 )
+    if [ -f ${prefix}.ovlp.paf ]; then
+        gzip ${prefix}.ovlp.paf
+    fi
 
-        cat <<-END_VERSIONS > versions.yml
-        "${task.process}":
-            hifiasm: \$(hifiasm --version 2>&1)
-        END_VERSIONS
-        """
-    }
-        stub:
-        def args = task.ext.args ?: ''
-        def prefix = task.ext.prefix ?: "${meta.id}"
-        """
-        touch ${prefix}.asm.r_utg.gfa
-        touch ${prefix}.asm.ec.bin
-        touch ${prefix}.asm.ovlp.source.bin
-        touch ${prefix}.asm.ovlp.reverse.bin
-        touch ${prefix}.asm.bp.p_ctg.gfa
-        touch ${prefix}.asm.p_utg.gfa
-        touch ${prefix}.asm.p_ctg.gfa
-        touch ${prefix}.asm.a_ctg.gfa
-        touch ${prefix}.asm.hap1.p_ctg.gfa
-        touch ${prefix}.asm.hap2.p_ctg.gfa
-        touch ${prefix}.stderr.log
+    cat <<-END_VERSIONS > versions.yml
+    "${task.process}":
+        hifiasm: \$(hifiasm --version 2>&1)
+    END_VERSIONS
+    """
 
-        cat <<-END_VERSIONS > versions.yml
-        "${task.process}":
-            hifiasm: \$(hifiasm --version 2>&1)
-        END_VERSIONS
-        """
+    stub:
+    prefix = task.ext.prefix ?: "${meta.id}"
+    """
+    touch ${prefix}.r_utg.gfa
+    touch ${prefix}.ec.bin
+    touch ${prefix}.ovlp.source.bin
+    touch ${prefix}.ovlp.reverse.bin
+    touch ${prefix}.hic.tlb.bin
+    touch ${prefix}.hic.lk.bin
+    touch ${prefix}.bp.p_ctg.gfa
+    touch ${prefix}.p_utg.gfa
+    touch ${prefix}.p_ctg.gfa
+    touch ${prefix}.a_ctg.gfa
+    touch ${prefix}.hap1.p_ctg.gfa
+    touch ${prefix}.hap2.p_ctg.gfa
+    echo "" | gzip > ${prefix}.ec.fa.gz
+    echo "" | gzip > ${prefix}.ovlp.paf.gz
+    touch ${prefix}.stderr.log
 
+    cat <<-END_VERSIONS > versions.yml
+    "${task.process}":
+        hifiasm: \$(hifiasm --version 2>&1)
+    END_VERSIONS
+    """
 }
diff --git a/modules/nf-core/hifiasm/meta.yml b/modules/nf-core/hifiasm/meta.yml
index b255571fbf7f..fcd211dbfe69 100644
--- a/modules/nf-core/hifiasm/meta.yml
+++ b/modules/nf-core/hifiasm/meta.yml
@@ -25,9 +25,11 @@ input:
     - long_reads:
         type: file
         description: Long reads PacBio HiFi reads or ONT reads (requires ext.arg '--ont').
+        ontologies: []
     - ul_reads:
         type: file
         description: ONT long reads to use with --ul.
+        ontologies: []
   - - meta1:
         type: map
         description: |
@@ -36,10 +38,12 @@ input:
         type: file
         description: Yak kmer dump file for paternal reads (can be used for haplotype
           resolution). It can have an arbitrary extension.
+        ontologies: []
     - maternal_kmer_dump:
         type: file
         description: Yak kmer dump file for maternal reads (can be used for haplotype
           resolution). It can have an arbitrary extension.
+        ontologies: []
   - - meta2:
         type: map
         description: |
@@ -47,9 +51,19 @@ input:
     - hic_read1:
         type: file
         description: Hi-C data Forward reads.
+        ontologies: []
     - hic_read2:
         type: file
         description: Hi-C data Reverse reads.
+        ontologies: []
+  - - meta3:
+        type: map
+        description: |
+          Groovy Map containing information about the input bin files
+    - bin_files:
+        type: file
+        description: bin files produced during a previous Hifiasm run
+        ontologies: []
 output:
   - raw_unitigs:
       - meta:
@@ -61,116 +75,133 @@ output:
           type: file
           description: Raw unitigs
           pattern: "*.r_utg.gfa"
-  - corrected_reads:
+  - bin_files:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.ec.bin":
+      - "*.bin":
           type: file
-          description: Corrected reads
-          pattern: "*.ec.bin"
-  - source_overlaps:
-      - meta:
-          type: map
           description: |
-            Groovy Map containing sample information
-            e.g. [ id:'test', single_end:false ]
-      - "*.ovlp.source.bin":
-          type: file
-          description: Source overlaps
-          pattern: "*.ovlp.source.bin"
-  - reverse_overlaps:
+            Binary files containing processed data for hifiasm, including
+            error-corrected reads, read overlaps, and Hi-C alignments. Can
+            be re-used as an input for subsequent re-runs of hifiasm with new
+            inputs or modified parameters in order to save recomputation of
+            initial results, which are the most computationally-expensive
+            steps.
+          pattern: "*.bin"
+  - processed_unitigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.ovlp.reverse.bin":
+      - "*.p_utg.gfa":
           type: file
-          description: Reverse overlaps
-          pattern: "*.ovlp.reverse.bin"
-  - processed_contigs:
+          description: Processed unitigs
+          pattern: "*.p_utg.gfa"
+  - primary_contigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.bp.p_ctg.gfa":
+      - ${prefix}.{p_ctg,bp.p_ctg,hic.p_ctg}.gfa:
           type: file
-          description: Processed contigs
-          pattern: "*.bp.p_ctg.gfa"
-  - processed_unitigs:
+          description: Contigs representing the primary assembly
+          pattern: "${prefix}.{p_ctg,bp.p_ctg,hic.p_ctg}.gfa"
+  - alternate_contigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.p_utg.gfa":
+      - ${prefix}.{a_ctg,hic.a_ctg}.gfa:
           type: file
-          description: Processed unitigs
-          pattern: "*.p_utg.gfa"
-  - primary_contigs:
+          description: Contigs representing the alternative assembly
+          pattern: "${prefix}.{a_ctg,hic.a_ctg}.gfa"
+  - hap1_contigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.asm.p_ctg.gfa":
+          pattern: "${prefix}.*.hap1.p_ctg.gfa"
+      - ${prefix}.*.hap1.p_ctg.gfa:
           type: file
-          description: Primary contigs
-          pattern: "*.asm.p_ctg.gfa"
-  - alternate_contigs:
+          description: |
+            Contigs for the first haplotype. How the haplotypes are represented
+            depends on the input mode; in standard HiFi-only mode, these
+            are partially-phased parental contigs. In Hi-C mode, they
+            are fully phased parental contigs, but the phasing is not maintained
+            between contigs. In trio mode, they are fully phased paternal contigs
+            all originating from a single parental haplotype.
+          pattern: "${prefix}.*.hap1.p_ctg.gfa"
+  - hap2_contigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.asm.a_ctg.gfa":
+          pattern: "${prefix}.*.hap2.p_ctg.gfa"
+      - ${prefix}.*.hap2.p_ctg.gfa:
           type: file
-          description: Alternative contigs
-          pattern: "*.asm.a_ctg.gfa"
-  - paternal_contigs:
+          description: |
+            Contigs for the second haplotype. How the haplotypes are represented
+            depends on the input mode; in standard HiFi-only mode, these
+            are partially-phased parental contigs. In Hi-C mode, they
+            are fully phased parental contigs, but the phasing is not maintained
+            between contigs. In trio mode, they are fully phased paternal contigs
+            all originating from a single parental haplotype.
+          pattern: "${prefix}.*.hap2.p_ctg.gfa"
+  - corrected_reads:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.hap1.p_ctg.gfa":
+      - "*.ec.fa.gz":
           type: file
-          description: Paternal contigs
-          pattern: "*.hap1.p_ctg.gfa"
-  - maternal_contigs:
+          description: |
+            If option --write-ec specified, a gzipped fasta file containing the error corrected
+            reads produced by the hifiasm error correction module
+          pattern: "*.ec.fa.gz"
+  - read_overlaps:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.hap2.p_ctg.gfa":
+      - "*.ovlp.paf.gz":
           type: file
-          description: Maternal contigs
-          pattern: "*.hap2.p_ctg.gfa"
+          description: |
+            If option --write-paf specified, a gzipped paf file describing the overlaps
+            among all error-corrected reads
+          pattern: "*.ovlp.paf.gz"
   - log:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.log":
+          pattern: "*.stderr.log"
+      - ${prefix}.stderr.log:
           type: file
           description: Stderr log
-          pattern: "*.log"
+          pattern: "*.stderr.log"
   - versions:
       - versions.yml:
           type: file
           description: File containing software versions
           pattern: "versions.yml"
+          ontologies: []
 authors:
   - "@sidorov-si"
   - "@scorreard"
   - "@mbeavitt"
   - "@schmytzi"
+  - "@prototaxites"
 maintainers:
   - "@sidorov-si"
   - "@scorreard"
diff --git a/modules/nf-core/hifiasm/tests/main.nf.test b/modules/nf-core/hifiasm/tests/main.nf.test
index b426d6f017a9..53edf404a285 100644
--- a/modules/nf-core/hifiasm/tests/main.nf.test
+++ b/modules/nf-core/hifiasm/tests/main.nf.test
@@ -9,8 +9,98 @@ nextflow_process {
     tag "modules_nfcore"
     tag "hifiasm"
 
-    test("homo_sapiens pacbio hifi [fastq, [,], [,] ]") {
+    test("homo_sapiens pacbio hifi [fastq, [,], [,], [,]]") {
         when {
+            params {
+                extra_output = "--write-ec --write-paf"
+            }
+
+            process {
+                """
+                input[0] = [
+                    [ id : 'test'],
+                    file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pacbio/fastq/test_hifi.fastq.gz', checkIfExists: true),
+                    []
+                ]
+                input[1] = [
+                    [],
+                    [],
+                    []
+                ]
+                input[2] = [
+                    [],
+                    [],
+                    []
+                ]
+                input[3] = [
+                    [],
+                    []
+                ]
+                """
+            }
+        }
+        then {
+            def bin_files = process.out.bin_files.get(0).get(1).collect { bin -> file(bin).name }
+            def expected_bin_files = [
+                "test.ec.bin",
+                "test.ovlp.reverse.bin",
+                "test.ovlp.source.bin"
+            ]
+
+            assertAll(
+                { assert process.success },
+                { assertContainsInAnyOrder(bin_files, expected_bin_files) },
+                { assert file(process.out.log.get(0).get(1)).exists() },
+                { assert snapshot(
+                    process.out.raw_unitigs,
+                    process.out.processed_unitigs,
+                    process.out.primary_contigs,
+                    process.out.hap1_contigs,
+                    process.out.hap2_contigs,
+                    process.out.fasta,
+                    process.out.paf,
+                    process.out.versions
+                ).match() }
+            )
+        }
+    }
+
+    test("homo_sapiens pacbio hifi [fastq, [,], [,], [bin] ]") {
+
+        setup {
+            run("HIFIASM", alias: "HIFIASM_INITIAL") {
+                script "../main.nf"
+                process {
+                    """
+                    input[0] = [
+                        [ id : 'test'],
+                        file(params.modules_testdata_base_path + 'genomics/homo_sapiens/pacbio/fastq/test_hifi.fastq.gz', checkIfExists: true),
+                        []
+                    ]
+                    input[1] = [
+                        [],
+                        [],
+                        []
+                    ]
+                    input[2] = [
+                        [],
+                        [],
+                        []
+                    ]
+                    input[3] = [
+                        [],
+                        []
+                    ]
+                    """
+                }
+            }
+        }
+
+        when {
+            params {
+                extra_output = ""
+            }
+
             process {
                 """
                 input[0] = [
@@ -28,31 +118,34 @@ nextflow_process {
                     [],
                     []
                 ]
+                input[3] = HIFIASM_INITIAL.out.bin_files
                 """
             }
         }
         then {
             assertAll(
                 { assert process.success },
-                { assert file(process.out.corrected_reads.get(0).get(1)).exists() },
-                { assert file(process.out.source_overlaps.get(0).get(1)).exists() },
-                { assert file(process.out.reverse_overlaps.get(0).get(1)).exists() },
                 { assert file(process.out.log.get(0).get(1)).exists() },
+                { assert file(process.out.log.get(0).get(1)).readLines().first().contains("Reads has been loaded.") },
                 { assert snapshot(
                     process.out.raw_unitigs,
-                    process.out.processed_contigs,
                     process.out.processed_unitigs,
-                    process.out.paternal_contigs,
-                    process.out.maternal_contigs,
+                    process.out.primary_contigs,
+                    process.out.hap1_contigs,
+                    process.out.hap2_contigs,
                     process.out.versions
                 ).match() }
             )
         }
     }
 
-    test("homo_sapiens pacbio hifi [fastq x2, [,], [,] ]") {
+    test("homo_sapiens pacbio hifi [fastq x2, [,], [,], [,] ]") {
 
         when {
+            params {
+                extra_output = ""
+            }
+
             process {
                 """
                 input[0] = Channel.of([
@@ -73,30 +166,43 @@ nextflow_process {
                     [],
                     []
                 ]
+                input[3] = [
+                    [],
+                    []
+                ]
                 """
             }
         }
         then {
+            def bin_files = process.out.bin_files.get(0).get(1).collect { bin -> file(bin).name }
+            def expected_bin_files = [
+                "test.ec.bin",
+                "test.ovlp.reverse.bin",
+                "test.ovlp.source.bin"
+            ]
+
             assertAll(
                 { assert process.success },
-                { assert file(process.out.corrected_reads.get(0).get(1)).exists() },
-                { assert file(process.out.source_overlaps.get(0).get(1)).exists() },
-                { assert file(process.out.reverse_overlaps.get(0).get(1)).exists() },
+                { assertContainsInAnyOrder(bin_files, expected_bin_files) },
                 { assert file(process.out.log.get(0).get(1)).exists() },
                 { assert snapshot(
                     process.out.raw_unitigs,
-                    process.out.processed_contigs,
                     process.out.processed_unitigs,
-                    process.out.paternal_contigs,
-                    process.out.maternal_contigs,
+                    process.out.primary_contigs,
+                    process.out.hap1_contigs,
+                    process.out.hap2_contigs,
                     process.out.versions
                 ).match() }
             )
         }
     }
 
-    test("homo_sapiens pacbio hifi [fastq, [yak, yak], [,] ]") {
+    test("homo_sapiens pacbio hifi [fastq, [yak, yak], [,], [,] ]") {
         when {
+            params {
+                extra_output = ""
+            }
+
             process {
                 """
                 input[0] = [
@@ -114,29 +220,47 @@ nextflow_process {
                     [],
                     []
                 ]
+                input[3] = [
+                    [],
+                    []
+                ]
                 """
             }
         }
         then {
+            def bin_files = process.out.bin_files.get(0).get(1).collect { bin -> file(bin).name }
+            def expected_bin_files = [
+                "test.ec.bin",
+                "test.ovlp.reverse.bin",
+                "test.ovlp.source.bin",
+                "test.hap1.phase.bin",
+                "test.hap2.phase.bin"
+            ]
+
             assertAll(
                 { assert process.success },
-                { assert file(process.out.corrected_reads.get(0).get(1)).exists() },
-                { assert file(process.out.source_overlaps.get(0).get(1)).exists() },
-                { assert file(process.out.reverse_overlaps.get(0).get(1)).exists() },
+                { assertContainsInAnyOrder(bin_files, expected_bin_files) },
+                { assert file(process.out.hap1_contigs.get(0).get(1)).exists() },
+                { assert file(process.out.hap1_contigs.get(0).get(1)).name == "test.dip.hap1.p_ctg.gfa" },
+                { assert file(process.out.hap2_contigs.get(0).get(1)).exists() },
+                { assert file(process.out.hap2_contigs.get(0).get(1)).name == "test.dip.hap2.p_ctg.gfa" },
                 { assert file(process.out.log.get(0).get(1)).exists() },
-                { assert file(process.out.maternal_contigs.get(0).get(1)).length() == 0},
                 { assert snapshot(
                     process.out.raw_unitigs,
                     process.out.processed_unitigs,
-                    process.out.paternal_contigs,
+                    process.out.hap1_contigs,
                     process.out.versions
                 ).match() }
             )
         }
     }
 
-    test("homo_sapiens pacbio hifi [fastq, [,], [fastq, fastq] ]") {
+    test("homo_sapiens pacbio hifi [fastq, [,], [fastq, fastq], [,] ]") {
         when {
+            params {
+                extra_output = ""
+            }
+
             process {
                 """
                 input[0] = [
@@ -154,29 +278,49 @@ nextflow_process {
                     file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_1.fastq.gz', checkIfExists: true),
                     file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_2.fastq.gz', checkIfExists: true)
                 ]
+                input[3] = [
+                    [],
+                    []
+                ]
                 """
             }
         }
         then {
+            def bin_files = process.out.bin_files.get(0).get(1).collect { bin -> file(bin).name }
+            def expected_bin_files = [
+                "test.ec.bin",
+                "test.ovlp.reverse.bin",
+                "test.ovlp.source.bin",
+                "test.hic.lk.bin",
+                "test.hic.tlb.bin"
+            ]
+
             assertAll(
                 { assert process.success },
-                { assert file(process.out.corrected_reads.get(0).get(1)).exists() },
-                { assert file(process.out.source_overlaps.get(0).get(1)).exists() },
-                { assert file(process.out.reverse_overlaps.get(0).get(1)).exists() },
+                { assertContainsInAnyOrder(bin_files, expected_bin_files) },
+                { assert file(process.out.hap1_contigs.get(0).get(1)).exists() },
+                { assert file(process.out.hap1_contigs.get(0).get(1)).name == "test.hic.hap1.p_ctg.gfa" },
+                { assert file(process.out.hap2_contigs.get(0).get(1)).exists() },
+                { assert file(process.out.hap2_contigs.get(0).get(1)).name == "test.hic.hap2.p_ctg.gfa" },
                 { assert file(process.out.log.get(0).get(1)).exists() },
-                { assert file(process.out.maternal_contigs.get(0).get(1)).length() == 0},
                 { assert snapshot(
                     process.out.raw_unitigs,
                     process.out.processed_unitigs,
-                    process.out.paternal_contigs,
+                    process.out.primary_contigs,
+                    process.out.alternate_contigs,
+                    process.out.hap1_contigs,
                     process.out.versions
                 ).match() }
             )
         }
     }
 
-    test("homo_sapiens pacbio hifi [fastq, [yak, yak], [fastq, fastq] ]") {
+    test("homo_sapiens pacbio hifi [fastq, [yak, yak], [fastq, fastq], [,] ]") {
         when {
+            params {
+                extra_output = ""
+            }
+            process {
                 """
                 input[0] = [
                     [ id : 'test'],
@@ -193,7 +337,12 @@ nextflow_process {
                     file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_1.fastq.gz, checkIfExists: true),
                     file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_2.fastq.gz, checkIfExists: true)
                 ]
+                input[3] = [
+                    [],
+                    []
+                ]
                 """
+            }
         }
         then {
             assertAll(
@@ -202,8 +351,13 @@ nextflow_process {
         }
     }
 
-    test("homo_sapiens pacbio hifi [fastq, [yak, ], [,] ]") {
+    test("homo_sapiens pacbio hifi [fastq, [yak, ], [,], [,] ]") {
         when {
+            params {
+                extra_output = ""
+            }
+
+            process {
                 """
                 input[0] = [
                     [ id : 'test'],
@@ -216,7 +370,12 @@ nextflow_process {
                     []
                 ]
                 input[2] = []
+                input[3] = [
+                    [],
+                    []
+                ]
                 """
+            }
         }
         then {
             assertAll(
@@ -225,8 +384,13 @@ nextflow_process {
         }
     }
 
-    test("homo_sapiens pacbio hifi [fastq, [,], [, fastq] ]") {
+    test("homo_sapiens pacbio hifi [fastq, [,], [, fastq], [,] ]") {
         when {
+            params {
+                extra_output = ""
+            }
+
+            process {
                 """
                 input[0] = [
                     [ id : 'test'],
@@ -239,7 +403,12 @@ nextflow_process {
                     [],
                     file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/fastq/test_2.fastq.gz', checkIfExists: true)
                 ]
+                input[3] = [
+                    [],
+                    []
+                ]
                 """
+            }
         }
         then {
             assertAll(
@@ -248,9 +417,13 @@ nextflow_process {
         }
     }
 
-    test("homo_sapiens pacbio hifi [fastq, [,], [,] ] - stub") {
+    test("homo_sapiens pacbio hifi [fastq, [,], [,], [,] ] - stub") {
         options "-stub"
         when {
+            params {
+                extra_output = ""
+            }
+
             process {
                 """
                 input[0] = [
@@ -268,6 +441,10 @@ nextflow_process {
                     [],
                     []
                 ]
+                input[3] = [
+                    [],
+                    []
+                ]
                 """
             }
         }
diff --git a/modules/nf-core/hifiasm/tests/main.nf.test.snap b/modules/nf-core/hifiasm/tests/main.nf.test.snap
index 508e4c27afc9..dcf22cd53629 100644
--- a/modules/nf-core/hifiasm/tests/main.nf.test.snap
+++ b/modules/nf-core/hifiasm/tests/main.nf.test.snap
@@ -1,12 +1,12 @@
 {
-    "homo_sapiens pacbio hifi [fastq, [,], [,] ]": {
+    "homo_sapiens pacbio hifi [fastq, [,], [fastq, fastq], [,] ]": {
         "content": [
             [
                 [
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.r_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
+                    "test.hic.r_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
                 ]
             ],
             [
@@ -14,7 +14,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.p_ctg.gfa:md5,c3225425a73a8d6d46536dab72380650"
+                    "test.hic.p_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
                 ]
             ],
             [
@@ -22,23 +22,18 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.p_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
+                    "test.hic.p_ctg.gfa:md5,6d0ec1ec65b1d2b295ac94b6fef25a27"
                 ]
             ],
             [
-                [
-                    {
-                        "id": "test"
-                    },
-                    "test.asm.bp.hap1.p_ctg.gfa:md5,78a86b6d5741a680e22a427ca9faa74a"
-                ]
+
             ],
             [
                 [
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.hap2.p_ctg.gfa:md5,ac2116fd2f22c67d4c304cbf9b9f7793"
+                    "test.hic.hap1.p_ctg.gfa:md5,f67a8fdfa756961360732c79d189054d"
                 ]
             ],
             [
@@ -47,18 +42,18 @@
         ],
         "meta": {
             "nf-test": "0.9.2",
-            "nextflow": "24.10.1"
+            "nextflow": "24.10.5"
         },
-        "timestamp": "2024-11-28T10:51:30.175326435"
+        "timestamp": "2025-03-14T16:39:37.645315715"
     },
-    "homo_sapiens pacbio hifi [fastq x2, [,], [,] ]": {
+    "homo_sapiens pacbio hifi [fastq, [,], [,], [bin] ]": {
         "content": [
             [
                 [
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.r_utg.gfa:md5,e6e38ac76f6b73142c3fe403f71d27b0"
+                    "test.bp.r_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
                 ]
             ],
             [
@@ -66,7 +61,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.p_ctg.gfa:md5,43890a1832d8f26de263e57dc5e3b8de"
+                    "test.bp.p_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
                 ]
             ],
             [
@@ -74,7 +69,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.p_utg.gfa:md5,e6e38ac76f6b73142c3fe403f71d27b0"
+                    "test.bp.p_ctg.gfa:md5,c3225425a73a8d6d46536dab72380650"
                 ]
             ],
             [
@@ -82,7 +77,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.hap1.p_ctg.gfa:md5,7d7ea2bed472de263f6ec3521959b0d9"
+                    "test.bp.hap1.p_ctg.gfa:md5,78a86b6d5741a680e22a427ca9faa74a"
                 ]
             ],
             [
@@ -90,7 +85,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.bp.hap2.p_ctg.gfa:md5,ce096a66c9bba039c6a22ba9e9409d01"
+                    "test.bp.hap2.p_ctg.gfa:md5,ac2116fd2f22c67d4c304cbf9b9f7793"
                 ]
             ],
             [
@@ -99,18 +94,26 @@
         ],
         "meta": {
             "nf-test": "0.9.2",
-            "nextflow": "24.10.3"
+            "nextflow": "24.10.5"
         },
-        "timestamp": "2025-03-04T10:53:37.361240273"
+        "timestamp": "2025-03-14T15:07:54.108750194"
     },
-    "homo_sapiens pacbio hifi [fastq, [,], [fastq, fastq] ]": {
+    "homo_sapiens pacbio hifi [fastq x2, [,], [,], [,] ]": {
         "content": [
             [
                 [
                     {
                         "id": "test"
                     },
-                    "test.asm.hic.r_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
+                    "test.bp.r_utg.gfa:md5,e6e38ac76f6b73142c3fe403f71d27b0"
+                ]
+            ],
+            [
+                [
+                    {
+                        "id": "test"
+                    },
+                    "test.bp.p_utg.gfa:md5,e6e38ac76f6b73142c3fe403f71d27b0"
                 ]
             ],
             [
@@ -118,7 +121,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.hic.p_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
+                    "test.bp.p_ctg.gfa:md5,43890a1832d8f26de263e57dc5e3b8de"
                 ]
             ],
             [
@@ -126,7 +129,15 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.hic.hap1.p_ctg.gfa:md5,f67a8fdfa756961360732c79d189054d"
+                    "test.bp.hap1.p_ctg.gfa:md5,7d7ea2bed472de263f6ec3521959b0d9"
+                ]
+            ],
+            [
+                [
+                    {
+                        "id": "test"
+                    },
+                    "test.bp.hap2.p_ctg.gfa:md5,ce096a66c9bba039c6a22ba9e9409d01"
                 ]
             ],
             [
@@ -135,11 +146,11 @@
         ],
         "meta": {
             "nf-test": "0.9.2",
-            "nextflow": "24.10.1"
+            "nextflow": "24.10.5"
         },
-        "timestamp": "2024-11-28T10:52:15.111066189"
+        "timestamp": "2025-03-14T15:08:24.563745561"
     },
-    "homo_sapiens pacbio hifi [fastq, [,], [,] ] - stub": {
+    "homo_sapiens pacbio hifi [fastq, [,], [,], [,] ] - stub": {
         "content": [
             {
                 "0": [
@@ -147,7 +158,7 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.r_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.r_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
                 "1": [
@@ -155,18 +166,16 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.ec.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        [
+                            "test.ec.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.hic.lk.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.hic.tlb.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.ovlp.reverse.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.ovlp.source.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        ]
                     ]
                 ],
                 "10": [
-                    [
-                        {
-                            "id": "test"
-                        },
-                        "test.stderr.log:md5,d41d8cd98f00b204e9800998ecf8427e"
-                    ]
-                ],
-                "11": [
                     "versions.yml:md5,a2ea36e18c39850b1680302d9f6c950f"
                 ],
                 "2": [
@@ -174,7 +183,7 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.ovlp.source.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.p_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
                 "3": [
@@ -182,7 +191,10 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.ovlp.reverse.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        [
+                            "test.bp.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        ]
                     ]
                 ],
                 "4": [
@@ -190,31 +202,21 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.bp.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.a_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
                 "5": [
-                    [
-                        {
-                            "id": "test"
-                        },
-                        "test.asm.p_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
-                    ]
+
                 ],
                 "6": [
-                    [
-                        {
-                            "id": "test"
-                        },
-                        "test.asm.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
-                    ]
+
                 ],
                 "7": [
                     [
                         {
                             "id": "test"
                         },
-                        "test.asm.a_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.ec.fa.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
                     ]
                 ],
                 "8": [
@@ -222,7 +224,7 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.hap1.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.ovlp.paf.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
                     ]
                 ],
                 "9": [
@@ -230,7 +232,7 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.hap2.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.stderr.log:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
                 "alternate_contigs": [
@@ -238,55 +240,54 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.a_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.a_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
-                "corrected_reads": [
+                "bin_files": [
                     [
                         {
                             "id": "test"
                         },
-                        "test.asm.ec.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        [
+                            "test.ec.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.hic.lk.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.hic.tlb.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.ovlp.reverse.bin:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.ovlp.source.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        ]
                     ]
                 ],
-                "log": [
+                "corrected_reads": [
                     [
                         {
                             "id": "test"
                         },
-                        "test.stderr.log:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.ec.fa.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
                     ]
                 ],
-                "maternal_contigs": [
-                    [
-                        {
-                            "id": "test"
-                        },
-                        "test.asm.hap2.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
-                    ]
+                "hap1_contigs": [
+
                 ],
-                "paternal_contigs": [
-                    [
-                        {
-                            "id": "test"
-                        },
-                        "test.asm.hap1.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
-                    ]
+                "hap2_contigs": [
+
                 ],
-                "primary_contigs": [
+                "log": [
                     [
                         {
                             "id": "test"
                         },
-                        "test.asm.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.stderr.log:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
-                "processed_contigs": [
+                "primary_contigs": [
                     [
                         {
                             "id": "test"
                         },
-                        "test.asm.bp.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        [
+                            "test.bp.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e",
+                            "test.p_ctg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        ]
                     ]
                 ],
                 "processed_unitigs": [
@@ -294,7 +295,7 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.p_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.p_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
                 "raw_unitigs": [
@@ -302,23 +303,15 @@
                         {
                             "id": "test"
                         },
-                        "test.asm.r_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.r_utg.gfa:md5,d41d8cd98f00b204e9800998ecf8427e"
                     ]
                 ],
-                "reverse_overlaps": [
+                "read_overlaps": [
                     [
                         {
                             "id": "test"
                         },
-                        "test.asm.ovlp.reverse.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
-                    ]
-                ],
-                "source_overlaps": [
-                    [
-                        {
-                            "id": "test"
-                        },
-                        "test.asm.ovlp.source.bin:md5,d41d8cd98f00b204e9800998ecf8427e"
+                        "test.ovlp.paf.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
                     ]
                 ],
                 "versions": [
@@ -328,18 +321,72 @@
         ],
         "meta": {
             "nf-test": "0.9.2",
-            "nextflow": "24.10.1"
+            "nextflow": "24.10.5"
+        },
+        "timestamp": "2025-03-17T13:55:35.007180089"
+    },
+    "homo_sapiens pacbio hifi [fastq, [,], [,], [,]]": {
+        "content": [
+            [
+                [
+                    {
+                        "id": "test"
+                    },
+                    "test.bp.r_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
+                ]
+            ],
+            [
+                [
+                    {
+                        "id": "test"
+                    },
+                    "test.bp.p_utg.gfa:md5,6a200e4bcb5d8d8fa6ed75874d26edc6"
+                ]
+            ],
+            [
+                [
+                    {
+                        "id": "test"
+                    },
+                    "test.bp.p_ctg.gfa:md5,c3225425a73a8d6d46536dab72380650"
+                ]
+            ],
+            [
+                [
+                    {
+                        "id": "test"
+                    },
+                    "test.bp.hap1.p_ctg.gfa:md5,78a86b6d5741a680e22a427ca9faa74a"
+                ]
+            ],
+            [
+                [
+                    {
+                        "id": "test"
+                    },
+                    "test.bp.hap2.p_ctg.gfa:md5,ac2116fd2f22c67d4c304cbf9b9f7793"
+                ]
+            ],
+            null,
+            null,
+            [
+                "versions.yml:md5,a2ea36e18c39850b1680302d9f6c950f"
+            ]
+        ],
+        "meta": {
+            "nf-test": "0.9.2",
+            "nextflow": "24.10.5"
         },
-        "timestamp": "2024-11-28T10:53:06.003871811"
+        "timestamp": "2025-03-17T13:53:18.392096098"
     },
-    "homo_sapiens pacbio hifi [fastq, [yak, yak], [,] ]": {
+    "homo_sapiens pacbio hifi [fastq, [yak, yak], [,], [,] ]": {
         "content": [
             [
                 [
                     {
                         "id": "test"
                     },
-                    "test.asm.dip.r_utg.gfa:md5,68361ac3e8babd51f3891d1637ca0fdc"
+                    "test.dip.r_utg.gfa:md5,68361ac3e8babd51f3891d1637ca0fdc"
                 ]
             ],
             [
@@ -347,7 +394,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.dip.p_utg.gfa:md5,68361ac3e8babd51f3891d1637ca0fdc"
+                    "test.dip.p_utg.gfa:md5,68361ac3e8babd51f3891d1637ca0fdc"
                 ]
             ],
             [
@@ -355,7 +402,7 @@
                     {
                         "id": "test"
                     },
-                    "test.asm.dip.hap1.p_ctg.gfa:md5,eed5da5f3dd415dbb711edb61a09802f"
+                    "test.dip.hap1.p_ctg.gfa:md5,eed5da5f3dd415dbb711edb61a09802f"
                 ]
             ],
             [
@@ -364,8 +411,8 @@
         ],
         "meta": {
             "nf-test": "0.9.2",
-            "nextflow": "24.10.1"
+            "nextflow": "24.10.5"
         },
-        "timestamp": "2024-11-28T10:51:45.301359171"
+        "timestamp": "2025-03-14T16:39:20.650653593"
     }
 }
\ No newline at end of file
diff --git a/modules/nf-core/hifiasm/tests/nextflow.config b/modules/nf-core/hifiasm/tests/nextflow.config
index 8dc2ae48a298..ead4b539a94f 100644
--- a/modules/nf-core/hifiasm/tests/nextflow.config
+++ b/modules/nf-core/hifiasm/tests/nextflow.config
@@ -1,3 +1,3 @@
 process {
-    ext.args = "-f0"
+    ext.args = "-f0 ${params.extra_output}"
 }


Reviews:
user: login: muffato
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-15T11:18:34Z
user: login: fellen31
body: > Is anyone using the separate .bin output channels? It might be cleaner to dump them out together but don't want to break anyone's workflow!

Would there be any other use case for the bin files than to resume the run? Thanks for updating the module to make that possible!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T09:57:25Z
user: login: muffato
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-17T13:47:54Z
user: login: muffato
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-17T16:00:21Z

Review comments:
diff_hunk: @@ -117,55 +126,61 @@ output:
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.asm.p_ctg.gfa":
+          pattern: "${prefix}.{p_ctg,bp.p_ctg,hic.p_ctg}.gfa"
+      - ${prefix}.{p_ctg,bp.p_ctg,hic.p_ctg}.gfa:
           type: file
           description: Primary contigs
-          pattern: "*.asm.p_ctg.gfa"
+          pattern: "${prefix}.{p_ctg,bp.p_ctg,hic.p_ctg}.gfa"
   - alternate_contigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.asm.a_ctg.gfa":
+          pattern: "${prefix}.{a_ctg,hic.a_ctg}.gfa"
+      - ${prefix}.{a_ctg,hic.a_ctg}.gfa:
           type: file
           description: Alternative contigs
-          pattern: "*.asm.a_ctg.gfa"
-  - paternal_contigs:
+          pattern: "${prefix}.{a_ctg,hic.a_ctg}.gfa"
+  - hap1_contigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.hap1.p_ctg.gfa":
+          pattern: "${prefix}.*.hap1.p_ctg.gfa"
+      - ${prefix}.*.hap1.p_ctg.gfa:
           type: file
           description: Paternal contigs
-          pattern: "*.hap1.p_ctg.gfa"
-  - maternal_contigs:
+          pattern: "${prefix}.*.hap1.p_ctg.gfa"
+  - hap2_contigs:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.hap2.p_ctg.gfa":
+          pattern: "${prefix}.*.hap2.p_ctg.gfa"
+      - ${prefix}.*.hap2.p_ctg.gfa:
           type: file
-          description: Maternal contigs
-          pattern: "*.hap2.p_ctg.gfa"
+          description: Paternal contigs
+          pattern: "${prefix}.*.hap2.p_ctg.gfa"
   - log:
       - meta:
           type: map
           description: |
             Groovy Map containing sample information
             e.g. [ id:'test', single_end:false ]
-      - "*.log":
+          pattern: "*.stderr.log"
+      - ${prefix}.stderr.log:
           type: file
           description: Stderr log
-          pattern: "*.log"
+          pattern: "*.stderr.log"
   - versions:
       - versions.yml:
           type: file
           description: File containing software versions
           pattern: "versions.yml"
+          ontologies: []
 authors:
path: modules/nf-core/hifiasm/meta.yml
user: login: muffato
body: Add yourself as an author. You deserved it ;)
created_at: 2025-03-15T11:13:40Z
author_association: MEMBER
diff_hunk: @@ -11,114 +11,100 @@ process HIFIASM {
     tuple val(meta) , path(long_reads)        , path(ul_reads)
     tuple val(meta1), path(paternal_kmer_dump), path(maternal_kmer_dump)
     tuple val(meta2), path(hic_read1)         , path(hic_read2)
+    tuple val(meta3), path(bin_files)
 
     output:
-    tuple val(meta), path("*.r_utg.gfa")       , emit: raw_unitigs
-    tuple val(meta), path("*.ec.bin")          , emit: corrected_reads
-    tuple val(meta), path("*.ovlp.source.bin") , emit: source_overlaps
-    tuple val(meta), path("*.ovlp.reverse.bin"), emit: reverse_overlaps
-    tuple val(meta), path("*.bp.p_ctg.gfa")    , emit: processed_contigs, optional: true
-    tuple val(meta), path("*.p_utg.gfa")       , emit: processed_unitigs, optional: true
-    tuple val(meta), path("*.asm.p_ctg.gfa")   , emit: primary_contigs  , optional: true
-    tuple val(meta), path("*.asm.a_ctg.gfa")   , emit: alternate_contigs, optional: true
-    tuple val(meta), path("*.hap1.p_ctg.gfa")  , emit: paternal_contigs , optional: true
-    tuple val(meta), path("*.hap2.p_ctg.gfa")  , emit: maternal_contigs , optional: true
-    tuple val(meta), path("*.log")             , emit: log
-    path  "versions.yml"                       , emit: versions
+    tuple val(meta), path("*.r_utg.gfa")                             , emit: raw_unitigs
+    tuple val(meta), path("*.bin")                                   , emit: bin_files        , optional: true
+    tuple val(meta), path("*.p_utg.gfa")                             , emit: processed_unitigs, optional: true
+    tuple val(meta), path("${prefix}.{p_ctg,bp.p_ctg,hic.p_ctg}.gfa"), emit: primary_contigs  , optional: true
+    tuple val(meta), path("${prefix}.{a_ctg,hic.a_ctg}.gfa")         , emit: alternate_contigs, optional: true
+    tuple val(meta), path("${prefix}.*.hap1.p_ctg.gfa")              , emit: hap1_contigs     , optional: true
+    tuple val(meta), path("${prefix}.*.hap2.p_ctg.gfa")              , emit: hap2_contigs     , optional: true
+    tuple val(meta), path("*.ec.fa.gz")                              , emit: fasta            , optional: true
+    tuple val(meta), path("*.ovlp.paf.gz")                           , emit: paf              , optional: true
path: modules/nf-core/hifiasm/main.nf
user: login: muffato
body: Could you give names that tell about what's in files rather than their format ? e.g. `corrected_reads` for `fasta`, and `read_overlap` for `paf`.
created_at: 2025-03-17T13:47:50Z
author_association: MEMBER

PR comments:
user: login: prototaxites
created_at: 2025-03-14T15:36:25Z
body: I'm not sure what to do about the empty file linting tests - I don't think there's enough data in the tests to produce non-empty files
author_association: CONTRIBUTOR
user: login: SPPearce
created_at: 2025-03-14T16:21:32Z
body: > I'm not sure what to do about the empty file linting tests - I don't think there's enough data in the tests to produce non-empty files

Typically you then replace the md5sum test with a file existence check.
author_association: CONTRIBUTOR
user: login: prototaxites
created_at: 2025-03-14T16:25:04Z
body: > Typically you then replace the md5sum test with a file existence check.

Is this standard practice for e.g. stub tests? I don't think I've ever written a test that way before.
author_association: CONTRIBUTOR
user: login: SPPearce
created_at: 2025-03-15T07:30:36Z
body: > > Typically you then replace the md5sum test with a file existence check.
> 
> Is this standard practice for e.g. stub tests? I don't think I've ever written a test that way before.

tests are allowed empty files provided they have "stub" in the name of the test
author_association: CONTRIBUTOR
user: login: prototaxites
created_at: 2025-03-17T10:01:31Z
body: > > Is anyone using the separate .bin output channels? It might be cleaner to dump them out together but don't want to break anyone's workflow!
> 
> Would there be any other use case for the bin files than to resume the run? Thanks for updating the module to make that possible!

I'm not aware of any other uses - you can dump some of the data out of them using hifiasm (e.g. `--write-ec` which will write the error-corrected reads bin file to fasta) - and am currently in the process of adding these outputs to the module. But I'm not aware that any other tool would use these outputs (and if you needed a specific one, you could still parse the output .bin file channel for the needed file).
author_association: CONTRIBUTOR
user: login: prototaxites
created_at: 2025-03-17T10:24:23Z
body: OK, I've added optional outputs for the error-corrected reads, and read overlaps in PAF format. I've also collapsed the bin files to a single output channel. I've also updated the documentation to add a bit more useful description about the outputs.

If these changes look good to folk I can go ahead and merge.
author_association: CONTRIBUTOR