diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6fefb91c..61c337e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## dev
+### New features
+
+- Added `expansionhunter` as a new caller. This caller is unique as no postprocessing is done on the outputs of the caller.
+- Added `sex` as a samplesheet field. This is an optional field to improve the repeat expansion calls from Expansionhunter.
+
+### Fixes
+
- Fixes a small issue with the VEP config (`.split()` error) by replacing it with the `name` attribute.
## v1.13.3
diff --git a/assets/schema_input.json b/assets/schema_input.json
index 1f16bcc1..41a8d630 100644
--- a/assets/schema_input.json
+++ b/assets/schema_input.json
@@ -94,6 +94,12 @@
"type": "boolean",
"default": false,
"meta": "msi"
+ },
+ "sex": {
+ "type": "string",
+ "default": null,
+ "meta": "sex",
+ "enum": ["male", "female"]
}
},
"anyOf": [
diff --git a/conf/modules.config b/conf/modules.config
index 502a0dc2..4cf4f900 100644
--- a/conf/modules.config
+++ b/conf/modules.config
@@ -321,6 +321,21 @@ process {
ext.prefix = {"${meta.sample}.${meta.roc_type}"}
}
+ /*
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ REPEATS DETECTION
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+ withName: ".*CRAM_REPEAT_EXPANSIONHUNTER:EXPANSIONHUNTER\$" {
+ ext.args = { meta.sex ? "--sex ${meta.sex}" : '' }
+ }
+
+ withName: ".*CRAM_REPEAT_EXPANSIONHUNTER:BCFTOOLS_ANNOTATE\$" {
+ ext.args = "-c INFO/REPREF:=INFO/REF --output-type z --write-index=tbi"
+ ext.prefix = { "${meta.id}.expansionhunter" }
+ }
+
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FINAL PROCESSES
diff --git a/conf/test.config b/conf/test.config
index 487ae100..79cb748f 100644
--- a/conf/test.config
+++ b/conf/test.config
@@ -38,6 +38,8 @@ params {
strtablefile = "https://github.com/nf-cmgg/test-datasets/raw/smallvariants/data/genomics/homo_sapiens/genome/hg38_chr21_22000000_23000000.strtable.zip"
ped = "https://github.com/nf-cmgg/test-datasets/raw/smallvariants/data/genomics/homo_sapiens/genome/test_dots.ped"
msi_baseline = "https://github.com/nf-cmgg/test-datasets/raw/smallvariants/data/genomics/homo_sapiens/genome/msi_subset.baseline.list"
+ somalier_sites = "https://github.com/brentp/somalier/files/3412456/sites.hg38.vcf.gz"
+ expansionhunter_catalogue = "https://github.com/nf-cmgg/test-datasets/raw/refs/heads/smallvariants/data/genomics/homo_sapiens/genome/variant_catalog.json"
// Pipeline specific parameters
filter = true
diff --git a/docs/parameters.md b/docs/parameters.md
index 538a1f73..df7cc801 100644
--- a/docs/parameters.md
+++ b/docs/parameters.md
@@ -17,60 +17,61 @@ Define where the pipeline should find input data and save output data.
Reference genome related files and options required for the workflow.
-| Parameter | Description | Type | Default | Required | Hidden |
-| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- | -------- | ------------- |
-| `genome` | Reference genome build. Used to fetch the right reference files. Help
Requires a Genome Reference Consortium reference ID (e.g. GRCh38) | `string` | GRCh38 | | |
-| `fasta` | Path to FASTA genome file. Help
This parameter is _mandatory_ if `--genome` is not specified. The path to the reference genome fasta. | `string` | | True | |
-| `fai` | Path to FASTA genome index file. | `string` | | | |
-| `dict` | Path to the sequence dictionary generated from the FASTA reference. This is only used when `haplotypecaller` is one of the specified callers. | `string` | | | |
-| `strtablefile` | Path to the STR table file generated from the FASTA reference. This is only used when `--dragstr` has been given. | `string` | | | |
-| `sdf` | Path to the SDF folder generated from the reference FASTA file. This is only required when using `--validate`. | `string` | | | |
-| `elfasta` | Path to the ELFASTA genome file. This is used when `elprep` is part of the callers and will be automatically generated when missing. | `string` | | | |
-| `elsites` | Path to the elsites file. This is used when `elprep` is part of the callers. | `string` | | | |
-| `genomes` | Object for genomes | `object` | | | True |
-| `igenomes_base` | Directory / URL base for iGenomes references. | `string` | | | `/references` |
-| `igenomes_ignore` | Do not load the iGenomes reference config. Help
Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`. | `boolean` | | | False |
-| `msi_baseline` | Path to the MSI baseline VCF file. | `string` | | | |
+| Parameter | Description | Type | Default | Required | Hidden |
+| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------- | -------- | ------ |
+| `genome` | Reference genome build. Used to fetch the right reference files. Help
Requires a Genome Reference Consortium reference ID (e.g. GRCh38) | `string` | GRCh38 | | |
+| `fasta` | Path to FASTA genome file. Help
This parameter is _mandatory_ if `--genome` is not specified. The path to the reference genome fasta. | `string` | | True | |
+| `fai` | Path to FASTA genome index file. | `string` | | | |
+| `dict` | Path to the sequence dictionary generated from the FASTA reference. This is only used when `haplotypecaller` is one of the specified callers. | `string` | | | |
+| `strtablefile` | Path to the STR table file generated from the FASTA reference. This is only used when `--dragstr` has been given. | `string` | | | |
+| `sdf` | Path to the SDF folder generated from the reference FASTA file. This is only required when using `--validate`. | `string` | | | |
+| `elfasta` | Path to the ELFASTA genome file. This is used when `elprep` is part of the callers and will be automatically generated when missing. | `string` | | | |
+| `elsites` | Path to the elsites file. This is used when `elprep` is part of the callers. | `string` | | | |
+| `expansionhunter_catalogue` | Path to the ExpansionHunter variant catalogue JSON file. This is needed when `expansionhunter` is part of the callers. | `string` | | | |
+| `genomes` | Object for genomes | `object` | | | True |
+| `igenomes_base` | Directory / URL base for iGenomes references. | `string` | | | True |
+| `igenomes_ignore` | Do not load the iGenomes reference config. Help
Do not load `igenomes.config` when running the pipeline. You may choose this option if you observe clashes between custom parameters and those supplied in `igenomes.config`. | `boolean` | | | False |
+| `msi_baseline` | Path to the MSI baseline VCF file. | `string` | | | |
## Pipeline specific parameters
Parameters that define how the pipeline works
-| Parameter | Description | Type | Default | Required | Hidden |
-| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------ | -------- | ------ |
-| `scatter_count` | The amount of scattering that should happen per sample. Help
Increase this number to increase the pipeline run speed, but at the tradeoff of using more IO and disk space. This can differ from the actual scatter count in some cases (especially with smaller files).
This has an effect on HaplotypeCaller, GenomicsDBImport and GenotypeGVCFs. | `integer` | 40 | | |
-| `merge_distance` | The merge distance for family BED files Help
Increase this parameter if GenomicsDBImport is running slow. This defines the maximum distance between intervals that should be merged. The less intervals GenomicsDBImport actually gets, the faster it will run. | `integer` | 100000 | | |
-| `dragstr` | Create DragSTR models to be used with HaplotypeCaller Help
This currently is only able to run single-core per sample. Due to this, the process is very slow with only very small improvements to the analysis. | `boolean` | | | |
-| `validate` | Validate the found variants | `boolean` | | | |
-| `filter` | Filter the found variants. | `boolean` | | | |
-| `annotate` | Annotate the found variants using Ensembl VEP. | `boolean` | | | |
-| `add_ped` | Add PED INFO header lines to the final VCFs. | `boolean` | | | |
-| `gemini` | Create a Gemini databases from the final VCFs. | `boolean` | | | |
-| `mosdepth_slow` | Don't run mosdepth in fast-mode Help
This is advised if you need exact coverage BED files as output. | `boolean` | | | |
-| `roi` | Path to the default ROI (regions of interest) BED file to be used for WES analysis. Help
This will be used for all samples that do not have a specific ROI file supplied to them through the samplesheet. Don't supply an ROI file to run the analysis as WGS. | `string` | | | |
-| `dbsnp` | Path to the dbSNP VCF file. This will be used to set the variant IDs. | `string` | | | |
-| `dbsnp_tbi` | Path to the index of the dbSNP VCF file. | `string` | | | |
-| `somalier_sites` | Path to the VCF file with sites for Somalier to use. | `string` | https://github.com/brentp/somalier/files/3412456/sites.hg38.vcf.gz | | |
-| `only_call` | Only call the variants without doing any post-processing. | `boolean` | | | |
-| `only_merge` | Only run the pipeline until the creation of the genomicsdbs and output them. | `boolean` | | | |
-| `output_genomicsdb` | Output the genomicsDB together with the joint-genotyped VCF. | `boolean` | | | |
-| `callers` | A comma delimited string of the available callers. Current options are: `haplotypecaller` and `vardict`. | `string` | haplotypecaller | | |
-| `vardict_min_af` | The minimum allele frequency for VarDict when no `vardict_min_af` is supplied in the samplesheet. | `number` | 0.1 | | |
-| `normalize` | Normalize the variant in the final VCFs. | `boolean` | | | |
-| `only_pass` | Filter out all variants that don't have the PASS filter for vardict. This only works when `--filter` is also given. | `boolean` | | | |
-| `keep_alt_contigs` | Keep all aditional contigs for calling instead of filtering them out before. | `boolean` | | | |
-| `disable_updio` | Disable UPDio analysis on the final VCFs. | `boolean` | | | |
-| `updio_common_cnvs` | A TSV file containing common CNVs to be used by UPDio. | `string` | | | |
-| `disable_automap` | Disable AutoMap analysis on the final VCFs. | `boolean` | | | |
-| `automap_repeats` | BED file with repeat regions in the genome. Help
This file will be automatically generated for hg38/GRCh38 and hg19/GRCh37 when this parameter has not been given. | `string` | | | |
-| `automap_panel` | TXT file with gene panel regions to be used by AutoMap. Help
By default the CMGG gene panel list will be used. | `string` | | | |
-| `updio_regions` | BED file with regions to be used by UPDio. | `string` | | | |
-| `automap_panel_name` | The panel name of the panel given with --automap_panel. | `string` | cmgg_bio | | |
-| `hc_phasing` | Perform phasing with HaplotypeCaller. | `boolean` | | | |
-| `min_callable_coverage` | The lowest callable coverage to determine callable regions. | `integer` | 5 | | |
-| `unique_out` | Don't change this value | `string` | | | True |
-| `disable_hc_dict_validation` | Disable the sequence dictionary validation in HaplotypeCaller | `boolean` | | | |
-| `skip_merged_cram_output` | Don't output the merged CRAM files. | `boolean` | | | |
+| Parameter | Description | Type | Default | Required | Hidden |
+| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------------- | -------- | ------ |
+| `scatter_count` | The amount of scattering that should happen per sample. Help
Increase this number to increase the pipeline run speed, but at the tradeoff of using more IO and disk space. This can differ from the actual scatter count in some cases (especially with smaller files).
This has an effect on HaplotypeCaller, GenomicsDBImport and GenotypeGVCFs. | `integer` | 40 | | |
+| `merge_distance` | The merge distance for family BED files Help
Increase this parameter if GenomicsDBImport is running slow. This defines the maximum distance between intervals that should be merged. The less intervals GenomicsDBImport actually gets, the faster it will run. | `integer` | 100000 | | |
+| `dragstr` | Create DragSTR models to be used with HaplotypeCaller Help
This currently is only able to run single-core per sample. Due to this, the process is very slow with only very small improvements to the analysis. | `boolean` | | | |
+| `validate` | Validate the found variants | `boolean` | | | |
+| `filter` | Filter the found variants. | `boolean` | | | |
+| `annotate` | Annotate the found variants using Ensembl VEP. | `boolean` | | | |
+| `add_ped` | Add PED INFO header lines to the final VCFs. | `boolean` | | | |
+| `gemini` | Create a Gemini databases from the final VCFs. | `boolean` | | | |
+| `mosdepth_slow` | Don't run mosdepth in fast-mode Help
This is advised if you need exact coverage BED files as output. | `boolean` | | | |
+| `roi` | Path to the default ROI (regions of interest) BED file to be used for WES analysis. Help
This will be used for all samples that do not have a specific ROI file supplied to them through the samplesheet. Don't supply an ROI file to run the analysis as WGS. | `string` | | | |
+| `dbsnp` | Path to the dbSNP VCF file. This will be used to set the variant IDs. | `string` | | | |
+| `dbsnp_tbi` | Path to the index of the dbSNP VCF file. | `string` | | | |
+| `somalier_sites` | Path to the VCF file with sites for Somalier to use. | `string` | | | |
+| `only_call` | Only call the variants without doing any post-processing. | `boolean` | | | |
+| `only_merge` | Only run the pipeline until the creation of the genomicsdbs and output them. | `boolean` | | | |
+| `output_genomicsdb` | Output the genomicsDB together with the joint-genotyped VCF. | `boolean` | | | |
+| `callers` | A comma delimited string of the available callers. Current options are: `haplotypecaller`, `vardict`, `elprep` and `expansionhunter`. | `string` | haplotypecaller | | |
+| `vardict_min_af` | The minimum allele frequency for VarDict when no `vardict_min_af` is supplied in the samplesheet. | `number` | 0.1 | | |
+| `normalize` | Normalize the variant in the final VCFs. | `boolean` | | | |
+| `only_pass` | Filter out all variants that don't have the PASS filter for vardict. This only works when `--filter` is also given. | `boolean` | | | |
+| `keep_alt_contigs` | Keep all aditional contigs for calling instead of filtering them out before. | `boolean` | | | |
+| `disable_updio` | Disable UPDio analysis on the final VCFs. | `boolean` | | | |
+| `updio_common_cnvs` | A TSV file containing common CNVs to be used by UPDio. | `string` | | | |
+| `disable_automap` | Disable AutoMap analysis on the final VCFs. | `boolean` | | | |
+| `automap_repeats` | BED file with repeat regions in the genome. Help
This file will be automatically generated for hg38/GRCh38 and hg19/GRCh37 when this parameter has not been given. | `string` | | | |
+| `automap_panel` | TXT file with gene panel regions to be used by AutoMap. Help
By default the CMGG gene panel list will be used. | `string` | | | |
+| `updio_regions` | BED file with regions to be used by UPDio. | `string` | | | |
+| `automap_panel_name` | The panel name of the panel given with --automap_panel. | `string` | cmgg_bio | | |
+| `hc_phasing` | Perform phasing with HaplotypeCaller. | `boolean` | | | |
+| `min_callable_coverage` | The lowest callable coverage to determine callable regions. | `integer` | 5 | | |
+| `unique_out` | Don't change this value | `string` | | | True |
+| `disable_hc_dict_validation` | Disable the sequence dictionary validation in HaplotypeCaller | `boolean` | | | |
+| `skip_merged_cram_output` | Don't output the merged CRAM files. | `boolean` | | | |
## Institutional config options
@@ -78,7 +79,7 @@ Parameters used to describe centralised config profiles. These should not be edi
| Parameter | Description | Type | Default | Required | Hidden |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------ | -------- | ------ |
-| `custom_config_version` | Git commit id for Institutional configs. | `string` | master | | True |
+| `custom_config_version` | Git commit id for Institutional configs. | `string` | main | | True |
| `custom_config_base` | Base directory for Institutional configs. Help
If you're running offline, Nextflow will not be able to fetch the institutional config files from the internet. If you don't need them, then this is not a problem. If you do need them, you should download the files from the repo and tell Nextflow where to find them with this parameter. | `string` | https://raw.githubusercontent.com/nf-cmgg/configs/main | | True |
| `config_profile_name` | Institutional config name. | `string` | | | True |
| `config_profile_description` | Institutional config description. | `string` | | | True |
diff --git a/docs/usage.md b/docs/usage.md
index e6533878..1fe90e4e 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -91,6 +91,7 @@ The samplesheet can have following columns:
| `roi` | OPTIONAL - Full path to a BED file containing the regions of interest for the current sample to call on. When this file is given, the pipeline will run this sample in WES mode. (The flag `--roi ` can also be given to run WES mode for all samples using the file specified by the flag) File has to have the extension `.bed` or `.bed.gz`. |
| `vardict_min_af` | OPTIONAL - The minimum AF value to use for the vardict variant caller (`--callers vardict`). This can be set in the samplesheet when it differs for all samples. A default can be set using the `--vardict_min_af` parameter (whichs defaults to 0.1) |
| `msi` | OPTIONAL - Set this to `true` when MSI calling should be performed on this sample. MSI calling is only done when a CRAM file is supplied and a baseline file has been provided via the `--msi_baseline` parameter. (By default this option is `false`) |
+| `sex` | OPTIONAL - The sex of the sample. This is an optional field used by expansionhunter to improve the repeat expansion calls. |
!!!note
diff --git a/main.nf b/main.nf
index 2859b24c..77ac3640 100644
--- a/main.nf
+++ b/main.nf
@@ -67,6 +67,9 @@ params {
// Path to the elsites file. This is used when `elprep` is part of the callers.
elsites: Path?
+ // Path to the ExpansionHunter variant catalogue JSON file. This is needed when `expansionhunter` is part of the callers.
+ expansionhunter_catalogue: Path? = getGenomeAttribute('expansionhunter_catalogue', params.genomes, params.genome)
+
// Object for genomes
genomes: Map = [:]
@@ -351,7 +354,7 @@ workflow {
// Check for dependencies between parameters
//
- def List available_callers = ["haplotypecaller", "vardict", "elprep"]
+ def List available_callers = ["haplotypecaller", "vardict", "elprep", "expansionhunter"]
if(params.dbsnp_tbi && !params.dbsnp){
error("Please specify the dbsnp VCF with --dbsnp VCF")
@@ -379,6 +382,10 @@ workflow {
if(!(caller in available_callers)) { error("\"${caller}\" is not a supported callers please use one or more of these instead: ${available_callers.join(', ')}") }
}
+ if (callers.contains("expansionhunter") && !params.expansionhunter_catalogue) {
+ error("Please specify the ExpansionHunter variant catalogue JSON file with --expansionhunter_catalogue")
+ }
+
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CONFIG FILES
@@ -450,6 +457,7 @@ workflow {
params.elsites,
params.msi_baseline,
params.updio_regions,
+ params.expansionhunter_catalogue,
// Boolean inputs
params.dragstr,
@@ -502,6 +510,7 @@ workflow {
gvcf_reports = SMALLVARIANTS.out.gvcf_reports
genomicsdb = SMALLVARIANTS.out.genomicsdb
vcfs = SMALLVARIANTS.out.vcfs.filter { _meta, vcf, _tbi -> vcf.startsWith(workflow.workDir) } // Filtering out input VCFs from the output publishing fixes an issue in the current implementation of the workflow output definitions: https://github.com/nextflow-io/nextflow/issues/5480
+ repeat_vcfs = SMALLVARIANTS.out.repeat_vcfs
gemini = SMALLVARIANTS.out.gemini
peds = SMALLVARIANTS.out.peds
joint_beds = SMALLVARIANTS.out.joint_beds
@@ -553,6 +562,10 @@ output {
vcf >> "${meta.family}/output_${params.unique_out}/${meta.id}.${meta.caller}.vcf.gz"
tbi >> "${meta.family}/output_${params.unique_out}/${meta.id}.${meta.caller}.vcf.gz.tbi"
} }
+ repeat_vcfs { path { meta, vcf, tbi ->
+ vcf >> "${meta.family}/output_${params.unique_out}/${meta.id}.${meta.caller}.vcf.gz"
+ tbi >> "${meta.family}/output_${params.unique_out}/${meta.id}.${meta.caller}.vcf.gz.tbi"
+ } }
gemini { path { meta, db ->
db >> "${meta.family}/output_${params.unique_out}/${meta.id}.${meta.caller}.db"
} }
diff --git a/modules.json b/modules.json
index b0708491..23f59434 100644
--- a/modules.json
+++ b/modules.json
@@ -87,6 +87,11 @@
"git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
"installed_by": ["modules"]
},
+ "expansionhunter": {
+ "branch": "master",
+ "git_sha": "0adfbfad03ff9af0d9fb437f0f2e1140e1c59316",
+ "installed_by": ["modules"]
+ },
"gatk4/calibratedragstrmodel": {
"branch": "master",
"git_sha": "6d46786420b4d7bc88eba026eb389c0c5535d120",
diff --git a/modules/nf-core/expansionhunter/environment.yml b/modules/nf-core/expansionhunter/environment.yml
new file mode 100644
index 00000000..cc175634
--- /dev/null
+++ b/modules/nf-core/expansionhunter/environment.yml
@@ -0,0 +1,9 @@
+---
+# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/environment-schema.json
+channels:
+ - conda-forge
+ - bioconda
+
+dependencies:
+ - bioconda::expansionhunter=5.0.0
+ - bioconda::htslib=1.22.1
diff --git a/modules/nf-core/expansionhunter/main.nf b/modules/nf-core/expansionhunter/main.nf
new file mode 100644
index 00000000..9c405764
--- /dev/null
+++ b/modules/nf-core/expansionhunter/main.nf
@@ -0,0 +1,53 @@
+process EXPANSIONHUNTER {
+ tag "$meta.id"
+ label 'process_low'
+
+ conda "${moduleDir}/environment.yml"
+ container "${ workflow.containerEngine in ['singularity', 'apptainer'] && !task.ext.singularity_pull_docker_container ?
+ 'https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/14/14e1d96665f934a98e569fc5a6fa237f98d3753eee2b6f60d0aea8ff9d44f406/data' :
+ 'community.wave.seqera.io/library/expansionhunter:5.0.0--389ada7e191a4fba' }"
+
+ input:
+ tuple val(meta), path(bam), path(bai)
+ tuple val(meta2), path(fasta)
+ tuple val(meta3), path(fasta_fai)
+ tuple val(meta4), path(variant_catalog)
+
+ output:
+ tuple val(meta), path("*.vcf.gz") , emit: vcf
+ tuple val(meta), path("*.json.gz") , emit: json
+ tuple val(meta), path("*_realigned.bam") , emit: bam
+ tuple val("${task.process}"), val('expansionhunter'), eval("ExpansionHunter --version | head -1 | sed -n 's/^.*ExpansionHunter v//; s/]//p'"), topic: versions, emit: versions_expansionhunter
+ tuple val("${task.process}"), val('bgzip'), eval("bgzip --version | sed '1!d;s/.* //'"), topic: versions, emit: versions_bgzip
+
+ when:
+ task.ext.when == null || task.ext.when
+
+ script:
+ def args = task.ext.args ?: ''
+ def args2 = task.ext.args2 ?: ''
+ def prefix = task.ext.prefix ?: "${meta.id}"
+
+ """
+ ExpansionHunter \\
+ ${args} \\
+ --threads ${task.cpus} \\
+ --reads ${bam} \\
+ --output-prefix ${prefix} \\
+ --reference ${fasta} \\
+ --variant-catalog ${variant_catalog}
+
+ bgzip --threads ${task.cpus} ${args2} ${prefix}.vcf
+ bgzip --threads ${task.cpus} ${args2} ${prefix}.json
+
+ """
+
+ stub:
+ def prefix = task.ext.prefix ?: "${meta.id}"
+ """
+ echo "" | gzip > ${prefix}.vcf.gz
+ echo "" | gzip > ${prefix}.json.gz
+ touch ${prefix}_realigned.bam
+
+ """
+}
diff --git a/modules/nf-core/expansionhunter/meta.yml b/modules/nf-core/expansionhunter/meta.yml
new file mode 100644
index 00000000..c6b07073
--- /dev/null
+++ b/modules/nf-core/expansionhunter/meta.yml
@@ -0,0 +1,144 @@
+name: expansionhunter
+description: Estimate repeat sizes using NGS data
+keywords:
+ - STR
+ - repeat_expansions
+ - bam
+ - cram
+ - vcf
+ - json
+tools:
+ - expansionhunter:
+ description: A tool for estimating repeat sizes
+ homepage: https://github.com/Illumina/ExpansionHunter
+ documentation: https://github.com/Illumina/ExpansionHunter/blob/master/docs/01_Introduction.md
+ doi: "10.1093/bioinformatics/btz431"
+ licence: ["Apache-2.0"]
+ identifier: biotools:ExpansionHunter
+input:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', single_end:false ]
+ - bam:
+ type: file
+ description: BAM/CRAM file
+ pattern: "*.{bam,cram}"
+ ontologies: []
+ - bai:
+ type: file
+ description: Index of BAM/CRAM file
+ pattern: "*.{bai,crai}"
+ ontologies: []
+ - - meta2:
+ type: map
+ description: |
+ Groovy Map containing reference information
+ e.g. [ id:'test' ]
+ - fasta:
+ type: file
+ description: Reference genome
+ pattern: "*.{fna,fa,fasta}"
+ ontologies: []
+ - - meta3:
+ type: map
+ description: |
+ Groovy Map containing reference information
+ e.g. [ id:'test' ]
+ - fasta_fai:
+ type: file
+ description: Reference genome index
+ pattern: "*.fai"
+ ontologies: []
+ - - meta4:
+ type: map
+ description: |
+ Groovy Map containing reference information
+ e.g. [ id:'test' ]
+ - variant_catalog:
+ type: file
+ description: JSON file with repeat expansion sites to genotype
+ pattern: "*.json"
+ ontologies:
+ - edam: http://edamontology.org/format_3464 # JSON
+output:
+ vcf:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', gender:'female' ]
+ - "*.vcf.gz":
+ type: file
+ description: VCF with repeat expansions
+ pattern: "*.vcf.gz"
+ ontologies:
+ - edam: http://edamontology.org/format_3989 # GZIP format
+ json:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', gender:'female' ]
+ - "*.json.gz":
+ type: file
+ description: JSON with repeat expansions
+ pattern: "*.json.gz"
+ ontologies:
+ - edam: http://edamontology.org/format_3989 # GZIP format
+ bam:
+ - - meta:
+ type: map
+ description: |
+ Groovy Map containing sample information
+ e.g. [ id:'test', gender:'female' ]
+ - "*_realigned.bam":
+ type: file
+ description: BAM/CRAM file
+ pattern: "*.{bam,cram}"
+ ontologies: []
+ versions_expansionhunter:
+ - - ${task.process}:
+ type: string
+ description: The process the versions were collected from
+ - expansionhunter:
+ type: string
+ description: The tool name
+ - ExpansionHunter --version | head -1 | sed -n 's/^.*ExpansionHunter v//; s/]//p':
+ type: eval
+ description: The expression to obtain the version of the tool
+ versions_bgzip:
+ - - ${task.process}:
+ type: string
+ description: The process the versions were collected from
+ - bgzip:
+ type: string
+ description: The tool name
+ - bgzip --version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+topics:
+ versions:
+ - - ${task.process}:
+ type: string
+ description: The process the versions were collected from
+ - expansionhunter:
+ type: string
+ description: The tool name
+ - ExpansionHunter --version | head -1 | sed -n 's/^.*ExpansionHunter v//; s/]//p':
+ type: eval
+ description: The expression to obtain the version of the tool
+ - - ${task.process}:
+ type: string
+ description: The process the versions were collected from
+ - bgzip:
+ type: string
+ description: The tool name
+ - bgzip --version | sed '1!d;s/.* //':
+ type: eval
+ description: The expression to obtain the version of the tool
+authors:
+ - "@jemten"
+maintainers:
+ - "@jemten"
diff --git a/modules/nf-core/expansionhunter/tests/main.nf.test b/modules/nf-core/expansionhunter/tests/main.nf.test
new file mode 100644
index 00000000..40c0f236
--- /dev/null
+++ b/modules/nf-core/expansionhunter/tests/main.nf.test
@@ -0,0 +1,62 @@
+nextflow_process {
+
+ name "Test Process EXPANSIONHUNTER"
+ script "modules/nf-core/expansionhunter/main.nf"
+ process "EXPANSIONHUNTER"
+ tag "modules"
+ tag "modules_nfcore"
+ tag "expansionhunter"
+
+ test("homo_sapiens - [bam,bai], fasta, fai, cat") {
+
+ when {
+ process {
+ """
+ input[0] = [ [ id:'test' ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true),
+ ]
+ input[1] = [[id:'fasta'],file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true)]
+ input[2] = [[id:'fasta_fai'],file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true)]
+ input[3] = [[id:'catalogue'],file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/loci/repeat_expansions.json', checkIfExists: true)]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ {assert process.success},
+ {assert snapshot(process.out).match("expansionhunter")}
+ )
+ }
+
+ }
+
+ test("homo_sapiens - [bam,bai], fasta, fai, cat - stub") {
+
+ options "-stub"
+
+ when {
+ process {
+ """
+ input[0] = [ [ id:'test' ], // meta map
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam', checkIfExists: true),
+ file(params.modules_testdata_base_path + 'genomics/homo_sapiens/illumina/bam/test.paired_end.sorted.bam.bai', checkIfExists: true),
+ ]
+ input[1] = [[id:'fasta'],file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta', checkIfExists: true)]
+ input[2] = [[id:'fasta_fai'],file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/genome.fasta.fai', checkIfExists: true)]
+ input[3] = [[id:'catalogue'],file(params.modules_testdata_base_path + 'genomics/homo_sapiens/genome/loci/repeat_expansions.json', checkIfExists: true)]
+ """
+ }
+ }
+
+ then {
+ assertAll(
+ {assert process.success},
+ {assert snapshot(process.out).match("stub")}
+ )
+ }
+
+ }
+
+}
diff --git a/modules/nf-core/expansionhunter/tests/main.nf.test.snap b/modules/nf-core/expansionhunter/tests/main.nf.test.snap
new file mode 100644
index 00000000..04b55ca1
--- /dev/null
+++ b/modules/nf-core/expansionhunter/tests/main.nf.test.snap
@@ -0,0 +1,176 @@
+{
+ "expansionhunter": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test"
+ },
+ "test.vcf.gz:md5,cfd4a1d35c0e469b99eb6aaa6d22de76"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "test"
+ },
+ "test.json.gz:md5,60d7dc4662c837bba2715d54b64a9bfe"
+ ]
+ ],
+ "2": [
+ [
+ {
+ "id": "test"
+ },
+ "test_realigned.bam:md5,3f9de11932f2548f8259c063ac37ab94"
+ ]
+ ],
+ "3": [
+ [
+ "EXPANSIONHUNTER",
+ "expansionhunter",
+ "5.0.0"
+ ]
+ ],
+ "4": [
+ [
+ "EXPANSIONHUNTER",
+ "bgzip",
+ "1.22.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test"
+ },
+ "test_realigned.bam:md5,3f9de11932f2548f8259c063ac37ab94"
+ ]
+ ],
+ "json": [
+ [
+ {
+ "id": "test"
+ },
+ "test.json.gz:md5,60d7dc4662c837bba2715d54b64a9bfe"
+ ]
+ ],
+ "vcf": [
+ [
+ {
+ "id": "test"
+ },
+ "test.vcf.gz:md5,cfd4a1d35c0e469b99eb6aaa6d22de76"
+ ]
+ ],
+ "versions_bgzip": [
+ [
+ "EXPANSIONHUNTER",
+ "bgzip",
+ "1.22.1"
+ ]
+ ],
+ "versions_expansionhunter": [
+ [
+ "EXPANSIONHUNTER",
+ "expansionhunter",
+ "5.0.0"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.3"
+ },
+ "timestamp": "2026-02-04T13:49:22.036774"
+ },
+ "stub": {
+ "content": [
+ {
+ "0": [
+ [
+ {
+ "id": "test"
+ },
+ "test.vcf.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
+ ]
+ ],
+ "1": [
+ [
+ {
+ "id": "test"
+ },
+ "test.json.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
+ ]
+ ],
+ "2": [
+ [
+ {
+ "id": "test"
+ },
+ "test_realigned.bam:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "3": [
+ [
+ "EXPANSIONHUNTER",
+ "expansionhunter",
+ "5.0.0"
+ ]
+ ],
+ "4": [
+ [
+ "EXPANSIONHUNTER",
+ "bgzip",
+ "1.22.1"
+ ]
+ ],
+ "bam": [
+ [
+ {
+ "id": "test"
+ },
+ "test_realigned.bam:md5,d41d8cd98f00b204e9800998ecf8427e"
+ ]
+ ],
+ "json": [
+ [
+ {
+ "id": "test"
+ },
+ "test.json.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
+ ]
+ ],
+ "vcf": [
+ [
+ {
+ "id": "test"
+ },
+ "test.vcf.gz:md5,68b329da9893e34099c7d8ad5cb9c940"
+ ]
+ ],
+ "versions_bgzip": [
+ [
+ "EXPANSIONHUNTER",
+ "bgzip",
+ "1.22.1"
+ ]
+ ],
+ "versions_expansionhunter": [
+ [
+ "EXPANSIONHUNTER",
+ "expansionhunter",
+ "5.0.0"
+ ]
+ ]
+ }
+ ],
+ "meta": {
+ "nf-test": "0.9.3",
+ "nextflow": "25.10.3"
+ },
+ "timestamp": "2026-02-04T13:53:07.012233"
+ }
+}
\ No newline at end of file
diff --git a/nextflow.config b/nextflow.config
index 72fcd50f..6881bea4 100644
--- a/nextflow.config
+++ b/nextflow.config
@@ -234,7 +234,7 @@ manifest {
plugins {
id 'nf-schema@2.7.2' // Validation of pipeline parameters and creation of an input channel from a sample sheet
id 'nf-ped@0.4.0' // Handling of PED files
- id 'nf-teams@0.1.1' // Sending messages to Microsoft Teams channels, configuration should still be done by the user
+ id 'nf-teams@0.2.0' // Sending messages to Microsoft Teams channels, configuration should still be done by the user
}
validation {
diff --git a/nextflow_schema.json b/nextflow_schema.json
index 4190f167..50d5e063 100644
--- a/nextflow_schema.json
+++ b/nextflow_schema.json
@@ -116,6 +116,15 @@
"description": "Path to the elsites file. This is used when `elprep` is part of the callers.",
"fa_icon": "far fa-file-code"
},
+ "expansionhunter_catalogue": {
+ "type": "string",
+ "format": "file-path",
+ "exists": true,
+ "mimetype": "application/json",
+ "pattern": "^\\S+\\.json$",
+ "description": "Path to the ExpansionHunter variant catalogue JSON file. This is needed when `expansionhunter` is part of the callers.",
+ "fa_icon": "far fa-file-code"
+ },
"genomes": {
"type": "object",
"hidden": true,
@@ -241,7 +250,7 @@
},
"callers": {
"type": "string",
- "description": "A comma delimited string of the available callers. Current options are: `haplotypecaller` and `vardict`.",
+ "description": "A comma delimited string of the available callers. Current options are: `haplotypecaller`, `vardict`, `elprep` and `expansionhunter`.",
"default": "haplotypecaller"
},
"vardict_min_af": {
diff --git a/subworkflows/local/cram_repeat_expansionhunter/main.nf b/subworkflows/local/cram_repeat_expansionhunter/main.nf
new file mode 100644
index 00000000..fd5caf28
--- /dev/null
+++ b/subworkflows/local/cram_repeat_expansionhunter/main.nf
@@ -0,0 +1,57 @@
+//
+// Estimate repeat size with Expanionhunter
+//
+
+include { EXPANSIONHUNTER } from '../../../modules/nf-core/expansionhunter/main'
+include { BCFTOOLS_ANNOTATE } from '../../../modules/nf-core/bcftools/annotate/main'
+include { TABIX_TABIX } from '../../../modules/nf-core/tabix/tabix/main'
+
+workflow CRAM_REPEAT_EXPANSIONHUNTER {
+ take:
+ ch_crams // channel: [mandatory] [ meta, cram, crai ] => The aligned CRAMs per sample with the regions they should be called on
+ ch_fasta // channel: [mandatory] [ meta, fasta ] => The fasta reference file
+ ch_fai // channel: [mandatory] [ meta, fai ] => The index of the fasta reference file
+ ch_catalogue // channel: [mandatory] [ meta, catalogue ] => The expansionhunter catalogue
+
+ main:
+
+ EXPANSIONHUNTER(
+ ch_crams,
+ ch_fasta,
+ ch_fai,
+ ch_catalogue
+ )
+
+ def ch_ref_header = channel.of(
+ '##INFO=',
+ '##INFO=',
+ '##INFO=',
+ '##INFO=',
+ '##INFO=',
+ '##INFO=',
+ '##INFO=',
+ '##FORMAT=',
+ '##FORMAT=',
+ '##FORMAT=',
+ '##FORMAT=',
+ '##FORMAT=',
+ '##FORMAT=',
+ '##FORMAT='
+ )
+ .collectFile(name:'header.txt', newLine:true)
+ .collect()
+
+ def ch_annotate_input = EXPANSIONHUNTER.out.vcf
+ .combine(ch_ref_header)
+ .map { meta, vcf, header ->
+ def new_meta = meta + [caller: 'expansionhunter']
+ [ new_meta, vcf, [], [], [], [], header, [] ]
+ }
+
+ BCFTOOLS_ANNOTATE(
+ ch_annotate_input
+ )
+
+ emit:
+ BCFTOOLS_ANNOTATE.out.vcf.join(BCFTOOLS_ANNOTATE.out.index, failOnDuplicate:true, failOnMismatch:true) // channel: [ val(meta), path(vcf), path(tbi) ]
+}
diff --git a/subworkflows/local/cram_repeat_expansionhunter/tests/main.nf.test b/subworkflows/local/cram_repeat_expansionhunter/tests/main.nf.test
new file mode 100644
index 00000000..31e7da63
--- /dev/null
+++ b/subworkflows/local/cram_repeat_expansionhunter/tests/main.nf.test
@@ -0,0 +1,50 @@
+nextflow_workflow {
+
+ name "Test Workflow CRAM_REPEAT_EXPANSIONHUNTER"
+ script "../main.nf"
+ workflow "CRAM_REPEAT_EXPANSIONHUNTER"
+
+ tag "subworkflows"
+ tag "subworkflows_local"
+ tag "cram_repeat_expansionhunter"
+
+ test("cram_repeat_expansionhunter - default") {
+
+ when {
+ workflow {
+ """
+ input[0] = channel.of([
+ [id:"NA24143", sample:"NA24143", family:"Ashkenazim", family_samples:"NA24143", sex: 'male'],
+ file(params.cram1, checkIfExists:true),
+ file(params.crai1, checkIfExists:true)
+ ],[
+ [id:"NA24149", sample:"NA24149", family:"Ashkenazim", family_samples:"NA24149", sex: null],
+ file(params.cram2, checkIfExists:true),
+ file(params.crai2, checkIfExists:true)
+ ])
+ input[1] = channel.value([
+ [id:"reference"],
+ file(params.fasta, checkIfExists:true)
+ ])
+ input[2] = channel.value([
+ [id:"reference"],
+ file(params.fai, checkIfExists:true)
+ ])
+ input[3] = channel.value([
+ [id:"reference"],
+ file(params.expansionhunter_catalogue, checkIfExists:true)
+ ])
+ """
+ }
+ }
+
+ then {
+ assert workflow.success
+ assert snapshot(
+ workflow.out.collect { num, vals -> [num:vals.collect { meta, vcf, tbi -> [meta, path(vcf).vcf.variantsMD5, file(tbi).name]}]}
+ ).match()
+ }
+
+ }
+
+}
diff --git a/subworkflows/local/cram_repeat_expansionhunter/tests/main.nf.test.snap b/subworkflows/local/cram_repeat_expansionhunter/tests/main.nf.test.snap
new file mode 100644
index 00000000..633b9016
--- /dev/null
+++ b/subworkflows/local/cram_repeat_expansionhunter/tests/main.nf.test.snap
@@ -0,0 +1,41 @@
+{
+ "cram_repeat_expansionhunter - default": {
+ "content": [
+ [
+ {
+ "num": [
+ [
+ {
+ "id": "NA24143",
+ "sample": "NA24143",
+ "family": "Ashkenazim",
+ "family_samples": "NA24143",
+ "sex": "male",
+ "caller": "expansionhunter"
+ },
+ "fa0162b0019fc333183e9d220bd996cd",
+ "NA24143.expansionhunter.vcf.gz.tbi"
+ ],
+ [
+ {
+ "id": "NA24149",
+ "sample": "NA24149",
+ "family": "Ashkenazim",
+ "family_samples": "NA24149",
+ "sex": null,
+ "caller": "expansionhunter"
+ },
+ "a1e23813bb591761b1817521c138019e",
+ "NA24149.expansionhunter.vcf.gz.tbi"
+ ]
+ ]
+ }
+ ]
+ ],
+ "timestamp": "2026-07-10T15:57:22.887444663",
+ "meta": {
+ "nf-test": "0.9.5",
+ "nextflow": "26.04.3"
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/nextflow.config b/tests/nextflow.config
index 7fd076d7..c51c36e4 100644
--- a/tests/nextflow.config
+++ b/tests/nextflow.config
@@ -19,6 +19,7 @@ params {
somalier_sites = "https://github.com/nf-cmgg/test-datasets/raw/smallvariants/data/genomics/homo_sapiens/illumina/regions/sites.hg38.vcf.gz"
vep_cache = null
msi_baseline = "https://github.com/nf-cmgg/test-datasets/raw/smallvariants/data/genomics/homo_sapiens/genome/msi_subset.baseline.list"
+ expansionhunter_catalogue = "https://github.com/nf-cmgg/test-datasets/raw/refs/heads/smallvariants/data/genomics/homo_sapiens/genome/variant_catalog.json"
vcfanno_config = "${projectDir}/assets/vcfanno.toml"
vcfanno_resources = "https://github.com/brentp/vcfanno/raw/master/example/exac.vcf.gz;https://github.com/brentp/vcfanno/raw/master/example/exac.vcf.gz.tbi"
diff --git a/tests/pipeline/callers/main.nf.test b/tests/pipeline/callers/main.nf.test
index de3ac974..6c794d40 100644
--- a/tests/pipeline/callers/main.nf.test
+++ b/tests/pipeline/callers/main.nf.test
@@ -95,4 +95,62 @@ nextflow_pipeline {
}
+ test("pipeline_callers - expansionhunter") {
+
+ when {
+ params {
+ outdir = "${outputDir}"
+ callers = "expansionhunter"
+ }
+ }
+
+ then {
+ assertAll(
+ { assert workflow.success },
+ { assert snapshot(
+ path("${outputDir}")
+ .list()
+ .collect { Utils.getRecursiveFileNames(it, "${outputDir}") }
+ .flatten()
+ .findAll {
+ !(it.contains("/execution_") || it.contains("/params_") || it.contains("/pipeline_") || it.contains("DONE"))
+ }
+ .collect {
+ it.replace(Utils.getDynamicOutputName(), "_")
+ }
+ ).match() }
+ )
+ }
+
+ }
+
+ test("pipeline_callers - expansionhunter + haplotypecaller") {
+
+ when {
+ params {
+ outdir = "${outputDir}"
+ callers = "expansionhunter,haplotypecaller"
+ }
+ }
+
+ then {
+ assertAll(
+ { assert workflow.success },
+ { assert snapshot(
+ path("${outputDir}")
+ .list()
+ .collect { Utils.getRecursiveFileNames(it, "${outputDir}") }
+ .flatten()
+ .findAll {
+ !(it.contains("/execution_") || it.contains("/params_") || it.contains("/pipeline_") || it.contains("DONE"))
+ }
+ .collect {
+ it.replace(Utils.getDynamicOutputName(), "_")
+ }
+ ).match() }
+ )
+ }
+
+ }
+
}
diff --git a/tests/pipeline/callers/main.nf.test.snap b/tests/pipeline/callers/main.nf.test.snap
index afd4979c..372810be 100644
--- a/tests/pipeline/callers/main.nf.test.snap
+++ b/tests/pipeline/callers/main.nf.test.snap
@@ -67,6 +67,127 @@
"nextflow": "25.10.4"
}
},
+ "pipeline_callers - expansionhunter": {
+ "content": [
+ [
+ "Ashkenazim/NA24143__/NA24143.bed",
+ "Ashkenazim/NA24143__/NA24143.per-base.bed.gz",
+ "Ashkenazim/NA24143__/NA24143.per-base.bed.gz.csi",
+ "Ashkenazim/NA24143__/mosdepth/NA24143.global.dist.txt",
+ "Ashkenazim/NA24143__/mosdepth/NA24143.region.dist.txt",
+ "Ashkenazim/NA24143__/mosdepth/NA24143.summary.txt",
+ "Ashkenazim/NA24143__/msi/NA24143_all_msi",
+ "Ashkenazim/NA24143__/msi/NA24143_dis_msi",
+ "Ashkenazim/NA24143__/msi/NA24143_summary_msi",
+ "Ashkenazim/NA24143__/msi/NA24143_unstable_msi",
+ "Ashkenazim/NA24149__/NA24149.bed",
+ "Ashkenazim/NA24149__/NA24149.per-base.bed.gz",
+ "Ashkenazim/NA24149__/NA24149.per-base.bed.gz.csi",
+ "Ashkenazim/NA24149__/mosdepth/NA24149.global.dist.txt",
+ "Ashkenazim/NA24149__/mosdepth/NA24149.region.dist.txt",
+ "Ashkenazim/NA24149__/mosdepth/NA24149.summary.txt",
+ "Ashkenazim/NA24149__/msi/NA24149_all_msi",
+ "Ashkenazim/NA24149__/msi/NA24149_dis_msi",
+ "Ashkenazim/NA24149__/msi/NA24149_summary_msi",
+ "Ashkenazim/NA24149__/msi/NA24149_unstable_msi",
+ "Ashkenazim/NA24385__/NA24385.bed",
+ "Ashkenazim/NA24385__/NA24385.per-base.bed.gz",
+ "Ashkenazim/NA24385__/NA24385.per-base.bed.gz.csi",
+ "Ashkenazim/NA24385__/mosdepth/NA24385.global.dist.txt",
+ "Ashkenazim/NA24385__/mosdepth/NA24385.region.dist.txt",
+ "Ashkenazim/NA24385__/mosdepth/NA24385.summary.txt",
+ "Ashkenazim/output__/NA24143.expansionhunter.vcf.gz",
+ "Ashkenazim/output__/NA24143.expansionhunter.vcf.gz.tbi",
+ "Ashkenazim/output__/NA24149.expansionhunter.vcf.gz",
+ "Ashkenazim/output__/NA24149.expansionhunter.vcf.gz.tbi",
+ "Ashkenazim/output__/NA24385.expansionhunter.vcf.gz",
+ "Ashkenazim/output__/NA24385.expansionhunter.vcf.gz.tbi",
+ "pipeline_info/nf_cmgg_smallvariants_software_mqc_versions.yml",
+ "_/multiqc_data/.stub",
+ "_/multiqc_report.html",
+ "_/samplesheet.csv"
+ ]
+ ],
+ "timestamp": "2026-07-10T15:55:45.020268258",
+ "meta": {
+ "nf-test": "0.9.5",
+ "nextflow": "26.04.3"
+ }
+ },
+ "pipeline_callers - expansionhunter + haplotypecaller": {
+ "content": [
+ [
+ "Ashkenazim/NA24143__/NA24143.bed",
+ "Ashkenazim/NA24143__/NA24143.haplotypecaller.bcftools_stats.txt",
+ "Ashkenazim/NA24143__/NA24143.haplotypecaller.g.vcf.gz",
+ "Ashkenazim/NA24143__/NA24143.haplotypecaller.g.vcf.gz.tbi",
+ "Ashkenazim/NA24143__/NA24143.per-base.bed.gz",
+ "Ashkenazim/NA24143__/NA24143.per-base.bed.gz.csi",
+ "Ashkenazim/NA24143__/mosdepth/NA24143.global.dist.txt",
+ "Ashkenazim/NA24143__/mosdepth/NA24143.region.dist.txt",
+ "Ashkenazim/NA24143__/mosdepth/NA24143.summary.txt",
+ "Ashkenazim/NA24143__/msi/NA24143_all_msi",
+ "Ashkenazim/NA24143__/msi/NA24143_dis_msi",
+ "Ashkenazim/NA24143__/msi/NA24143_summary_msi",
+ "Ashkenazim/NA24143__/msi/NA24143_unstable_msi",
+ "Ashkenazim/NA24149__/NA24149.bed",
+ "Ashkenazim/NA24149__/NA24149.haplotypecaller.bcftools_stats.txt",
+ "Ashkenazim/NA24149__/NA24149.haplotypecaller.g.vcf.gz",
+ "Ashkenazim/NA24149__/NA24149.haplotypecaller.g.vcf.gz.tbi",
+ "Ashkenazim/NA24149__/NA24149.per-base.bed.gz",
+ "Ashkenazim/NA24149__/NA24149.per-base.bed.gz.csi",
+ "Ashkenazim/NA24149__/mosdepth/NA24149.global.dist.txt",
+ "Ashkenazim/NA24149__/mosdepth/NA24149.region.dist.txt",
+ "Ashkenazim/NA24149__/mosdepth/NA24149.summary.txt",
+ "Ashkenazim/NA24149__/msi/NA24149_all_msi",
+ "Ashkenazim/NA24149__/msi/NA24149_dis_msi",
+ "Ashkenazim/NA24149__/msi/NA24149_summary_msi",
+ "Ashkenazim/NA24149__/msi/NA24149_unstable_msi",
+ "Ashkenazim/NA24385__/NA24385.bed",
+ "Ashkenazim/NA24385__/NA24385.haplotypecaller.bcftools_stats.txt",
+ "Ashkenazim/NA24385__/NA24385.haplotypecaller.g.vcf.gz",
+ "Ashkenazim/NA24385__/NA24385.haplotypecaller.g.vcf.gz.tbi",
+ "Ashkenazim/NA24385__/NA24385.per-base.bed.gz",
+ "Ashkenazim/NA24385__/NA24385.per-base.bed.gz.csi",
+ "Ashkenazim/NA24385__/mosdepth/NA24385.global.dist.txt",
+ "Ashkenazim/NA24385__/mosdepth/NA24385.region.dist.txt",
+ "Ashkenazim/NA24385__/mosdepth/NA24385.summary.txt",
+ "Ashkenazim/output__/Ashkenazim.haplotypecaller.bed",
+ "Ashkenazim/output__/Ashkenazim.haplotypecaller.ped",
+ "Ashkenazim/output__/Ashkenazim.haplotypecaller.vcf.gz",
+ "Ashkenazim/output__/Ashkenazim.haplotypecaller.vcf.gz.tbi",
+ "Ashkenazim/output__/NA24143.expansionhunter.vcf.gz",
+ "Ashkenazim/output__/NA24143.expansionhunter.vcf.gz.tbi",
+ "Ashkenazim/output__/NA24149.expansionhunter.vcf.gz",
+ "Ashkenazim/output__/NA24149.expansionhunter.vcf.gz.tbi",
+ "Ashkenazim/output__/NA24385.expansionhunter.vcf.gz",
+ "Ashkenazim/output__/NA24385.expansionhunter.vcf.gz.tbi",
+ "Ashkenazim/output__/automap/haplotypecaller/sample1.HomRegions.cmgg_bio.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample1.HomRegions.pdf",
+ "Ashkenazim/output__/automap/haplotypecaller/sample1.HomRegions.strict.cmgg_bio.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample1.HomRegions.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample2.HomRegions.cmgg_bio.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample2.HomRegions.pdf",
+ "Ashkenazim/output__/automap/haplotypecaller/sample2.HomRegions.strict.cmgg_bio.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample2.HomRegions.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample3.HomRegions.cmgg_bio.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample3.HomRegions.pdf",
+ "Ashkenazim/output__/automap/haplotypecaller/sample3.HomRegions.strict.cmgg_bio.tsv",
+ "Ashkenazim/output__/automap/haplotypecaller/sample3.HomRegions.tsv",
+ "Ashkenazim/qc__/Ashkenazim.haplotypecaller.bcftools_stats.txt",
+ "Ashkenazim/qc__/Ashkenazim.haplotypecaller.html",
+ "pipeline_info/nf_cmgg_smallvariants_software_mqc_versions.yml",
+ "_/multiqc_data/.stub",
+ "_/multiqc_report.html",
+ "_/samplesheet.csv"
+ ]
+ ],
+ "timestamp": "2026-07-10T15:56:58.538828587",
+ "meta": {
+ "nf-test": "0.9.5",
+ "nextflow": "26.04.3"
+ }
+ },
"pipeline_callers - vardict + haplotypecaller": {
"content": [
[
diff --git a/workflows/smallvariants.nf b/workflows/smallvariants.nf
index e4c00aba..4edd7d8a 100644
--- a/workflows/smallvariants.nf
+++ b/workflows/smallvariants.nf
@@ -21,6 +21,7 @@ include { CRAM_CALL_GATK4 } from '../subworkflows/local/cram_c
include { GVCF_JOINT_GENOTYPE_GATK4 } from '../subworkflows/local/gvcf_joint_genotype_gatk4/main'
include { BAM_CALL_ELPREP } from '../subworkflows/local/bam_call_elprep/main'
include { BAM_CALL_VARDICTJAVA } from '../subworkflows/local/bam_call_vardictjava/main'
+include { CRAM_REPEAT_EXPANSIONHUNTER } from '../subworkflows/local/cram_repeat_expansionhunter/main'
include { VCF_EXTRACT_RELATE_SOMALIER } from '../subworkflows/local/vcf_extract_relate_somalier/main'
include { VCF_PED_RTGTOOLS } from '../subworkflows/local/vcf_ped_rtgtools/main'
include { VCF_ANNOTATION } from '../subworkflows/local/vcf_annotation/main'
@@ -106,6 +107,7 @@ workflow SMALLVARIANTS {
elsites // path: path to the elsites file for elprep
msi_baseline // path: path to the msi_baseline file
updio_regions // path: path to the BED file with regions to be used by UPDio
+ expansionhunter_catalogue // path: path to the ExpansionHunter variant catalog
// Boolean inputs
dragstr // boolean: create a dragstr model and use it for haplotypecaller
@@ -142,6 +144,7 @@ workflow SMALLVARIANTS {
def List gvcf_callers = ["haplotypecaller", "elprep"]
def List bam_callers = ["elprep", "vardict"]
+ def List snv_callers = ["haplotypecaller", "vardict", "elprep"]
//
// Importing and convert the input files passed through the parameters to channels
@@ -178,6 +181,8 @@ workflow SMALLVARIANTS {
def ch_updio_regions = updio_regions ? channel.value(updio_regions) : []
+ def ch_expansionhunter_catalogue = expansionhunter_catalogue ? channel.value([[id:"expansionhunter_catalogue"], expansionhunter_catalogue]) : channel.empty()
+
//
// Check for the presence of EnsemblVEP plugins that use extra files
//
@@ -474,6 +479,21 @@ workflow SMALLVARIANTS {
def ch_merged_crams = CRAM_PREPARE_SAMTOOLS_BEDTOOLS.out.merged_crams
def ch_mosdepth_reports = CRAM_PREPARE_SAMTOOLS_BEDTOOLS.out.mosdepth_reports
+ //
+ // Call repeat expansions
+ //
+
+ def ch_expansionhunter_vcfs = channel.empty()
+ if ("expansionhunter" in callers) {
+ CRAM_REPEAT_EXPANSIONHUNTER(
+ CRAM_PREPARE_SAMTOOLS_BEDTOOLS.out.ready_crams,
+ ch_fasta_ready,
+ ch_fai_ready,
+ ch_expansionhunter_catalogue
+ )
+ ch_expansionhunter_vcfs = CRAM_REPEAT_EXPANSIONHUNTER.out
+ }
+
//
// Split the BED files
//
@@ -727,7 +747,8 @@ workflow SMALLVARIANTS {
// Validate the found variants
//
- if (validate){
+ if (validate && callers.intersect(snv_callers)){
+ def callers_to_validate = callers.intersect(snv_callers)
def ch_truths_input = ch_input.truth_variants
.map { meta, vcf, tbi, bed ->
def new_meta = meta - meta.subMap("duplicate_count")
@@ -761,7 +782,7 @@ workflow SMALLVARIANTS {
}
.mix(ch_truths_input.tbi)
.mix(ch_truths_input.no_vcf)
- .combine(callers)
+ .combine(callers_to_validate)
.map { meta, vcf, tbi, bed, caller ->
def new_meta = meta + [caller: caller]
[ new_meta, vcf, tbi, bed ]
@@ -794,7 +815,7 @@ workflow SMALLVARIANTS {
}
ch_single_beds
- .combine(callers)
+ .combine(callers_to_validate)
.map { meta, bed, caller ->
def new_meta = [
id:meta.id,
@@ -949,6 +970,7 @@ workflow SMALLVARIANTS {
msi = ch_msisensor_output // channel: [ val(meta), path(file) ]
genomicsdb = ch_final_genomicsdb // channel: [ val(meta), path(genomicsdb) ]
vcfs = ch_final_vcfs // channel: [ val(meta), path(vcf), path(tbi) ]
+ repeat_vcfs = ch_expansionhunter_vcfs // channel: [ val(meta), path(vcf), path(tbi) ]
gemini = ch_final_dbs // channel: [ val(meta), path(db) ]
peds = ch_final_peds // channel: [ val(meta), path(ped) ]
single_beds = ch_single_beds // channel: [ val(meta), path(bed) ]