From fd54207e5197e9ee253383925aabf7dc7cb71010 Mon Sep 17 00:00:00 2001 From: AlexVCaron Date: Thu, 17 Jul 2025 17:51:12 +0000 Subject: [PATCH 01/37] fixes to registration modules, renaming to unify nomenclature --- .../nf-neuro/registration/anattodwi/main.nf | 38 ++++++++++--------- modules/nf-neuro/registration/ants/main.nf | 37 +++++++++--------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index 5c8521e3..3417ec58 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -5,22 +5,22 @@ process REGISTRATION_ANATTODWI { container "scilus/scilus:2.2.0" input: - tuple val(meta), path(t1), path(b0), path(metric) + tuple val(meta), path(t1), path(b0), path(metric) output: - tuple val(meta), path("*0GenericAffine.mat") , emit: affine - tuple val(meta), path("*1Warp.nii.gz") , emit: warp - tuple val(meta), path("*1InverseWarp.nii.gz") , emit: inverse_warp - tuple val(meta), path("*t1_warped.nii.gz") , emit: t1_warped - tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*__output0ForwardAffine.mat") , emit: affine + tuple val(meta), path("*__output1ForwardWarp.nii.gz") , emit: warp + tuple val(meta), path("*__output0BackwardWarp.nii.gz") , emit: inverse_warp + tuple val(meta), path("*__output1BackwardAffine.nii.gz") , emit: inverse_affine + tuple val(meta), path("*t1_warped.nii.gz") , emit: t1_warped + tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true + path "versions.yml" , emit: versions when: - task.ext.when == null || task.ext.when + task.ext.when == null || task.ext.when script: def prefix = task.ext.prefix ?: "${meta.id}" - def run_qc = task.ext.run_qc ? task.ext.run_qc : false """ @@ -49,9 +49,12 @@ process REGISTRATION_ANATTODWI { --smoothing-sigmas 3x2x1 mv outputWarped.nii.gz ${prefix}__t1_warped.nii.gz - mv output0GenericAffine.mat ${prefix}__output0GenericAffine.mat - mv output1InverseWarp.nii.gz ${prefix}__output1InverseWarp.nii.gz - mv output1Warp.nii.gz ${prefix}__output1Warp.nii.gz + mv output0GenericAffine.mat ${prefix}__output0ForwardAffine.mat + mv output1InverseWarp.nii.gz ${prefix}__output0BackwardWarp.nii.gz + mv output1Warp.nii.gz ${prefix}__output1ForwardWarp.nii.gz + + antsApplyTransforms -d 3 -i $b0 -r $t1 -o Linear[${prefix}__output1BackwardAffine.mat] \ + -t [${prefix}__output0ForwardAffine.mat,1] ### ** QC ** ### if $run_qc; @@ -109,7 +112,7 @@ process REGISTRATION_ANATTODWI { scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') - imagemagick: \$(convert -version | sed -n 's/.*ImageMagick \\([0-9]\\{1,\\}\\.[0-9]\\{1,\\}\\.[0-9]\\{1,\\}\\).*/\\1/p') + imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') END_VERSIONS """ @@ -130,9 +133,10 @@ process REGISTRATION_ANATTODWI { convert -h touch ${prefix}__t1_warped.nii.gz - touch ${prefix}__output0GenericAffine.mat - touch ${prefix}__output1InverseWarp.nii.gz - touch ${prefix}__output1Warp.nii.gz + touch ${prefix}__output0ForwardAffine.mat + touch ${prefix}__output1ForwardWarp.nii.gz + touch ${prefix}__output0BackwardWarp.nii.gz + touch ${prefix}__output1BackwardAffine.mat touch ${prefix}__registration_anattodwi_mqc.gif cat <<-END_VERSIONS > versions.yml @@ -140,7 +144,7 @@ process REGISTRATION_ANATTODWI { scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') - imagemagick: \$(convert -version | sed -n 's/.*ImageMagick \\([0-9]\\{1,\\}\\.[0-9]\\{1,\\}\\.[0-9]\\{1,\\}\\).*/\\1/p') + imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') END_VERSIONS """ } diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index 633f1937..7e600517 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -6,19 +6,19 @@ process REGISTRATION_ANTS { container "scilus/scilus:2.2.0" input: - tuple val(meta), path(fixedimage), path(movingimage), path(mask) /* optional, input = [] */ + tuple val(meta), path(fixedimage), path(movingimage), path(mask) //** optional, input = [] **// output: - tuple val(meta), path("*_warped.nii.gz") , emit: image - tuple val(meta), path("*__output0GenericAffine.mat") , emit: affine - tuple val(meta), path("*__output1InverseAffine.mat") , emit: inverse_affine - tuple val(meta), path("*__output1Warp.nii.gz") , emit: warp, optional:true - tuple val(meta), path("*__output0InverseWarp.nii.gz") , emit: inverse_warp, optional: true - tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*_warped.nii.gz") , emit: image + tuple val(meta), path("*__output0ForwardAffine.mat") , emit: affine + tuple val(meta), path("*__output1ForwardWarp.nii.gz") , emit: warp, optional:true + tuple val(meta), path("*__output1InverseWarp.nii.gz") , emit: inverse_warp, optional: true + tuple val(meta), path("*__output0InverseAffine.mat") , emit: inverse_affine + tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true + path "versions.yml" , emit: versions when: - task.ext.when == null || task.ext.when + task.ext.when == null || task.ext.when script: def args = task.ext.args ?: '' @@ -49,17 +49,17 @@ process REGISTRATION_ANTS { $ants $dimension -f $fixedimage -m $movingimage -o output -t $transform $args $seed mv outputWarped.nii.gz ${prefix}__warped.nii.gz - mv output0GenericAffine.mat ${prefix}__output0GenericAffine.mat + mv output0GenericAffine.mat ${prefix}__output0ForwardAffine.mat if [ $transform != "t" ] && [ $transform != "r" ] && [ $transform != "a" ]; then - mv output1InverseWarp.nii.gz ${prefix}__output0InverseWarp.nii.gz - mv output1Warp.nii.gz ${prefix}__output1Warp.nii.gz + mv output1InverseWarp.nii.gz ${prefix}__output0BackwardWarp.nii.gz + mv output1Warp.nii.gz ${prefix}__output1ForwardWarp.nii.gz fi antsApplyTransforms -d 3 -i $fixedimage -r $movingimage \ - -o Linear[${prefix}__output1InverseAffine.mat] \ - -t [${prefix}__output0GenericAffine.mat,1] + -o Linear[${prefix}__output0BackwardAffine.mat]\ + -t [${prefix}__output1ForwardAffine.mat,1] ### ** QC ** ### if $run_qc; @@ -116,7 +116,6 @@ process REGISTRATION_ANTS { """ stub: - def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" """ @@ -134,10 +133,10 @@ process REGISTRATION_ANTS { scil_viz_volume_screenshot -h touch ${prefix}__t1_warped.nii.gz - touch ${prefix}__output0GenericAffine.mat - touch ${prefix}__output1InverseAffine.mat - touch ${prefix}__output0InverseWarp.nii.gz - touch ${prefix}__output1Warp.nii.gz + touch ${prefix}__output0ForwardAffine.mat + touch ${prefix}__output1ForwardWarp.nii.gz + touch ${prefix}__output0BackwardWarp.nii.gz + touch ${prefix}__output1BackwardAffine.mat cat <<-END_VERSIONS > versions.yml "${task.process}": From 98ebf2859f55f020eb458e7965e82a3267862bcd Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 17 Jul 2025 18:59:12 +0000 Subject: [PATCH 02/37] ants works --- modules/nf-neuro/registration/anattodwi/main.nf | 3 ++- modules/nf-neuro/registration/ants/main.nf | 8 ++++---- .../nf-neuro/registration/ants/tests/main.nf.test.snap | 6 ++++++ modules/nf-neuro/registration/ants/tests/nextflow.config | 1 + 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index 3417ec58..cac9b896 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -53,7 +53,8 @@ process REGISTRATION_ANATTODWI { mv output1InverseWarp.nii.gz ${prefix}__output0BackwardWarp.nii.gz mv output1Warp.nii.gz ${prefix}__output1ForwardWarp.nii.gz - antsApplyTransforms -d 3 -i $b0 -r $t1 -o Linear[${prefix}__output1BackwardAffine.mat] \ + antsApplyTransforms -d 3 -i $b0 -r $t1 \ + -o Linear[${prefix}__output1BackwardAffine.mat] \ -t [${prefix}__output0ForwardAffine.mat,1] ### ** QC ** ### diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index 7e600517..5f9d7b44 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -12,8 +12,8 @@ process REGISTRATION_ANTS { tuple val(meta), path("*_warped.nii.gz") , emit: image tuple val(meta), path("*__output0ForwardAffine.mat") , emit: affine tuple val(meta), path("*__output1ForwardWarp.nii.gz") , emit: warp, optional:true - tuple val(meta), path("*__output1InverseWarp.nii.gz") , emit: inverse_warp, optional: true - tuple val(meta), path("*__output0InverseAffine.mat") , emit: inverse_affine + tuple val(meta), path("*__output0BackwardWarp.nii.gz") , emit: inverse_warp, optional: true + tuple val(meta), path("*__output1BackwardAffine.mat") , emit: inverse_affine tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions @@ -58,8 +58,8 @@ process REGISTRATION_ANTS { fi antsApplyTransforms -d 3 -i $fixedimage -r $movingimage \ - -o Linear[${prefix}__output0BackwardAffine.mat]\ - -t [${prefix}__output1ForwardAffine.mat,1] + -o Linear[${prefix}__output1BackwardAffine.mat] \ + -t [${prefix}__output0ForwardAffine.mat,1] ### ** QC ** ### if $run_qc; diff --git a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap index 88a1961d..05335044 100644 --- a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap @@ -235,6 +235,12 @@ ] ], "2": [ + + ], + "3": [ + + ], + "4": [ [ { "id": "test" diff --git a/modules/nf-neuro/registration/ants/tests/nextflow.config b/modules/nf-neuro/registration/ants/tests/nextflow.config index 3750dac9..675ffab6 100644 --- a/modules/nf-neuro/registration/ants/tests/nextflow.config +++ b/modules/nf-neuro/registration/ants/tests/nextflow.config @@ -2,5 +2,6 @@ process { withName: "REGISTRATION_ANTS" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.repro_mode = 1 + ext.initial_transform = { "[$fixedimage,$movingimage,1]" } } } From af85c5a05765dd510fd6c89de0cfb8b0c99c4f7b Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Fri, 18 Jul 2025 19:27:15 +0000 Subject: [PATCH 03/37] MODULES : align naming conventions, order of inputs, output both single and combined transforms, update meta, containers and versioning, fix typos, syntax and indentation --- .../nf-neuro/registration/anattodwi/main.nf | 88 +++++--- .../nf-neuro/registration/anattodwi/meta.yml | 162 +++++++++---- .../registration/anattodwi/tests/main.nf.test | 8 +- .../anattodwi/tests/main.nf.test.snap | 5 +- modules/nf-neuro/registration/ants/main.nf | 79 ++++--- modules/nf-neuro/registration/ants/meta.yml | 213 +++++++++++++++--- .../registration/ants/tests/main.nf.test | 88 +++++--- .../registration/ants/tests/nextflow.config | 2 +- ...options.config => nextflow_no_warp.config} | 3 - .../ants/tests/nextflow_quick.config | 3 +- .../registration/antsapplytransforms/main.nf | 102 ++++++--- .../registration/antsapplytransforms/meta.yml | 2 +- .../antsapplytransforms/tests/main.nf.test | 70 +++++- .../tests/main.nf.test.snap | 4 +- .../antsapplytransforms/tests/nextflow.config | 2 +- .../nf-neuro/registration/tractogram/main.nf | 1 - .../tractogram/tests/main.nf.test.snap | 2 +- 17 files changed, 598 insertions(+), 236 deletions(-) rename modules/nf-neuro/registration/ants/tests/{nextflow_options.config => nextflow_no_warp.config} (84%) diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index cac9b896..803efb5c 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -5,23 +5,27 @@ process REGISTRATION_ANATTODWI { container "scilus/scilus:2.2.0" input: - tuple val(meta), path(t1), path(b0), path(metric) + tuple val(meta), path(fixedreference), path(movinganat), path(metric) output: - tuple val(meta), path("*__output0ForwardAffine.mat") , emit: affine - tuple val(meta), path("*__output1ForwardWarp.nii.gz") , emit: warp - tuple val(meta), path("*__output0BackwardWarp.nii.gz") , emit: inverse_warp - tuple val(meta), path("*__output1BackwardAffine.nii.gz") , emit: inverse_affine - tuple val(meta), path("*t1_warped.nii.gz") , emit: t1_warped - tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*_warped.nii.gz") , emit: anat_warped + tuple val(meta), path("*__output1ForwardAffine.mat") , emit: affine + tuple val(meta), path("*__output0ForwardWarp.nii.gz") , emit: warp + tuple val(meta), path("*__output1BackwardWarp.nii.gz") , emit: inverse_warp + tuple val(meta), path("*__output0BackwardAffine.mat") , emit: inverse_affine + tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform + tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform + tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform + tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform + tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: def prefix = task.ext.prefix ?: "${meta.id}" - def run_qc = task.ext.run_qc ? task.ext.run_qc : false + def run_qc = task.ext.run_qc as Boolean || false """ export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=$task.cpus @@ -33,35 +37,38 @@ process REGISTRATION_ANATTODWI { --output [output,outputWarped.nii.gz,outputInverseWarped.nii.gz]\ --interpolation Linear --use-histogram-matching 0\ --winsorize-image-intensities [0.005,0.995]\ - --initial-moving-transform [$b0,$t1,1]\ + --initial-moving-transform [$fixedreference,$movinganat,1]\ --transform Rigid['0.2']\ - --metric MI[$b0,$t1,1,32,Regular,0.25]\ + --metric MI[$fixedreference,$movinganat,1,32,Regular,0.25]\ --convergence [500x250x125x50,1e-6,10] --shrink-factors 8x4x2x1\ --smoothing-sigmas 3x2x1x0\ --transform Affine['0.2']\ - --metric MI[$b0,$t1,1,32,Regular,0.25]\ + --metric MI[$fixedreference,$movinganat,1,32,Regular,0.25]\ --convergence [500x250x125x50,1e-6,10] --shrink-factors 8x4x2x1\ --smoothing-sigmas 3x2x1x0\ --transform SyN[0.1,3,0]\ - --metric MI[$b0,$t1,1,32]\ - --metric CC[$metric,$t1,1,4]\ + --metric MI[$fixedreference,$movinganat,1,32]\ + --metric CC[$metric,$movinganat,1,4]\ --convergence [50x25x10,1e-6,10] --shrink-factors 4x2x1\ --smoothing-sigmas 3x2x1 - mv outputWarped.nii.gz ${prefix}__t1_warped.nii.gz - mv output0GenericAffine.mat ${prefix}__output0ForwardAffine.mat - mv output1InverseWarp.nii.gz ${prefix}__output0BackwardWarp.nii.gz - mv output1Warp.nii.gz ${prefix}__output1ForwardWarp.nii.gz + moving_id=\$(basename $movinganat .nii.gz) + moving_id=\${moving_id#${meta.id}__*} - antsApplyTransforms -d 3 -i $b0 -r $t1 \ - -o Linear[${prefix}__output1BackwardAffine.mat] \ - -t [${prefix}__output0ForwardAffine.mat,1] + mv outputWarped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz + mv output0GenericAffine.mat ${prefix}__output1ForwardAffine.mat + mv output1Warp.nii.gz ${prefix}__output0ForwardWarp.nii.gz + mv output1InverseWarp.nii.gz ${prefix}__output1BackwardWarp.nii.gz + + antsApplyTransforms -d 3 -i $movinganat -r $fixedreference \ + -o Linear[${prefix}__output0BackwardAffine.mat] \ + -t [${prefix}__output1ForwardAffine.mat,1] ### ** QC ** ### if $run_qc; then # Extract dimensions. - dim=\$(mrinfo ${prefix}__t1_warped.nii.gz -size) + dim=\$(mrinfo ${prefix}__\${moving_id}_warped.nii.gz -size) read sagittal_dim coronal_dim axial_dim <<< "\${dim}" # Get middle slices. @@ -72,8 +79,12 @@ process REGISTRATION_ANATTODWI { # Set viz params. viz_params="--display_slice_number --display_lr --size 256 256" + # Get fixed ID, moving ID already computed + fixed_id=\$(basename $fixedreference .nii.gz) + fixed_id=\${fixed_id#${meta.id}__*} + # Iterate over images. - for image in t1_warped b0; + for image in \${moving_id}_warped \${fixed_id}; do mrconvert *\${image}.nii.gz *\${image}_viz.nii.gz -stride -1,2,3 scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_coronal.png \ @@ -83,11 +94,11 @@ process REGISTRATION_ANATTODWI { scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_axial.png \ --slices \$axial_mid --axis axial \$viz_params - if [ \$image != b0 ]; + if [ \$image != \${fixed_id} ]; then - title="Warped T1" + title="Warped \${moving_id^^}" else - title="Reference B0" + title="Reference \${fixed_id^^}" fi convert +append \${image}_coronal*.png \${image}_axial*.png \ @@ -101,19 +112,19 @@ process REGISTRATION_ANATTODWI { # Create GIF. convert -delay 10 -loop 0 -morph 10 \ - t1_warped_mosaic.png b0_mosaic.png t1_warped_mosaic.png \ + \${moving_id}_warped_mosaic.png \${fixed_id}_mosaic.png \${moving_id}_warped_mosaic.png \ ${prefix}_registration_anattodwi_mqc.gif # Clean up. - rm t1_warped_mosaic.png b0_mosaic.png + rm \${moving_id}_warped_mosaic.png \${fixed_id}_mosaic.png fi cat <<-END_VERSIONS > versions.yml "${task.process}": - scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') - mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') + mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') + scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ @@ -133,19 +144,22 @@ process REGISTRATION_ANATTODWI { scil_viz_volume_screenshot -h convert -h - touch ${prefix}__t1_warped.nii.gz - touch ${prefix}__output0ForwardAffine.mat - touch ${prefix}__output1ForwardWarp.nii.gz - touch ${prefix}__output0BackwardWarp.nii.gz - touch ${prefix}__output1BackwardAffine.mat + moving_id=\$(basename $movinganat .nii.gz) + moving_id=\${moving_id#${meta.id}__*} + + touch ${prefix}__\${moving_id}_warped.nii.gz + touch ${prefix}__output1ForwardAffine.mat + touch ${prefix}__output0ForwardWarp.nii.gz + touch ${prefix}__output1BackwardWarp.nii.gz + touch ${prefix}__output0BackwardAffine.mat touch ${prefix}__registration_anattodwi_mqc.gif cat <<-END_VERSIONS > versions.yml "${task.process}": - scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') - mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') + mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') + scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ } diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index aa5e0681..c28150be 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -8,82 +8,151 @@ keywords: - dwi tools: - ANTs: - description: Advanced Normalization Tools (ANTs) for image processing. - homepage: http://stnava.github.io/ANTs/ + description: "Advanced Normalization Tools." + homepage: "https://github.com/ANTsX/ANTs" + documentation: "http://stnava.github.io/ANTsDoc/" doi: "10.1038/s41598-021-87564-6" - identifier: "" + - ImageMagick: + description: "ImageMagick is a software suite to create, edit, compose, or convert bitmap images." + homepage: "https://imagemagick.org/" + documentation: "https://imagemagick.org/script/command-line-processing.php" + - MRtrix3: + description: "MRtrix3 is a software package for processing diffusion MRI data." + homepage: "https://www.mrtrix3.org/" + documentation: "https://mrtrix.readthedocs.io/en/latest/" + doi: "10.1016/j.neuroimage.2019.116137" + - Scilpy: + description: "Scilpy is a Python library for processing diffusion MRI data." + homepage: "https://github.com/scilus/scilpy" + documentation: "https://scilpy.readthedocs.io/en/latest/" +args: + - run_qc: + type: boolean + description: "Run quality control for the registration process" + default: false + input: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - t1: + - fixedreference: type: file - description: Nifti image file to register on dwi + description: Nifti image file - fixed DWI reference (usually b0) pattern: "*.{nii,nii.gz}" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - b0: + - movinganat: type: file - description: Nifti image file - b0 + description: Nifti image file - moving anat to register (usually T1w) pattern: "*.{nii,nii.gz}" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - metric: type: file - description: Nifti image file metric used to register (fa) + description: Nifti image file - additional fixed metric (usually FA) pattern: "*.{nii,nii.gz}" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format output: + anat_warped: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.{nii,nii.gz}": + type: file + description: Anatomical image warped to DWI space + pattern: "*.{nii,nii.gz}" + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format affine: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*0GenericAffine.mat": - type: file - description: Affine transformation matrix. - pattern: "*0GenericAffine.mat" - ontologies: [] + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__output1ForwardAffine.mat": + type: file + description: Affine transformation matrix file. + pattern: "*__output1ForwardAffine.mat" + ontologies: [] warp: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*1Warp.nii.gz": - type: file - description: Warp field. - pattern: "*1Warp.{nii,nii.gz}" - ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__output0ForwardWarp.nii.gz": + type: file + description: Deformation field file. + pattern: "*__output0ForwardWarp.nii.gz" + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format inverse_warp: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__output1BackwardWarp.nii.gz": + type: file + description: Inverse deformation field file. + pattern: "*__output1BackwardWarp.nii.gz" + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format + inverse_affine: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__output0BackwardAffine.mat": + type: file + description: Inverse affine transformation matrix file. + pattern: "*__output0BackwardAffine.mat" + ontologies: [] + image_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Transformation files to warp images in the correct order + for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. + pattern: "*.{nii,nii.gz,mat}" + ontologies: [] + inverse_image_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Transformation files to warp images in the correct order for + REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*.{nii,nii.gz,mat}" + ontologies: [] + tractogram_transform: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*1InverseWarp.nii.gz": - type: file - description: Inverse warp field. - pattern: "*1InverseWarp.{nii,nii.gz}" - ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format - t1_warped: - - - meta: - type: map + - "*.{nii,nii.gz,mat}": + type: list description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*t1_warped.nii.gz": - type: file - description: Anatomical T1 warped to dwi space. - pattern: "*t1_warped.{nii,nii.gz}" - ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*.{nii,nii.gz,mat}" + ontologies: [] mqc: - - meta: type: map @@ -104,5 +173,6 @@ output: pattern: versions.yml ontologies: - edam: http://edamontology.org/format_3750 # YAML + authors: - "@medde" diff --git a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test index 0b675aa2..bc9f06d0 100644 --- a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test +++ b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test @@ -53,8 +53,8 @@ nextflow_process { file("\${test_data_directory}/fa.nii.gz") ] } - input[0] = ch_t1w - .join(ch_b0) + input[0] = ch_b0 + .join(ch_t1w) .join(ch_fa) """ } @@ -98,8 +98,8 @@ nextflow_process { file("\${test_data_directory}/fa.nii.gz") ] } - input[0] = ch_t1w - .join(ch_b0) + input[0] = ch_b0 + .join(ch_t1w) .join(ch_fa) """ } diff --git a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap index 437f536f..24cc1077 100644 --- a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap @@ -20,6 +20,9 @@ "test__output1Warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" ] ], + "10": [ + "versions.yml:md5,f7d4a628967ea923c4ce688c43ad7f5f" + ], "2": [ [ { @@ -77,7 +80,7 @@ "test_registration_anattodwi_mqc.gif:md5,687252d31b0109f99a174b4e3960e4e6" ] ], - "t1_warped": [ + "tractogram_transform": [ [ { "id": "test", diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index 5f9d7b44..661d319f 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -9,37 +9,42 @@ process REGISTRATION_ANTS { tuple val(meta), path(fixedimage), path(movingimage), path(mask) //** optional, input = [] **// output: - tuple val(meta), path("*_warped.nii.gz") , emit: image - tuple val(meta), path("*__output0ForwardAffine.mat") , emit: affine - tuple val(meta), path("*__output1ForwardWarp.nii.gz") , emit: warp, optional:true - tuple val(meta), path("*__output0BackwardWarp.nii.gz") , emit: inverse_warp, optional: true - tuple val(meta), path("*__output1BackwardAffine.mat") , emit: inverse_affine - tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*_warped.nii.gz") , emit: image + tuple val(meta), path("*__output1ForwardAffine.mat") , emit: affine + tuple val(meta), path("*__output0ForwardWarp.nii.gz") , emit: warp, optional: true + tuple val(meta), path("*__output1BackwardWarp.nii.gz") , emit: inverse_warp, optional: true + tuple val(meta), path("*__output0BackwardAffine.mat") , emit: inverse_affine + tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform + tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform + tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform + tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform + tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: + def initialization_types = ["geometric center": 0, "intensities": 1, "origin": 2] def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - def suffix_qc = task.ext.suffix_qc ? "${task.ext.suffix_qc}" : "" - def ants = task.ext.quick ? "antsRegistrationSyNQuick.sh " : "antsRegistrationSyN.sh " - def dimension = task.ext.dimension ? "-d " + task.ext.dimension : "-d 3" - def transform = task.ext.transform ? task.ext.transform : "s" - def seed = task.ext.random_seed ? " -e " + task.ext.random_seed : "-e 1234" - def run_qc = task.ext.run_qc ? task.ext.run_qc : false - - if ( task.ext.threads ) args += "-n " + task.ext.threads - if ( task.ext.initial_transform ) args += " -i " + task.ext.initial_transform - if ( task.ext.histogram_bins ) args += " -r " + task.ext.histogram_bins - if ( task.ext.spline_distance ) args += " -s " + task.ext.spline_distance - if ( task.ext.gradient_step ) args += " -g " + task.ext.gradient_step - if ( task.ext.mask ) args += " -x $mask" - if ( task.ext.type ) args += " -p " + task.ext.type - if ( task.ext.histogram_matching ) args += " -j " + task.ext.histogram_matching - if ( task.ext.repro_mode ) args += " -y " + task.ext.repro_mode - if ( task.ext.collapse_output ) args += " -z " + task.ext.collapse_output + def suffix_qc = task.ext.suffix_qc ?: "" + def ants = task.ext.quick ? "antsRegistrationSyNQuick.sh" : "antsRegistrationSyN.sh" + def dimension = "-d ${task.ext.dimension ?: 3}" + def transform = task.ext.transform ?: "s" + def seed = " -e ${task.ext.random_seed ?: 1234}" + def run_qc = task.ext.run_qc as Boolean || false + + args += " -n $task.cpus" + if ( mask ) args += " -x $mask" + if ( task.ext.initial_transform ) args += " -i [$fixedimage,$movingimage,${initialization_types[task.ext.initial_transform]}]" + if ( task.ext.histogram_bins ) args += " -r $task.ext.histogram_bins" + if ( task.ext.spline_distance ) args += " -s $task.ext.spline_distance" + if ( task.ext.gradient_step ) args += " -g $task.ext.gradient_step" + if ( task.ext.precision ) args += " -p $task.ext.precision" + if ( task.ext.histogram_matching ) args += " -j $task.ext.histogram_matching" + if ( task.ext.repro_mode ) args += " -y $task.ext.repro_mode" + if ( task.ext.collapse_output ) args += " -z $task.ext.collapse_output" """ export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=$task.cpus @@ -49,17 +54,17 @@ process REGISTRATION_ANTS { $ants $dimension -f $fixedimage -m $movingimage -o output -t $transform $args $seed mv outputWarped.nii.gz ${prefix}__warped.nii.gz - mv output0GenericAffine.mat ${prefix}__output0ForwardAffine.mat + mv output0GenericAffine.mat ${prefix}__output1ForwardAffine.mat if [ $transform != "t" ] && [ $transform != "r" ] && [ $transform != "a" ]; then - mv output1InverseWarp.nii.gz ${prefix}__output0BackwardWarp.nii.gz - mv output1Warp.nii.gz ${prefix}__output1ForwardWarp.nii.gz + mv output1InverseWarp.nii.gz ${prefix}__output1BackwardWarp.nii.gz + mv output1Warp.nii.gz ${prefix}__output0ForwardWarp.nii.gz fi antsApplyTransforms -d 3 -i $fixedimage -r $movingimage \ - -o Linear[${prefix}__output1BackwardAffine.mat] \ - -t [${prefix}__output0ForwardAffine.mat,1] + -o Linear[${prefix}__output0BackwardAffine.mat] \ + -t [${prefix}__output1ForwardAffine.mat,1] ### ** QC ** ### if $run_qc; @@ -108,10 +113,10 @@ process REGISTRATION_ANTS { cat <<-END_VERSIONS > versions.yml "${task.process}": - scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') - mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') + mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') + scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ @@ -133,17 +138,17 @@ process REGISTRATION_ANTS { scil_viz_volume_screenshot -h touch ${prefix}__t1_warped.nii.gz - touch ${prefix}__output0ForwardAffine.mat - touch ${prefix}__output1ForwardWarp.nii.gz - touch ${prefix}__output0BackwardWarp.nii.gz - touch ${prefix}__output1BackwardAffine.mat + touch ${prefix}__output1ForwardAffine.mat + touch ${prefix}__output0ForwardWarp.nii.gz + touch ${prefix}__output1BackwardWarp.nii.gz + touch ${prefix}__output0BackwardAffine.mat cat <<-END_VERSIONS > versions.yml "${task.process}": - scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') - mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') + mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') + scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ } diff --git a/modules/nf-neuro/registration/ants/meta.yml b/modules/nf-neuro/registration/ants/meta.yml index 73657632..544f0747 100644 --- a/modules/nf-neuro/registration/ants/meta.yml +++ b/modules/nf-neuro/registration/ants/meta.yml @@ -1,18 +1,126 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json -name: registration_ants -description: Image registration with antsRegistrationSyN or antsRegistrationSyNQuick +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/scilus/nf-neuro/main/modules/meta-schema.json +name: "registration_ants" +description: | + Image registration with antsRegistrationSyN or antsRegistrationSyNQuick. + + Defaults: 3D images and 3-stage registration (rigid + affine + deformable) + + Main features: + (1) Supports multiple transformation types (see `transform` argument). + (2) Supports initial transformations (see `initial_transform` argument) via a closure, e.g. `{ [$fixedimage,$movingimage,0] }`. + (3) Automatic creation of inverse transformations matrices. + (4) Curated combined output transformations for REGISTRATION_ANTSAPPLYTRANSFORMS and + REGISTRATION_TRANSFORMTRACTOGRAM processes : `image_transform`, `tractogram_transform`, and their inverse. + (5) Quality control (QC) image generation for MultiQC reports. keywords: - nifti - registration - - SyN - - SyNQuick - - trk + - antsRegistrationSyN + - antsRegistrationSyNQuick tools: - ANTs: - description: Advanced Normalization Tools (ANTs) for image processing. - homepage: http://stnava.github.io/ANTs/ + description: "Advanced Normalization Tools." + homepage: "https://github.com/ANTsX/ANTs" + documentation: "http://stnava.github.io/ANTsDoc/" doi: "10.1038/s41598-021-87564-6" - identifier: "" + - ImageMagick: + description: "ImageMagick is a software suite to create, edit, compose, or convert bitmap images." + homepage: "https://imagemagick.org/" + documentation: "https://imagemagick.org/script/command-line-processing.php" + - MRtrix3: + description: "MRtrix3 is a software package for processing diffusion MRI data." + homepage: "https://www.mrtrix3.org/" + documentation: "https://mrtrix.readthedocs.io/en/latest/" + doi: "10.1016/j.neuroimage.2019.116137" + - Scilpy: + description: "Scilpy is a Python library for processing diffusion MRI data." + homepage: "https://github.com/scilus/scilpy" + documentation: "https://scilpy.readthedocs.io/en/latest/" +args: + - quick: + type: boolean + description: "Use antsRegistrationSyNQuick instead of antsRegistrationSyN." + default: false + - repro_mode: + type: boolean + description: "Run in reproducibility mode (single threaded)." + default: false + - histogram_matching: + type: boolean + description: "Perform histogram matching between images before registration." + default: false + - transform: + type: string + description: | + Type of transformation to perform : + - t : translation (1 stage) + - r : rigid (1 stage) + - a : rigid + affine (2 stages) + - s : rigid + affine + deformable syn (3 stages) + - sr : rigid + deformable syn (2 stages) + - so : deformable syn only (1 stage) + - b : rigid + affine + deformable b-spline syn (3 stages) + - br : rigid + deformable b-spline syn (2 stages) + - bo : deformable b-spline syn only (1 stage) + default: "s" + choices: + - t + - r + - a + - s + - sr + - so + - b + - br + - bo + - initial_transform: + type: string + description: Algorithmic initialization by geometric center, intensities, or origin. + default: "" + choices: + - geometric_center + - intensities + - origin + - dimension: + type: int + description: "Number of spatial dimensions of the images" + default: 3 + - gradient_step: + type: float + description: "Gradient step size for the optimization of SyN and B-spline SyN." + default: 0.1 + - histogram_bins: + type: int + description: "Number of histogram bins when using the Mutual Information metric with SyN and B-spline SyN." + default: 32 + - spline_distance: + type: float + description: "Distance between control points for B-spline SyN." + default: 26 + - run_qc: + type: boolean + description: "Run quality control (QC) to generate a MultiQC report." + default: false + - suffix_qc: + type: string + description: "Suffix for the QC image file." + default: "" + - precision: + type: string + description: "Precision of the output image." + default: "float" + choices: + - float + - double + - collapse_output: + type: boolean + description: "Collapse output transformations into a single file." + default: false + - random_seed: + type: int + description: "Random seed for reproducibility." + default: 1234 input: # Only when we have meta - - meta: @@ -57,21 +165,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output0GenericAffine.mat": + - "*__output1ForwardAffine.mat": type: file description: Affine transformation from moving to fixed - pattern: "*__output0GenericAffine.mat" - ontologies: [] - inverse_affine: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*__output1InverseAffine.mat": - type: file - description: Affine transformation from fixed to moving - pattern: "*__output1InverseAffine.mat" + pattern: "*__output1ForwardAffine.mat" ontologies: [] warp: - - meta: @@ -79,10 +176,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output1Warp.nii.gz": + - "*__output0ForwardWarp.nii.gz": type: file description: Nifti volume containing warp field from moving to fixed - pattern: "*__output1Warp.nii.gz" + pattern: "*__output0ForwardWarp.nii.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format inverse_warp: @@ -91,12 +188,75 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output0InverseWarp.nii.gz": + - "*__output1BackwardWarp.nii.gz": type: file description: Nifti volume containing warp field from fixed to moving - pattern: "*__output0InverseWarp.nii.gz" + pattern: "*__output1BackwardWarp.nii.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format + inverse_affine: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__output0BackwardAffine.mat": + type: file + description: Affine transformation from fixed to moving + pattern: "*__output0BackwardAffine.mat" + ontologies: [] + image_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + pattern: "*.{nii,nii.gz,mat}" + ontologies: [] + inverse_image_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Inverse transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*.{nii,nii.gz,mat}" + ontologies: [] + tractogram_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*.{nii,nii.gz,mat}" + ontologies: [] + inverse_tractogram_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Inverse transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*.{nii,nii.gz,mat}" + ontologies: [] mqc: - - meta: type: map @@ -118,3 +278,4 @@ output: - edam: http://edamontology.org/format_3750 # YAML authors: - "@ThoumyreStanislas" + - "@AlexVCaron" diff --git a/modules/nf-neuro/registration/ants/tests/main.nf.test b/modules/nf-neuro/registration/ants/tests/main.nf.test index 41c856ad..df3133e0 100644 --- a/modules/nf-neuro/registration/ants/tests/main.nf.test +++ b/modules/nf-neuro/registration/ants/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_process { name "Test Process REGISTRATION_ANTS" script "../main.nf" process "REGISTRATION_ANTS" + config "./nextflow.config" tag "modules" tag "modules_nfneuro" @@ -17,22 +18,21 @@ nextflow_process { script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf" process { """ - input[0] = Channel.from( [ "T1w.zip", "b0.zip" ] ) + input[0] = Channel.from( [ "T1w.zip", "others.zip" ] ) input[1] = "test.load-test-data" """ } } } - test("registration - ants") { - config "./nextflow.config" + test("registration - ants - SyN") { when { process { """ ch_split_test_data = LOAD_DATA.out.test_data_directory .branch{ T1w: it.simpleName == "T1w" - b0: it.simpleName == "b0" + moving: it.simpleName == "others" } ch_T1w = ch_split_test_data.T1w.map{ test_data_directory -> [ @@ -40,15 +40,21 @@ nextflow_process { file("\${test_data_directory}/T1w.nii.gz") ] } - ch_b0 = ch_split_test_data.b0.map{ + ch_moving = ch_split_test_data.moving.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz") + file("\${test_data_directory}/t1.nii.gz") ] } - input[0] = ch_b0 - .join(ch_T1w) - .map{ it + [[]] } + ch_T1w_mask = ch_split_test_data.T1w.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/T1w_mask.nii.gz") + ] + } + input[0] = ch_T1w + .join(ch_moving) + .join(ch_T1w_mask) """ } } @@ -60,7 +66,7 @@ nextflow_process { } } - test("registration - ants - quick") { + test("registration - ants - SyN quick") { config "./nextflow_quick.config" when { process { @@ -68,7 +74,7 @@ nextflow_process { ch_split_test_data = LOAD_DATA.out.test_data_directory .branch{ T1w: it.simpleName == "T1w" - b0: it.simpleName == "b0" + moving: it.simpleName == "others" } ch_T1w = ch_split_test_data.T1w.map{ test_data_directory -> [ @@ -76,15 +82,21 @@ nextflow_process { file("\${test_data_directory}/T1w.nii.gz") ] } - ch_b0 = ch_split_test_data.b0.map{ + ch_moving = ch_split_test_data.moving.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/t1.nii.gz") + ] + } + ch_T1w_mask = ch_split_test_data.T1w.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz") + file("\${test_data_directory}/T1w_mask.nii.gz") ] } - input[0] = ch_b0 - .join(ch_T1w) - .map{ it + [[]] } + input[0] = ch_T1w + .join(ch_moving) + .join(ch_T1w_mask) """ } } @@ -96,31 +108,37 @@ nextflow_process { } } - test("registration - ants - options") { - config "./nextflow_options.config" + test("registration - ants - no warps") { + config "./nextflow_no_warp.config" when { process { """ ch_split_test_data = LOAD_DATA.out.test_data_directory .branch{ T1w: it.simpleName == "T1w" - b0: it.simpleName == "b0" + moving: it.simpleName == "others" } ch_T1w = ch_split_test_data.T1w.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/T1w.nii.gz"), - file("\${test_data_directory}/T1w_mask.nii.gz") + file("\${test_data_directory}/T1w.nii.gz") ] } - ch_b0 = ch_split_test_data.b0.map{ + ch_moving = ch_split_test_data.moving.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz") + file("\${test_data_directory}/t1.nii.gz") ] } - input[0] = ch_b0 - .join(ch_T1w) + ch_T1w_mask = ch_split_test_data.T1w.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/T1w_mask.nii.gz") + ] + } + input[0] = ch_T1w + .join(ch_moving) + .join(ch_T1w_mask) """ } } @@ -141,23 +159,29 @@ nextflow_process { ch_split_test_data = LOAD_DATA.out.test_data_directory .branch{ T1w: it.simpleName == "T1w" - b0: it.simpleName == "b0" + moving: it.simpleName == "others" } ch_T1w = ch_split_test_data.T1w.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/T1w.nii.gz"), - file("\${test_data_directory}/T1w_mask.nii.gz") + file("\${test_data_directory}/T1w.nii.gz") + ] + } + ch_moving = ch_split_test_data.moving.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/t1.nii.gz") ] } - ch_b0 = ch_split_test_data.b0.map{ + ch_T1w_mask = ch_split_test_data.T1w.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz") + file("\${test_data_directory}/T1w_mask.nii.gz") ] } - input[0] = ch_b0 - .join(ch_T1w) + input[0] = ch_T1w + .join(ch_moving) + .join(ch_T1w_mask) """ } } diff --git a/modules/nf-neuro/registration/ants/tests/nextflow.config b/modules/nf-neuro/registration/ants/tests/nextflow.config index 675ffab6..ee34944b 100644 --- a/modules/nf-neuro/registration/ants/tests/nextflow.config +++ b/modules/nf-neuro/registration/ants/tests/nextflow.config @@ -2,6 +2,6 @@ process { withName: "REGISTRATION_ANTS" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.repro_mode = 1 - ext.initial_transform = { "[$fixedimage,$movingimage,1]" } + ext.initial_transform = "intensities" } } diff --git a/modules/nf-neuro/registration/ants/tests/nextflow_options.config b/modules/nf-neuro/registration/ants/tests/nextflow_no_warp.config similarity index 84% rename from modules/nf-neuro/registration/ants/tests/nextflow_options.config rename to modules/nf-neuro/registration/ants/tests/nextflow_no_warp.config index 88c9a90a..3e060ea6 100644 --- a/modules/nf-neuro/registration/ants/tests/nextflow_options.config +++ b/modules/nf-neuro/registration/ants/tests/nextflow_no_warp.config @@ -2,14 +2,11 @@ process { withName: "REGISTRATION_ANTS" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.quick = true - ext.run_qc = true - ext.threads = 1 ext.transform = "r" ext.histogram_bins = 4 ext.spline_distance = 26 ext.gradient_step = 0.1 ext.histogram_matching = 0 - ext.repro_mode = 0 ext.collapse_output = 0 ext.random_seed = 1234 } diff --git a/modules/nf-neuro/registration/ants/tests/nextflow_quick.config b/modules/nf-neuro/registration/ants/tests/nextflow_quick.config index 9fd98e5b..18651856 100644 --- a/modules/nf-neuro/registration/ants/tests/nextflow_quick.config +++ b/modules/nf-neuro/registration/ants/tests/nextflow_quick.config @@ -2,8 +2,7 @@ process { withName: "REGISTRATION_ANTS" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.quick = true - ext.repro_mode = 1 ext.run_qc = true - ext.suffix_qc = "T1_to_DWI" + ext.suffix_qc = "T1_to_T1_slab" } } diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index 7b0b9551..cbad21e7 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -5,7 +5,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { container "scilus/scilus:2.2.0" input: - tuple val(meta), path(image), path(reference), path(warp), path(affine) + tuple val(meta), path(images, arity: '1..*'), path(reference), path(transformations, arity: '1..*') output: tuple val(meta), path("*__warped.nii.gz") , emit: warped_image @@ -17,38 +17,62 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { script: def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = task.ext.first_suffix ? "${task.ext.first_suffix}__warped" : "__warped" - def suffix_qc = task.ext.suffix_qc ? "${task.ext.suffix_qc}" : "" + def suffix = "${task.ext.first_suffix ?: ""}__warped" + def suffix_qc = task.ext.suffix_qc ?: "" - def output_dtype = task.ext.output_dtype ? "-u " + task.ext.output_dtype : "" - def dimensionality = task.ext.dimensionality ? "-d " + task.ext.dimensionality : "-d 3" - def image_type = task.ext.image_type ? "-e " + task.ext.image_type : "-e 0" - def interpolation = task.ext.interpolation ? "-n " + task.ext.interpolation : "" - def default_val = task.ext.default_val ? "-f " + task.ext.default_val : "" - def run_qc = task.ext.run_qc ? task.ext.run_qc : false + def output_dtype = "-u ${task.ext.output_dtype ?: "default"}" + def dimensionality = "-d ${task.ext.dimensionality ?: 3}" + def image_type = "-e ${task.ext.image_type ?: 0}" + def interpolation = "-n ${task.ext.interpolation ?: "Linear"}" + def default_val = "-f ${task.ext.default_val ?: 3}" + def run_qc = task.ext.run_qc as Boolean || false """ export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=$task.cpus export OMP_NUM_THREADS=1 export OPENBLAS_NUM_THREADS=1 - for image in $image; - do \ - ext=\${image#*.} - bname=\$(basename \${image} .\${ext}) - - antsApplyTransforms $dimensionality\ - -i \$image\ - -r $reference\ - -o ${prefix}__\${bname}${suffix}.nii.gz\ - $interpolation\ - -t $warp $affine\ - $output_dtype\ - $image_type\ - $default_val - - ### ** QC ** ### - if $run_qc; + for image in $images; + do + + ext=\${image#*.} + bname=\$(basename \${image} .\${ext}) + + antsApplyTransforms $dimensionality \ + -i \$image \ + -r $reference \ + -o ${prefix}__\${bname}${suffix}.nii.gz \ + $interpolation \ + ${transformations.collect{ t -> "-t $t" }.join(" ")} \ + $output_dtype \ + $image_type \ + $default_val + + ### ** QC ** ### + if $run_qc; + then + + ln -sf $reference reference.nii.gz + extract_dim=\$(mrinfo ${prefix}__\${bname}${suffix}.nii.gz -size) + read sagittal_dim coronal_dim axial_dim <<< "\${extract_dim}" + + # Get the middle slice + coronal_dim=\$((\$coronal_dim / 2)) + axial_dim=\$((\$axial_dim / 2)) + sagittal_dim=\$((\$sagittal_dim / 2)) + + # Set viz params. + viz_params="--display_slice_number --display_lr --size 256 256" + # Iterate over images. + for image in reference \${bname}${suffix}; + do + scil_viz_volume_screenshot.py *\${image}.nii.gz \${image}_coronal.png \ + --slices \$coronal_dim --axis coronal \$viz_params + scil_viz_volume_screenshot.py *\${image}.nii.gz \${image}_sagittal.png \ + --slices \$sagittal_dim --axis sagittal \$viz_params + scil_viz_volume_screenshot.py *\${image}.nii.gz \${image}_axial.png \ + --slices \$axial_dim --axis axial \$viz_params + if [ \$image != reference ]; then mv $reference reference.nii.gz extract_dim=\$(mrinfo ${prefix}__\${bname}${suffix}.nii.gz -size) @@ -91,14 +115,30 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { # Clean up. rm *_mosaic.png fi + convert +append \${image}_coronal*.png \${image}_axial*.png \ + \${image}_sagittal*.png \${image}_mosaic.png + convert -annotate +20+230 "\${title}" -fill white -pointsize 30 \ + \${image}_mosaic.png \${image}_mosaic.png + # Clean up. + rm \${image}_coronal*.png \${image}_sagittal*.png \${image}_axial*.png + done + # Create GIF. + convert -delay 10 -loop 0 -morph 10 \ + \${bname}${suffix}_mosaic.png reference_mosaic.png \${bname}${suffix}_mosaic.png \ + ${prefix}_\${bname}${suffix_qc}_registration_antsapplytransforms_mqc.gif + # Clean up. + rm *_mosaic.png + + fi + done cat <<-END_VERSIONS > versions.yml "${task.process}": - scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') - mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') + mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') + scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ @@ -119,7 +159,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { convert -h scil_viz_volume_screenshot -h - for image in $image; + for image in $images; do \ ext=\${image#*.} bname=\$(basename \${image} .\${ext}) @@ -129,10 +169,10 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { cat <<-END_VERSIONS > versions.yml "${task.process}": - scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\1/') - mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') imagemagick: \$(convert -version | grep "Version:" | sed -E 's/.*ImageMagick ([0-9.-]+).*/\\1/') + mrtrix: \$(mrinfo -version 2>&1 | grep "== mrinfo" | sed -E 's/== mrinfo ([0-9.]+).*/\\1/') + scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ } diff --git a/modules/nf-neuro/registration/antsapplytransforms/meta.yml b/modules/nf-neuro/registration/antsapplytransforms/meta.yml index 181fb889..c1ea3760 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/meta.yml +++ b/modules/nf-neuro/registration/antsapplytransforms/meta.yml @@ -31,7 +31,7 @@ args: - dimensionality: type: number description: | - Dimensionality of the input image. + Dimensionality of input images. e.g. `2` for 2D images, `3` for 3D images. - image_type: type: integer diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test index 1aaddbef..23256d77 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_process { name "Test Process REGISTRATION_ANTSAPPLYTRANSFORMS" script "../main.nf" process "REGISTRATION_ANTSAPPLYTRANSFORMS" + config "./nextflow.config" tag "modules" tag "modules_nfneuro" @@ -25,9 +26,6 @@ nextflow_process { } test("registration - antsapplytransforms") { - - config "./nextflow.config" - when { process { """ @@ -36,7 +34,6 @@ nextflow_process { [ id:'test', single_end:false ], // meta map file("\${test_data_directory}/b0.nii.gz"), file("\${test_data_directory}/mni_masked_2x2x2.nii.gz"), - file("\${test_data_directory}/output1Warp.nii.gz"), file("\${test_data_directory}/output0GenericAffine.mat") ]} """ @@ -50,13 +47,64 @@ nextflow_process { } } - test("registration - antsapplytransforms - stub-run") { + test("registration - antsapplytransforms - multiple transforms") { + when { + process { + """ + input[0] = LOAD_DATA.out.test_data_directory + .map{ test_data_directory -> [ + [ id:'test', single_end:false ], // meta map + file("\${test_data_directory}/b0.nii.gz"), + file("\${test_data_directory}/mni_masked_2x2x2.nii.gz"), + [ + file("\${test_data_directory}/output1Warp.nii.gz"), + file("\${test_data_directory}/output0GenericAffine.mat") + ] + ]} + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + test("registration - antsapplytransforms - multiple images") { + when { + process { + """ + input[0] = LOAD_DATA.out.test_data_directory + .map{ test_data_directory -> [ + [ id:'test', single_end:false ], // meta map + [ + file("\${test_data_directory}/b0.nii.gz"), + file("\${test_data_directory}/b0.nii.gz").copyTo( + "\${test_data_directory}/b0_copy.nii.gz" + ) + ], + file("\${test_data_directory}/mni_masked_2x2x2.nii.gz"), + [ + file("\${test_data_directory}/output1Warp.nii.gz"), + file("\${test_data_directory}/output0GenericAffine.mat") + ] + ]} + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("registration - antsapplytransforms - stub-run") { tag "stub" options "-stub-run" - - config "./nextflow.config" - when { process { """ @@ -65,8 +113,10 @@ nextflow_process { [ id:'test', single_end:false ], // meta map file("\${test_data_directory}/b0.nii.gz"), file("\${test_data_directory}/mni_masked_2x2x2.nii.gz"), - file("\${test_data_directory}/output1Warp.nii.gz"), - file("\${test_data_directory}/output0GenericAffine.mat") + [ + file("\${test_data_directory}/output1Warp.nii.gz"), + file("\${test_data_directory}/output0GenericAffine.mat") + ] ]} """ } diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap index 5a153e08..9f28397d 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "registration - antsapplytransforms": { + "registration - antsapplytransforms - multiple transforms": { "content": [ { "0": [ @@ -64,4 +64,4 @@ }, "timestamp": "2025-10-09T20:09:58.870177157" } -} \ No newline at end of file +} diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config b/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config index 8e50f45e..1aac9a64 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config @@ -1,6 +1,6 @@ process { withName: "REGISTRATION_ANTSAPPLYTRANSFORMS" { - ext.interpolation = "linear" + ext.interpolation = "Linear" ext.first_suffix = "b0" ext.dimensionality = 3 ext.image_type = 0 diff --git a/modules/nf-neuro/registration/tractogram/main.nf b/modules/nf-neuro/registration/tractogram/main.nf index fe1a9086..a6a33153 100644 --- a/modules/nf-neuro/registration/tractogram/main.nf +++ b/modules/nf-neuro/registration/tractogram/main.nf @@ -70,7 +70,6 @@ process REGISTRATION_TRACTOGRAM { ext=\${tractogram#*.} bname=\$(basename \${tractogram} .\${ext} | sed 's/${prefix}_\\+//') - touch ${prefix}__\${bname}${suffix}.\${ext} done cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap index b3172550..93f75e88 100644 --- a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap @@ -97,4 +97,4 @@ }, "timestamp": "2025-09-22T22:17:13.547090754" } -} \ No newline at end of file +} From 9994f48a0287eb0be1216b07645e261c17e8d316 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Fri, 18 Jul 2025 19:27:32 +0000 Subject: [PATCH 04/37] SUBWORKFLOWS : work in progress --- subworkflows/nf-neuro/bundle_seg/main.nf | 29 +++-- .../nf-neuro/bundle_seg/tests/main.nf.test | 2 +- .../bundle_seg/tests/main.nf.test.snap | 2 +- .../nf-neuro/output_template_space/main.nf | 68 +++++------ .../tests/main.nf.test.snap | 2 +- subworkflows/nf-neuro/registration/main.nf | 94 ++++++++++----- .../nf-neuro/registration/tests/main.nf.test | 10 +- .../registration/tests/main.nf.test.snap | 107 ++++++++++++++---- subworkflows/nf-neuro/tractoflow/main.nf | 32 +++--- .../nf-neuro/tractoflow/tests/main.nf.test | 2 +- .../tractoflow/tests/main.nf.test.snap | 12 +- 11 files changed, 235 insertions(+), 125 deletions(-) diff --git a/subworkflows/nf-neuro/bundle_seg/main.nf b/subworkflows/nf-neuro/bundle_seg/main.nf index ff489e2d..08dbcefa 100644 --- a/subworkflows/nf-neuro/bundle_seg/main.nf +++ b/subworkflows/nf-neuro/bundle_seg/main.nf @@ -1,5 +1,6 @@ -include { REGISTRATION_ANTS } from '../../../modules/nf-neuro/registration/ants/main' -include { BUNDLE_RECOGNIZE } from '../../../modules/nf-neuro/bundle/recognize/main' +include { BUNDLE_RECOGNIZE } from '../../../modules/nf-neuro/bundle/recognize/main' + +include { REGISTRATION } from '../../../subworkflows/nf-neuro/registration/main' def fetch_bundleseg_atlas(atlasUrl, configUrl, dest) { @@ -60,9 +61,11 @@ workflow BUNDLE_SEG { } else { if ( !file("$workflow.workDir/atlas/mni_masked.nii.gz").exists() ) { - fetch_bundleseg_atlas( "https://zenodo.org/records/10103446/files/atlas.zip?download=1", - "https://zenodo.org/records/10103446/files/config.zip?download=1", - "${workflow.workDir}/") + fetch_bundleseg_atlas( + "https://zenodo.org/records/10103446/files/atlas.zip?download=1", + "https://zenodo.org/records/10103446/files/config.zip?download=1", + "${workflow.workDir}/" + ) } atlas_anat = Channel.fromPath("$workflow.workDir/atlas/mni_masked.nii.gz") atlas_config = Channel.fromPath("$workflow.workDir/config/config_fss_1.json") @@ -71,15 +74,19 @@ workflow BUNDLE_SEG { // ** Register the atlas to subject's space. Set up atlas file as moving image ** // // ** and subject anat as fixed image. ** // - ch_register = ch_fa.combine(atlas_anat) - .map{ it + [[]] } - - REGISTRATION_ANTS ( ch_register ) - ch_versions = ch_versions.mix(REGISTRATION_ANTS.out.versions.first()) + REGISTRATION( + atlas_anat, + ch_fa, + Channel.empty(), + Channel.empty(), + Channel.empty(), + Channel.empty() + ) + ch_versions = ch_versions.mix(REGISTRATION.out.versions.first()) // ** Perform bundle recognition and segmentation ** // ch_recognize_bundle = ch_tractogram - .join(REGISTRATION_ANTS.out.affine) + .join(REGISTRATION.out.affine) .combine(atlas_config) .combine(atlas_average) diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test index 15d681cc..6f5314cd 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test @@ -60,7 +60,7 @@ nextflow_workflow { [(channel.key): ["versions"].contains(channel.key) ? channel.value : channel.value.collect{ subject -> - [ subject[0] ] + subject[1..-1].collect{ entry -> entry ? file(entry).name : "" } + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } } ] } ).match() } diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index c74639eb..464b86db 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -48,7 +48,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.6" }, "timestamp": "2025-10-17T17:38:41.717732229" } diff --git a/subworkflows/nf-neuro/output_template_space/main.nf b/subworkflows/nf-neuro/output_template_space/main.nf index 9b3f74b0..d7a770d9 100644 --- a/subworkflows/nf-neuro/output_template_space/main.nf +++ b/subworkflows/nf-neuro/output_template_space/main.nf @@ -3,12 +3,13 @@ include { IMAGE_APPLYMASK as MASK_T1W } from '../../../module include { IMAGE_APPLYMASK as MASK_T2W } from '../../../modules/nf-neuro/image/applymask/main.nf' include { BETCROP_FSLBETCROP as BET_T1W } from '../../../modules/nf-neuro/betcrop/fslbetcrop/main.nf' include { BETCROP_FSLBETCROP as BET_T2W } from '../../../modules/nf-neuro/betcrop/fslbetcrop/main.nf' -include { REGISTRATION_ANTS } from '../../../modules/nf-neuro/registration/ants/main.nf' include { REGISTRATION_ANTSAPPLYTRANSFORMS as WARPIMAGES } from '../../../modules/nf-neuro/registration/antsapplytransforms/main.nf' include { REGISTRATION_ANTSAPPLYTRANSFORMS as WARPMASK } from '../../../modules/nf-neuro/registration/antsapplytransforms/main.nf' include { REGISTRATION_ANTSAPPLYTRANSFORMS as WARPLABELS } from '../../../modules/nf-neuro/registration/antsapplytransforms/main.nf' include { REGISTRATION_TRACTOGRAM } from '../../../modules/nf-neuro/registration/tractogram/main.nf' +include { REGISTRATION } from '../registration/main.nf' + workflow OUTPUT_TEMPLATE_SPACE { take: @@ -84,7 +85,7 @@ workflow OUTPUT_TEMPLATE_SPACE { } ch_brain_mask = ch_brain_mask - | branch { + .branch { TRUE: it[0] != [] FALSE: false } @@ -92,55 +93,61 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** If the template has a brain mask, we will use it ** // if ( ! ch_brain_mask.FALSE ) { ch_bet_tpl_t1w = ch_t1w_tpl - | combine(ch_brain_mask) - | map{ t1w, mask -> [ [id: "template"], t1w, mask ] } + .combine(ch_brain_mask) + .map{ t1w, mask -> [ [id: "template"], t1w, mask ] } MASK_T1W ( ch_bet_tpl_t1w ) ch_versions = ch_versions.mix(MASK_T1W.out.versions) // ** Strip the template from the meta field so we can combine it ** // ch_t1w_tpl = MASK_T1W.out.image - | map{ _meta, image -> image } + .map{ _meta, image -> image } ch_bet_tpl_t2w = ch_t2w_tpl - | combine(ch_brain_mask) - | map{ t2w, mask -> [ [id: "template"], t2w, mask ] } + .combine(ch_brain_mask) + .map{ t2w, mask -> [ [id: "template"], t2w, mask ] } MASK_T2W ( ch_bet_tpl_t2w ) ch_versions = ch_versions.mix(MASK_T2W.out.versions) // ** Strip the template from the meta field so we can combine it ** // ch_t2w_tpl = MASK_T2W.out.image - | map{ _meta, image -> image } + .map{ _meta, image -> image } } else { // ** The template may not have a brain mask, so we will ** // // ** run BET by default (bit painful, but necessary) ** // ch_bet_tpl_t1w = ch_t1w_tpl - | map{ t1w -> [ [id: "template"], t1w, [], [] ] } + .map{ t1w -> [ [id: "template"], t1w, [], [] ] } BET_T1W ( ch_bet_tpl_t1w ) ch_versions = ch_versions.mix(BET_T1W.out.versions) // ** Strip the template from the meta field so we can combine it ** // ch_t1w_tpl = BET_T1W.out.image - | map{ _meta, image -> image } + .map{ _meta, image -> image } ch_bet_tpl_t2w = ch_t2w_tpl - | map{ t2w -> [ [id: "template"], t2w, [], [] ] } + .map{ t2w -> [ [id: "template"], t2w, [], [] ] } BET_T2W ( ch_bet_tpl_t2w ) ch_versions = ch_versions.mix(BET_T2W.out.versions) // ** Strip the template from the meta field so we can combine it ** // ch_t2w_tpl = BET_T2W.out.image - | map{ _meta, image -> image } + .map{ _meta, image -> image } } + ch_template = ch_anat + .map{ meta, _anat -> meta } + .combine(params.use_template_t2w ? ch_t2w_tpl : ch_t1w_tpl) // ** Register the subject to the template space ** // - ch_registration = ch_anat - | combine(params.use_template_t2w ? ch_t2w_tpl : ch_t1w_tpl) - | map{ meta, anat, tpl -> tuple(meta, tpl, anat, []) } - - REGISTRATION_ANTS ( ch_registration ) - ch_versions = ch_versions.mix(REGISTRATION_ANTS.out.versions) + REGISTRATION( + ch_anat, + ch_template, + Channel.empty(), + Channel.empty(), + Channel.empty(), + Channel.empty() + ) + ch_versions = ch_versions.mix(REGISTRATION.out.versions) // ** Apply the transformation to all files ** // // ** The channel ch_nifti_files contains all the files that ** // @@ -148,35 +155,32 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** [ tuple(meta, [ file1, file2, ... ]) ] ** // // ** Need to unpack the files and apply the transformation to each one ** // ch_files_to_transform = ch_nifti_files - | join(REGISTRATION_ANTS.out.image) - | join(REGISTRATION_ANTS.out.warp) - | join(REGISTRATION_ANTS.out.affine) + .join(REGISTRATION.out.image_warped) + .join(REGISTRATION.out.image_transform) WARPIMAGES ( ch_files_to_transform ) ch_versions = ch_versions.mix(WARPIMAGES.out.versions) // ** Same process for the masks ** // ch_masks_to_transform = ch_mask_files - | join(REGISTRATION_ANTS.out.image) - | join(REGISTRATION_ANTS.out.warp) - | join(REGISTRATION_ANTS.out.affine) + .join(REGISTRATION.out.image_warped) + .join(REGISTRATION.out.image_transform) WARPMASK ( ch_masks_to_transform ) ch_versions = ch_versions.mix(WARPMASK.out.versions) // ** Same process for the labels ** // ch_labels_to_transform = ch_labels_files - | join(REGISTRATION_ANTS.out.image) - | join(REGISTRATION_ANTS.out.warp) - | join(REGISTRATION_ANTS.out.affine) + .join(REGISTRATION.out.image_warped) + .join(REGISTRATION.out.image_transform) WARPLABELS ( ch_labels_to_transform ) ch_versions = ch_versions.mix(WARPLABELS.out.versions) // ** Apply the transformation to the tractograms ** // ch_tractograms_to_transform = ch_trk_files - | join(REGISTRATION_ANTS.out.image) - | join(REGISTRATION_ANTS.out.inverse_warp) - | join(REGISTRATION_ANTS.out.affine) - | map{ meta, trk, image, warp, affine -> + .join(REGISTRATION.out.image_warped) + .join(REGISTRATION.out.tractogram_transform) + .map{ it[0..1] + it[2..-1].flatten() } + .map{ meta, trk, image, affine, warp -> tuple(meta, image, affine, trk, [], warp) } @@ -186,7 +190,7 @@ workflow OUTPUT_TEMPLATE_SPACE { emit: ch_t1w_tpl = ch_t1w_tpl // channel: [ tpl-T1w ] ch_t2w_tpl = ch_t2w_tpl // channel: [ tpl-T2w ] - ch_registered_anat = REGISTRATION_ANTS.out.image // channel: [ val(meta), [ image ] ] + ch_registered_anat = REGISTRATION.out.image_warped // channel: [ val(meta), [ image ] ] ch_warped_nifti_files = WARPIMAGES.out.warped_image // channel: [ val(meta), [ warped_image ] ] ch_warped_mask_files = WARPMASK.out.warped_image // channel: [ val(meta), [ warped_mask ] ] ch_warped_labels_files = WARPLABELS.out.warped_image // channel: [ val(meta), [ warped_labels ] ] diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap index 91e12a29..a6bd94b7 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap @@ -119,4 +119,4 @@ }, "timestamp": "2025-10-17T17:39:09.650176125" } -} \ No newline at end of file +} diff --git a/subworkflows/nf-neuro/registration/main.nf b/subworkflows/nf-neuro/registration/main.nf index e04e0b7f..57c1417e 100644 --- a/subworkflows/nf-neuro/registration/main.nf +++ b/subworkflows/nf-neuro/registration/main.nf @@ -45,14 +45,20 @@ workflow REGISTRATION { ch_versions = ch_versions.mix(REGISTRATION_EASYREG.out.versions.first()) // ** Set compulsory outputs ** // + affine = Channel.empty() + warp = REGISTRATION_EASYREG.out.fwd_field + inverse_affine = Channel.empty() + inverse_warp = REGISTRATION_EASYREG.out.bak_field image_warped = REGISTRATION_EASYREG.out.flo_reg - transfo_image = REGISTRATION_EASYREG.out.fwd_field - transfo_trk = REGISTRATION_EASYREG.out.bak_field - ref_warped = REGISTRATION_EASYREG.out.ref_reg + image_transform = REGISTRATION_EASYREG.out.fwd_field + inverse_image_transform = REGISTRATION_EASYREG.out.bak_field + tractogram_transform = REGISTRATION_EASYREG.out.bak_field + inverse_tractogram_transform = REGISTRATION_EASYREG.out.fwd_field // ** Set optional outputs. ** // // If segmentations are not provided as inputs, // easyreg will outputs synthseg segmentations + ref_warped = REGISTRATION_EASYREG.out.ref_reg out_segmentation = ch_segmentation.mix( REGISTRATION_EASYREG.out.flo_seg ) out_ref_segmentation = ch_ref_segmentation.mix( REGISTRATION_EASYREG.out.ref_seg ) } @@ -64,11 +70,22 @@ workflow REGISTRATION { REGISTRATION_SYNTHREGISTRATION ( ch_register ) ch_versions = ch_versions.mix(REGISTRATION_SYNTHREGISTRATION.out.versions.first()) - // ** Set outputs ** // + // ** Set compulsory outputs ** // + affine = REGISTRATION_SYNTHREGISTRATION.out.affine + warp = REGISTRATION_SYNTHREGISTRATION.out.warp + inverse_affine = Channel.empty() // FIXME : this transformation should be available + inverse_warp = Channel.empty() // FIXME : this transformation should be available + image_warped = REGISTRATION_SYNTHREGISTRATION.out.warped_image - transfo_image = REGISTRATION_SYNTHREGISTRATION.out.warp - .join(REGISTRATION_SYNTHREGISTRATION.out.affine) // FIXME : this is .lta, should be .mat, but we need a custom container for that - transfo_trk = Channel.empty() // FIXME : this transformation should be available + // FIXME : this is .lta, should be .mat, but we need a custom container for that + image_transform = REGISTRATION_SYNTHREGISTRATION.out.warp + .join(REGISTRATION_SYNTHREGISTRATION.out.affine) + inverse_image_transform = Channel.empty() // FIXME : this transformation should be available + tractogram_transform = Channel.empty() // FIXME : this transformation should be available + inverse_tractogram_transform = REGISTRATION_SYNTHREGISTRATION.out.warp + .join(REGISTRATION_SYNTHREGISTRATION.out.affine) + + // ** and optional outputs. ** // ref_warped = Channel.empty() out_segmentation = Channel.empty() out_ref_segmentation = Channel.empty() @@ -97,11 +114,16 @@ workflow REGISTRATION { ch_versions = ch_versions.mix(REGISTRATION_ANATTODWI.out.versions.first()) // ** Set compulsory outputs ** // + affine = REGISTRATION_ANATTODWI.out.affine + warp = REGISTRATION_ANATTODWI.out.warp + inverse_affine = REGISTRATION_ANATTODWI.out.inverse_affine + inverse_warp = REGISTRATION_ANATTODWI.out.inverse_warp + image_warped = REGISTRATION_ANATTODWI.out.t1_warped - transfo_image = REGISTRATION_ANATTODWI.out.warp - .join(REGISTRATION_ANATTODWI.out.affine) - transfo_trk = REGISTRATION_ANATTODWI.out.affine - .join(REGISTRATION_ANATTODWI.out.inverse_warp) + image_transform = REGISTRATION_ANATTODWI.out.image_transform + inverse_image_transform = REGISTRATION_ANATTODWI.out.inverse_image_transform + tractogram_transform = REGISTRATION_ANATTODWI.out.tractogram_transform + inverse_tractogram_transform = REGISTRATION_ANATTODWI.out.inverse_tractogram_transform // ** Registration using ANTS SYN SCRIPTS ** // // Registration using antsRegistrationSyN.sh or antsRegistrationSyNQuick.sh, has @@ -118,26 +140,44 @@ workflow REGISTRATION { ch_versions = ch_versions.mix(REGISTRATION_ANTS.out.versions.first()) // ** Set compulsory outputs ** // - image_warped = image_warped.mix(REGISTRATION_ANTS.out.image) - transfo_image = REGISTRATION_ANTS.out.warp - .join(REGISTRATION_ANTS.out.affine) - .mix(transfo_image) - transfo_trk = REGISTRATION_ANTS.out.inverse_affine - .join(REGISTRATION_ANTS.out.inverse_warp) - .mix(transfo_trk) - - // **et optional outputs **// + affine = affine.mix(REGISTRATION_ANTS.out.affine) + warp = warp.mix(REGISTRATION_ANTS.out.warp) + inverse_affine = inverse_affine.mix(REGISTRATION_ANTS.out.inverse_affine) + inverse_warp = inverse_warp.mix(REGISTRATION_ANTS.out.inverse_warp) + + image_warped = image_warped + .mix(REGISTRATION_ANTS.out.image) + image_transform = image_transform + .mix(REGISTRATION_ANTS.out.image_transform) + inverse_image_transform = inverse_image_transform + .mix(REGISTRATION_ANTS.out.inverse_image_transform) + tractogram_transform = tractogram_transform + .mix(REGISTRATION_ANTS.out.tractogram_transform) + inverse_tractogram_transform = inverse_tractogram_transform + .mix(REGISTRATION_ANTS.out.inverse_tractogram_transform) + + // **and optional outputs **// ref_warped = Channel.empty() out_segmentation = Channel.empty() out_ref_segmentation = Channel.empty() } emit: - image_warped = image_warped // channel: [ val(meta), image ] ] - ref_warped = ref_warped // channel: [ val(meta), ref ] - transfo_image = transfo_image // channel: [ val(meta), [ warp ], [ ] ] - transfo_trk = transfo_trk // channel: [ val(meta), [ ], [ inverse-warp ] ] - segmentation = out_segmentation // channel: [ val(meta), segmentation ] - ref_segmentation = out_ref_segmentation // channel: [ val(meta), ref-segmentation ] - versions = ch_versions // channel: [ versions.yml ] + image_warped = image_warped // channel: [ val(meta), image ] + ref_warped = ref_warped // channel: [ val(meta), ref ] + // Individual transforms + affine = affine // channel: [ val(meta), ] + warp = warp // channel: [ val(meta), ] + inverse_affine = inverse_affine // channel: [ val(meta), ] + inverse_warp = inverse_warp // channel: [ val(meta), ] + // Combined transforms + image_transform = image_transform // channel: [ val(meta), [ , ] ] + inverse_image_transform = inverse_image_transform // channel: [ val(meta), [ , ] ] + tractogram_transform = tractogram_transform // channel: [ val(meta), [ , ] ] + inverse_tractogram_transform = inverse_tractogram_transform // channel: [ val(meta), [ , ] ] + // Segmentations + segmentation = out_segmentation // channel: [ val(meta), segmentation ] + ref_segmentation = out_ref_segmentation // channel: [ val(meta), ref-segmentation ] + + versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test b/subworkflows/nf-neuro/registration/tests/main.nf.test index 30b6f1d1..062ec1ec 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test @@ -78,7 +78,7 @@ nextflow_workflow { [(channel.key): ["versions"].contains(channel.key) ? channel.value : channel.value.collect{ subject -> - [ subject[0] ] + subject[1..-1].collect{ entry -> entry ? file(entry).name : "" } + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } } ] } ).match() }, @@ -134,7 +134,7 @@ nextflow_workflow { [(channel.key): ["versions"].contains(channel.key) ? channel.value : channel.value.collect{ subject -> - [ subject[0] ] + subject[1..-1].collect{ entry -> entry ? file(entry).name : "" } + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } } ] } ).match() }, @@ -192,7 +192,7 @@ nextflow_workflow { [(channel.key): ["versions"].contains(channel.key) ? channel.value : channel.value.collect{ subject -> - [ subject[0] ] + subject[1..-1].collect{ entry -> entry ? file(entry).name : "" } + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } } ] } ).match() } @@ -240,14 +240,14 @@ nextflow_workflow { [(channel.key): ["versions"].contains(channel.key) ? channel.value : channel.value.collect{ subject -> - [ subject[0] ] + subject[1..-1].collect{ entry -> entry ? file(entry).name : "" } + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } } ] } ).match() }, { assert workflow.out .findAll{ channel -> !channel.key.isInteger() } .every{ channel -> ["ref_warped", - "transfo_trk", + "tractogram_transform", "segmentation", "ref_segmentation"].contains(channel.key) ? channel.value.size() == 0 diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index b42e26eb..738c7127 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -2,6 +2,15 @@ "registration - synthregistration": { "content": [ { + "image_transform": [ + [ + { + "id": "test" + }, + "test__deform_warp.nii.gz", + "test__affine_warp.lta" + ] + ], "image_warped": [ [ { @@ -10,7 +19,7 @@ "test__output_warped.nii.gz" ] ], - "transfo_image": [ + "inverse_tractogram_transform": [ [ { "id": "test" @@ -28,11 +37,19 @@ "nf-test": "0.9.0", "nextflow": "25.04.6" }, - "timestamp": "2025-07-04T21:00:00.502234107" + "timestamp": "2025-07-18T01:59:59.744051543" }, "registration - easyreg": { "content": [ { + "image_transform": [ + [ + { + "id": "test" + }, + "test_forward_field.nii.gz" + ] + ], "image_warped": [ [ { @@ -41,39 +58,47 @@ "test_floating_registered.nii.gz" ] ], - "ref_segmentation": [ + "inverse_image_transform": [ [ { "id": "test" }, - "test_reference_segmentation.nii.gz" + "test_backward_field.nii.gz" ] ], - "ref_warped": [ + "inverse_tractogram_transform": [ [ { "id": "test" }, - "test_reference_registered.nii.gz" + "test_forward_field.nii.gz" ] ], - "segmentation": [ + "ref_segmentation": [ [ { "id": "test" }, - "test_floating_segmentation.nii.gz" + "test_reference_segmentation.nii.gz" ] ], - "transfo_image": [ + "ref_warped": [ [ { "id": "test" }, - "test_forward_field.nii.gz" + "test_reference_registered.nii.gz" + ] + ], + "segmentation": [ + [ + { + "id": "test" + }, + "test_floating_segmentation.nii.gz" ] ], - "transfo_trk": [ + "tractogram_transform": [ [ { "id": "test" @@ -95,6 +120,15 @@ "registration - antsRegistration": { "content": [ { + "image_transform": [ + [ + { + "id": "test" + }, + "test__output0ForwardWarp.nii.gz", + "test__output1ForwardAffine.mat" + ] + ], "image_warped": [ [ { @@ -103,22 +137,31 @@ "test__t1_warped.nii.gz" ] ], - "transfo_image": [ + "inverse_image_transform": [ + [ + { + "id": "test" + }, + "test__output0BackwardAffine.mat", + "test__output1BackwardWarp.nii.gz" + ] + ], + "inverse_tractogram_transform": [ [ { "id": "test" }, - "test__output1Warp.nii.gz", - "test__output0GenericAffine.mat" + "test__output0ForwardWarp.nii.gz", + "test__output1ForwardAffine.mat" ] ], - "transfo_trk": [ + "tractogram_transform": [ [ { "id": "test" }, - "test__output0GenericAffine.mat", - "test__output1InverseWarp.nii.gz" + "test__output0BackwardAffine.mat", + "test__output1BackwardWarp.nii.gz" ] ], "versions": [ @@ -135,6 +178,15 @@ "registration - SyNQuick": { "content": [ { + "image_transform": [ + [ + { + "id": "test" + }, + "test__output0ForwardWarp.nii.gz", + "test__output1ForwardAffine.mat" + ] + ], "image_warped": [ [ { @@ -143,22 +195,31 @@ "test__t1_warped.nii.gz" ] ], - "transfo_image": [ + "inverse_image_transform": [ + [ + { + "id": "test" + }, + "test__output0BackwardAffine.mat", + "test__output1BackwardWarp.nii.gz" + ] + ], + "inverse_tractogram_transform": [ [ { "id": "test" }, - "test__output1Warp.nii.gz", - "test__output0GenericAffine.mat" + "test__output0ForwardWarp.nii.gz", + "test__output1ForwardAffine.mat" ] ], - "transfo_trk": [ + "tractogram_transform": [ [ { "id": "test" }, - "test__output1InverseAffine.mat", - "test__output0InverseWarp.nii.gz" + "test__output0BackwardAffine.mat", + "test__output1BackwardWarp.nii.gz" ] ], "versions": [ diff --git a/subworkflows/nf-neuro/tractoflow/main.nf b/subworkflows/nf-neuro/tractoflow/main.nf index ca9ed917..09694894 100644 --- a/subworkflows/nf-neuro/tractoflow/main.nf +++ b/subworkflows/nf-neuro/tractoflow/main.nf @@ -1,18 +1,18 @@ // PREPROCESSING -include { PREPROC_DWI } from '../preproc_dwi/main' -include { PREPROC_T1 } from '../preproc_t1/main' -include { REGISTRATION as T1_REGISTRATION } from '../registration/main' -include { REGISTRATION_ANTSAPPLYTRANSFORMS as TRANSFORM_WMPARC } from '../../../modules/nf-neuro/registration/antsapplytransforms/main' -include { REGISTRATION_ANTSAPPLYTRANSFORMS as TRANSFORM_APARC_ASEG } from '../../../modules/nf-neuro/registration/antsapplytransforms/main' -include { REGISTRATION_ANTSAPPLYTRANSFORMS as TRANSFORM_LESION_MASK } from '../../../modules/nf-neuro/registration/antsapplytransforms/main' -include { ANATOMICAL_SEGMENTATION } from '../anatomical_segmentation/main' +include { PREPROC_DWI } from '../preproc_dwi/main' +include { PREPROC_T1 } from '../preproc_t1/main' +include { REGISTRATION as T1_REGISTRATION } from '../registration/main' +include { REGISTRATION_ANTSAPPLYTRANSFORMS as TRANSFORM_WMPARC } from '../../../modules/nf-neuro/registration/antsapplytransforms/main' +include { REGISTRATION_ANTSAPPLYTRANSFORMS as TRANSFORM_APARC_ASEG } from '../../../modules/nf-neuro/registration/antsapplytransforms/main' +include { REGISTRATION_ANTSAPPLYTRANSFORMS as TRANSFORM_LESION_MASK } from '../../../modules/nf-neuro/registration/antsapplytransforms/main' +include { ANATOMICAL_SEGMENTATION } from '../anatomical_segmentation/main' // RECONSTRUCTION -include { RECONST_FRF } from '../../../modules/nf-neuro/reconst/frf/main' -include { RECONST_MEANFRF } from '../../../modules/nf-neuro/reconst/meanfrf/main' -include { RECONST_DTIMETRICS } from '../../../modules/nf-neuro/reconst/dtimetrics/main' -include { RECONST_FODF } from '../../../modules/nf-neuro/reconst/fodf/main' +include { RECONST_FRF } from '../../../modules/nf-neuro/reconst/frf/main' +include { RECONST_MEANFRF } from '../../../modules/nf-neuro/reconst/meanfrf/main' +include { RECONST_DTIMETRICS } from '../../../modules/nf-neuro/reconst/dtimetrics/main' +include { RECONST_FODF } from '../../../modules/nf-neuro/reconst/fodf/main' // TRACKING include { TRACKING_PFTTRACKING } from '../../../modules/nf-neuro/tracking/pfttracking/main' @@ -110,7 +110,7 @@ workflow TRACTOFLOW { TRANSFORM_WMPARC( ch_wmparc .join(PREPROC_DWI.out.b0) - .join(T1_REGISTRATION.out.transfo_image) + .join(T1_REGISTRATION.out.image_transform) ) ch_versions = ch_versions.mix(TRANSFORM_WMPARC.out.versions.first()) @@ -120,7 +120,7 @@ workflow TRACTOFLOW { TRANSFORM_APARC_ASEG( ch_aparc_aseg .join(PREPROC_DWI.out.b0) - .join(T1_REGISTRATION.out.transfo_image) + .join(T1_REGISTRATION.out.image_transform) ) ch_versions = ch_versions.mix(TRANSFORM_APARC_ASEG.out.versions.first()) @@ -129,7 +129,7 @@ workflow TRACTOFLOW { TRANSFORM_LESION_MASK( ch_lesion_mask .join(PREPROC_DWI.out.b0) - .join(T1_REGISTRATION.out.transfo_image) + .join(T1_REGISTRATION.out.image_transform) ) ch_versions = ch_versions.mix(TRANSFORM_LESION_MASK.out.versions.first()) @@ -269,8 +269,8 @@ workflow TRACTOFLOW { wmparc = TRANSFORM_WMPARC.out.warped_image // REGISTRATION - anatomical_to_diffusion = T1_REGISTRATION.out.transfo_image - diffusion_to_anatomical = T1_REGISTRATION.out.transfo_trk + anatomical_to_diffusion = T1_REGISTRATION.out.image_transform + diffusion_to_anatomical = T1_REGISTRATION.out.inverse_image_transform // IN ANATOMICAL SPACE t1_native = PREPROC_T1.out.t1_final diff --git a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test index 06f4c7c4..63c22e6a 100644 --- a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test +++ b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test @@ -99,7 +99,7 @@ nextflow_workflow { [(channel.key): ["versions"].contains(channel.key) ? channel.value : channel.value.collect{ subject -> - [ subject[0] ] + subject[1..-1].collect{ entry -> entry ? file(entry).name : "" } + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } } ] } ).match() } diff --git a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap index bca3e2e6..4b37a05e 100644 --- a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap @@ -31,8 +31,8 @@ { "id": "test" }, - "test__output1Warp.nii.gz", - "test__output0GenericAffine.mat" + "test__output0ForwardWarp.nii.gz", + "test__output1ForwardAffine.mat" ] ], "csf_fodf": [ @@ -64,8 +64,8 @@ { "id": "test" }, - "test__output0GenericAffine.mat", - "test__output1InverseWarp.nii.gz" + "test__output0BackwardAffine.mat", + "test__output1BackwardWarp.nii.gz" ] ], "dti_ad": [ @@ -195,9 +195,7 @@ { "id": "test" }, - "test__frf.txt", - "", - "" + "test__frf.txt" ], [ { From 57f60db930ff2f870b0a2feb99b243d353baed7d Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Sun, 20 Jul 2025 18:50:36 +0000 Subject: [PATCH 05/37] realign all modules interfaces. update meta --- .../nf-neuro/registration/anattodwi/main.nf | 64 +++---- .../nf-neuro/registration/anattodwi/meta.yml | 54 ++++-- modules/nf-neuro/registration/ants/main.nf | 77 ++++---- modules/nf-neuro/registration/ants/meta.yml | 42 ++--- modules/nf-neuro/registration/convert/main.nf | 23 +-- .../nf-neuro/registration/convert/meta.yml | 5 + modules/nf-neuro/registration/easyreg/main.nf | 62 +++---- .../nf-neuro/registration/easyreg/meta.yml | 106 +++++------ .../registration/easyreg/tests/main.nf.test | 22 ++- .../easyreg/tests/main.nf.test.snap | 22 +-- .../registration/synthregistration/main.nf | 125 ++++++++++--- .../registration/synthregistration/meta.yml | 164 ++++++++++++++++-- .../synthregistration/tests/main.nf.test | 13 +- .../synthregistration/tests/main.nf.test.snap | 61 +++++-- .../synthregistration/tests/nextflow.config | 3 +- 15 files changed, 560 insertions(+), 283 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index 803efb5c..0c1cd345 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -5,20 +5,20 @@ process REGISTRATION_ANATTODWI { container "scilus/scilus:2.2.0" input: - tuple val(meta), path(fixedreference), path(movinganat), path(metric) + tuple val(meta), path(fixed_reference), path(moving_anat), path(metric) output: - tuple val(meta), path("*_warped.nii.gz") , emit: anat_warped - tuple val(meta), path("*__output1ForwardAffine.mat") , emit: affine - tuple val(meta), path("*__output0ForwardWarp.nii.gz") , emit: warp - tuple val(meta), path("*__output1BackwardWarp.nii.gz") , emit: inverse_warp - tuple val(meta), path("*__output0BackwardAffine.mat") , emit: inverse_affine - tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform - tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform - tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform - tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform - tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*_warped.nii.gz") , emit: anat_warped + tuple val(meta), path("*__forward1_affine.mat") , emit: affine + tuple val(meta), path("*__forward0_warp.nii.gz") , emit: warp + tuple val(meta), path("*__backward1_warp.nii.gz") , emit: inverse_warp + tuple val(meta), path("*__backward0_affine.mat") , emit: inverse_affine + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform + tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -34,35 +34,35 @@ process REGISTRATION_ANATTODWI { export ANTS_RANDOM_SEED=1234 antsRegistration --dimensionality 3 --float 0\ - --output [output,outputWarped.nii.gz,outputInverseWarped.nii.gz]\ + --output [trans,warped.nii.gz]\ --interpolation Linear --use-histogram-matching 0\ --winsorize-image-intensities [0.005,0.995]\ - --initial-moving-transform [$fixedreference,$movinganat,1]\ + --initial-moving-transform [$fixed_reference,$moving_anat,1]\ --transform Rigid['0.2']\ - --metric MI[$fixedreference,$movinganat,1,32,Regular,0.25]\ + --metric MI[$fixed_reference,$moving_anat,1,32,Regular,0.25]\ --convergence [500x250x125x50,1e-6,10] --shrink-factors 8x4x2x1\ --smoothing-sigmas 3x2x1x0\ --transform Affine['0.2']\ - --metric MI[$fixedreference,$movinganat,1,32,Regular,0.25]\ + --metric MI[$fixed_reference,$moving_anat,1,32,Regular,0.25]\ --convergence [500x250x125x50,1e-6,10] --shrink-factors 8x4x2x1\ --smoothing-sigmas 3x2x1x0\ --transform SyN[0.1,3,0]\ - --metric MI[$fixedreference,$movinganat,1,32]\ - --metric CC[$metric,$movinganat,1,4]\ + --metric MI[$fixed_reference,$moving_anat,1,32]\ + --metric CC[$metric,$moving_anat,1,4]\ --convergence [50x25x10,1e-6,10] --shrink-factors 4x2x1\ --smoothing-sigmas 3x2x1 - moving_id=\$(basename $movinganat .nii.gz) + moving_id=\$(basename $moving_anat .nii.gz) moving_id=\${moving_id#${meta.id}__*} - mv outputWarped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz - mv output0GenericAffine.mat ${prefix}__output1ForwardAffine.mat - mv output1Warp.nii.gz ${prefix}__output0ForwardWarp.nii.gz - mv output1InverseWarp.nii.gz ${prefix}__output1BackwardWarp.nii.gz + mv warped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz + mv trans0GenericAffine.mat ${prefix}__forward1_affine.mat + mv trans1Warp.nii.gz ${prefix}__forward0_warp.nii.gz + mv trans1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz - antsApplyTransforms -d 3 -i $movinganat -r $fixedreference \ - -o Linear[${prefix}__output0BackwardAffine.mat] \ - -t [${prefix}__output1ForwardAffine.mat,1] + antsApplyTransforms -d 3 -i $moving_anat -r $fixed_reference \ + -o Linear[${prefix}__backward0_affine.mat] \ + -t [${prefix}__forward1_affine.mat,1] ### ** QC ** ### if $run_qc; @@ -80,7 +80,7 @@ process REGISTRATION_ANATTODWI { viz_params="--display_slice_number --display_lr --size 256 256" # Get fixed ID, moving ID already computed - fixed_id=\$(basename $fixedreference .nii.gz) + fixed_id=\$(basename $fixed_reference .nii.gz) fixed_id=\${fixed_id#${meta.id}__*} # Iterate over images. @@ -144,14 +144,14 @@ process REGISTRATION_ANATTODWI { scil_viz_volume_screenshot -h convert -h - moving_id=\$(basename $movinganat .nii.gz) + moving_id=\$(basename $moving_anat .nii.gz) moving_id=\${moving_id#${meta.id}__*} touch ${prefix}__\${moving_id}_warped.nii.gz - touch ${prefix}__output1ForwardAffine.mat - touch ${prefix}__output0ForwardWarp.nii.gz - touch ${prefix}__output1BackwardWarp.nii.gz - touch ${prefix}__output0BackwardAffine.mat + touch ${prefix}__forward1_affine.mat + touch ${prefix}__forward0_warp.nii.gz + touch ${prefix}__backward1_warp.nii.gz + touch ${prefix}__backward0_affine.mat touch ${prefix}__registration_anattodwi_mqc.gif cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index c28150be..05c5dc18 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -30,29 +30,31 @@ args: type: boolean description: "Run quality control for the registration process" default: false - input: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - fixedreference: + - fixed_reference: type: file description: Nifti image file - fixed DWI reference (usually b0) pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - movinganat: + - moving_anat: type: file description: Nifti image file - moving anat to register (usually T1w) pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - metric: type: file description: Nifti image file - additional fixed metric (usually FA) pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format output: @@ -62,10 +64,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz}": + - "*_warped.{nii,nii.gz}": type: file description: Anatomical image warped to DWI space - pattern: "*.{nii,nii.gz}" + pattern: "*_warped.{nii,nii.gz}" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format affine: @@ -74,10 +76,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output1ForwardAffine.mat": + - "*__forward1_affine.mat": type: file description: Affine transformation matrix file. - pattern: "*__output1ForwardAffine.mat" + pattern: "*__forward1_affine.mat" ontologies: [] warp: - - meta: @@ -85,10 +87,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output0ForwardWarp.nii.gz": + - "*__forward0_warp.nii.gz": type: file description: Deformation field file. - pattern: "*__output0ForwardWarp.nii.gz" + pattern: "*__forward0_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format inverse_warp: @@ -97,10 +99,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output1BackwardWarp.nii.gz": + - "*__backward1_warp.nii.gz": type: file description: Inverse deformation field file. - pattern: "*__output1BackwardWarp.nii.gz" + pattern: "*__backward1_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format inverse_affine: @@ -109,10 +111,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output0BackwardAffine.mat": + - "*__backward0_affine.mat": type: file description: Inverse affine transformation matrix file. - pattern: "*__output0BackwardAffine.mat" + pattern: "*__backward0_affine.mat" ontologies: [] image_transform: - - meta: @@ -120,12 +122,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz,mat}": + - "*__forward*.{nii,nii.gz,mat}": type: list description: | Tuple, Transformation files to warp images in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. - pattern: "*.{nii,nii.gz,mat}" + pattern: "*__forward*.{nii,nii.gz,mat}" ontologies: [] inverse_image_transform: - - meta: @@ -133,12 +135,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz,mat}": + - "*__backward*.{nii,nii.gz,mat}": type: list description: | Tuple, Transformation files to warp images in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii,nii.gz,mat}" ontologies: [] tractogram_transform: - - meta: @@ -146,12 +148,25 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz,mat}": + - "*__backward*.{nii,nii.gz,mat}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii,nii.gz,mat}" + ontologies: [] + inverse_tractogram_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__forward*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + pattern: "*__forward*.{nii,nii.gz,mat}" ontologies: [] mqc: - - meta: @@ -176,3 +191,4 @@ output: authors: - "@medde" + - "@AlexVCaron" diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index 661d319f..d72389a3 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -6,20 +6,20 @@ process REGISTRATION_ANTS { container "scilus/scilus:2.2.0" input: - tuple val(meta), path(fixedimage), path(movingimage), path(mask) //** optional, input = [] **// + tuple val(meta), path(fixed_image), path(moving_image), path(mask) //** optional, input = [] **// output: - tuple val(meta), path("*_warped.nii.gz") , emit: image - tuple val(meta), path("*__output1ForwardAffine.mat") , emit: affine - tuple val(meta), path("*__output0ForwardWarp.nii.gz") , emit: warp, optional: true - tuple val(meta), path("*__output1BackwardWarp.nii.gz") , emit: inverse_warp, optional: true - tuple val(meta), path("*__output0BackwardAffine.mat") , emit: inverse_affine - tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform - tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform - tuple val(meta), path("*__output*Backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform - tuple val(meta), path("*__output*Forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform - tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*_warped.nii.gz") , emit: image_warped + tuple val(meta), path("*__forward1_affine.mat") , emit: affine, optional: true + tuple val(meta), path("*__forward0_warp.nii.gz") , emit: warp, optional: true + tuple val(meta), path("*__backward1_warp.nii.gz") , emit: inverse_warp, optional: true + tuple val(meta), path("*__backward0_affine.mat") , emit: inverse_affine, optional: true + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform + tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -37,7 +37,7 @@ process REGISTRATION_ANTS { args += " -n $task.cpus" if ( mask ) args += " -x $mask" - if ( task.ext.initial_transform ) args += " -i [$fixedimage,$movingimage,${initialization_types[task.ext.initial_transform]}]" + if ( task.ext.initial_transform ) args += " -i [$fixed_image,$moving_image,${initialization_types[task.ext.initial_transform]}]" if ( task.ext.histogram_bins ) args += " -r $task.ext.histogram_bins" if ( task.ext.spline_distance ) args += " -s $task.ext.spline_distance" if ( task.ext.gradient_step ) args += " -g $task.ext.gradient_step" @@ -51,26 +51,33 @@ process REGISTRATION_ANTS { export OMP_NUM_THREADS=1 export OPENBLAS_NUM_THREADS=1 - $ants $dimension -f $fixedimage -m $movingimage -o output -t $transform $args $seed + $ants $dimension -f $fixed_image -m $moving_image -o output -t $transform $args $seed - mv outputWarped.nii.gz ${prefix}__warped.nii.gz - mv output0GenericAffine.mat ${prefix}__output1ForwardAffine.mat + moving_id=\$(basename $moving_image .nii.gz) + moving_id=\${moving_id#${meta.id}__*} + + mv outputWarped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz + + if [ $transform != "bo" ] && [ $transform != "so" ]; + then + mv output0GenericAffine.mat ${prefix}__forward1_affine.mat + fi if [ $transform != "t" ] && [ $transform != "r" ] && [ $transform != "a" ]; then - mv output1InverseWarp.nii.gz ${prefix}__output1BackwardWarp.nii.gz - mv output1Warp.nii.gz ${prefix}__output0ForwardWarp.nii.gz + mv output1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz + mv output1Warp.nii.gz ${prefix}__forward0_warp.nii.gz fi - antsApplyTransforms -d 3 -i $fixedimage -r $movingimage \ - -o Linear[${prefix}__output0BackwardAffine.mat] \ - -t [${prefix}__output1ForwardAffine.mat,1] + antsApplyTransforms -d 3 -i $fixed_image -r $moving_image \ + -o Linear[${prefix}__backward0_affine.mat] \ + -t [${prefix}__forward1_affine.mat,1] ### ** QC ** ### if $run_qc; then - mv $fixedimage fixedimage.nii.gz - extract_dim=\$(mrinfo fixedimage.nii.gz -size) + mv $fixed_image fixed_image.nii.gz + extract_dim=\$(mrinfo fixed_image.nii.gz -size) read sagittal_dim coronal_dim axial_dim <<< "\${extract_dim}" # Get the middle slice @@ -78,10 +85,14 @@ process REGISTRATION_ANTS { axial_dim=\$((\$axial_dim / 2)) sagittal_dim=\$((\$sagittal_dim / 2)) + # Get fixed ID, moving ID already computed + fixed_id=\$(basename $fixed_image .nii.gz) + fixed_id=\${fixed_id#${meta.id}__*} + # Set viz params. viz_params="--display_slice_number --display_lr --size 256 256" # Iterate over images. - for image in fixedimage warped; + for image in fixed_image warped; do mrconvert *\${image}.nii.gz *\${image}_viz.nii.gz -stride -1,2,3 scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_coronal.png \ @@ -90,11 +101,11 @@ process REGISTRATION_ANTS { --slices \$sagittal_dim --axis sagittal \$viz_params scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_axial.png \ --slices \$axial_dim --axis axial \$viz_params - if [ \$image != fixedimage ]; + if [ \$image != fixed_image ]; then - title="T1 Warped" + title="Warped \${moving_id^^}" else - title="fixedimage" + title="Reference \${fixed_id^^}" fi convert +append \${image}_coronal*.png \${image}_axial*.png \ \${image}_sagittal*.png \${image}_mosaic.png @@ -105,7 +116,7 @@ process REGISTRATION_ANTS { done # Create GIF. convert -delay 10 -loop 0 -morph 10 \ - warped_mosaic.png fixedimage_mosaic.png warped_mosaic.png \ + warped_mosaic.png fixed_image_mosaic.png warped_mosaic.png \ ${prefix}_${suffix_qc}_registration_ants_mqc.gif # Clean up. rm *_mosaic.png @@ -122,6 +133,7 @@ process REGISTRATION_ANTS { stub: def prefix = task.ext.prefix ?: "${meta.id}" + def suffix_qc = task.ext.suffix_qc ?: "" """ set +e @@ -138,10 +150,11 @@ process REGISTRATION_ANTS { scil_viz_volume_screenshot -h touch ${prefix}__t1_warped.nii.gz - touch ${prefix}__output1ForwardAffine.mat - touch ${prefix}__output0ForwardWarp.nii.gz - touch ${prefix}__output1BackwardWarp.nii.gz - touch ${prefix}__output0BackwardAffine.mat + touch ${prefix}__forward1_affine.mat + touch ${prefix}__forward0_warp.nii.gz + touch ${prefix}__backward1_warp.nii.gz + touch ${prefix}__backward0_affine.mat + touch ${prefix}_${suffix_qc}_registration_ants_mqc.gif cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-neuro/registration/ants/meta.yml b/modules/nf-neuro/registration/ants/meta.yml index 544f0747..30bbcd1e 100644 --- a/modules/nf-neuro/registration/ants/meta.yml +++ b/modules/nf-neuro/registration/ants/meta.yml @@ -122,32 +122,34 @@ args: description: "Random seed for reproducibility." default: 1234 input: - # Only when we have meta - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - fixedimage: + - fixed_image: type: file description: Fixed image(s) or source image(s) or reference image(s) pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - movingimage: + - moving_image: type: file description: Moving image(s) or target image(s) pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - mask: type: file description: Mask(s) for the fixed image space pattern: "*.{nii,nii.gz}" + mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format output: - image: + image_warped: - - meta: type: map description: | @@ -165,10 +167,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output1ForwardAffine.mat": + - "*__forward1_affine.mat": type: file description: Affine transformation from moving to fixed - pattern: "*__output1ForwardAffine.mat" + pattern: "*__forward1_affine.mat" ontologies: [] warp: - - meta: @@ -176,10 +178,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output0ForwardWarp.nii.gz": + - "*__forward0_warp.nii.gz": type: file description: Nifti volume containing warp field from moving to fixed - pattern: "*__output0ForwardWarp.nii.gz" + pattern: "*__forward0_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format inverse_warp: @@ -188,10 +190,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output1BackwardWarp.nii.gz": + - "*__backward1_warp.nii.gz": type: file description: Nifti volume containing warp field from fixed to moving - pattern: "*__output1BackwardWarp.nii.gz" + pattern: "*__backward1_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format inverse_affine: @@ -200,10 +202,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output0BackwardAffine.mat": + - "*__backward0_affine.mat": type: file description: Affine transformation from fixed to moving - pattern: "*__output0BackwardAffine.mat" + pattern: "*__backward0_affine.mat" ontologies: [] image_transform: - - meta: @@ -211,12 +213,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz,mat}": + - "*__forward*.{nii,nii.gz,mat}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. - pattern: "*.{nii,nii.gz,mat}" + pattern: "*__forward*.{nii,nii.gz,mat}" ontologies: [] inverse_image_transform: - - meta: @@ -224,12 +226,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz,mat}": + - "*__backward*.{nii,nii.gz,mat}": type: list description: | Tuple, Inverse transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii,nii.gz,mat}" ontologies: [] tractogram_transform: - - meta: @@ -237,12 +239,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz,mat}": + - "*__backward*.{nii,nii.gz,mat}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii,nii.gz,mat}" ontologies: [] inverse_tractogram_transform: - - meta: @@ -250,12 +252,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii,nii.gz,mat}": + - "*__forward*.{nii,nii.gz,mat}": type: list description: | Tuple, Inverse transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*.{nii,nii.gz,mat}" + pattern: "*__forward*.{nii,nii.gz,mat}" ontologies: [] mqc: - - meta: diff --git a/modules/nf-neuro/registration/convert/main.nf b/modules/nf-neuro/registration/convert/main.nf index 3c9af61e..60757e8c 100644 --- a/modules/nf-neuro/registration/convert/main.nf +++ b/modules/nf-neuro/registration/convert/main.nf @@ -9,8 +9,8 @@ process REGISTRATION_CONVERT { tuple val(meta), path(deform), path(affine), path(source), path(target), path(fs_license) output: - tuple val(meta), path("*out_warp.{nii,nii.gz,mgz,m3z}") , emit: deform_transform - tuple val(meta), path("*out_affine.{txt,lta,mat,dat}") , emit: affine_transform, optional: true + tuple val(meta), path("*out_warp.{nii,nii.gz,mgz,m3z}") , emit: deform_transform, optional: true + tuple val(meta), path("*out_affine.{txt,lta,mat,dat}") , emit: affine_transform, optional: true path "versions.yml" , emit: versions when: @@ -55,16 +55,19 @@ process REGISTRATION_CONVERT { lta_convert ${invert} ${source_geometry_affine} ${target_geometry_affine} ${in_format_affine} ${out_format_affine} ${prefix}__out_affine.\${ext_affine} fi - declare -A deform_dictionnary=( ["--outm3z"]="m3z" \ - ["--outfsl"]="nii.gz" \ - ["--outlps"]="nii.gz" \ - ["--outitk"]="nii.gz" \ - ["--outras"]="nii.gz" \ - ["--outvox"]="mgz" ) + if [[ -f "$affine" ]]; + then + declare -A deform_dictionnary=( ["--outm3z"]="m3z" \ + ["--outfsl"]="nii.gz" \ + ["--outlps"]="nii.gz" \ + ["--outitk"]="nii.gz" \ + ["--outras"]="nii.gz" \ + ["--outvox"]="mgz" ) - ext_deform=\${deform_dictionnary[${out_format_deform}]} + ext_deform=\${deform_dictionnary[${out_format_deform}]} - mri_warp_convert ${source_geometry_deform} ${downsample} ${in_format_deform} ${out_format_deform} ${prefix}__out_warp.\${ext_deform} + mri_warp_convert ${source_geometry_deform} ${downsample} ${in_format_deform} ${out_format_deform} ${prefix}__out_warp.\${ext_deform} + fi rm \$FREESURFER_HOME/license.txt diff --git a/modules/nf-neuro/registration/convert/meta.yml b/modules/nf-neuro/registration/convert/meta.yml index 95cbb1ac..93d6666a 100644 --- a/modules/nf-neuro/registration/convert/meta.yml +++ b/modules/nf-neuro/registration/convert/meta.yml @@ -26,6 +26,7 @@ input: description: Deform transform to convert. Default usage expects Freesurfer .mgz format from mri_synthmorph pattern: "*.{nii,nii.gz,mgz,m3z}" + mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - affine: @@ -33,12 +34,14 @@ input: description: Affine transform to convert. Default usage expects Freesurfer .lta format from mri_synthmorph pattern: "*.{lta,txt,xfm,dat}" + mandatory: false ontologies: [] - source: type: file description: Moving Nifti volume used for registration. Defines source image geometry pattern: "*.{nii,nii.gz}" + mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - target: @@ -46,6 +49,7 @@ input: description: Fixed Nifti volume used for registration. Defines target image geometry. (optional) pattern: "*.{nii,nii.gz}" + mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - fs_license: @@ -55,6 +59,7 @@ input: Optional. If you have already set your license as prescribed by Freesurfer (copied to a .license file in your $FREESURFER_HOME), this is not required. pattern: "*.txt" + mandatory: true ontologies: [] output: deform_transform: diff --git a/modules/nf-neuro/registration/easyreg/main.nf b/modules/nf-neuro/registration/easyreg/main.nf index e81c2095..57c01870 100644 --- a/modules/nf-neuro/registration/easyreg/main.nf +++ b/modules/nf-neuro/registration/easyreg/main.nf @@ -2,58 +2,42 @@ process REGISTRATION_EASYREG { tag "$meta.id" - label 'process_single' label 'process_high' container "freesurfer/freesurfer:7.4.1" input: - tuple val(meta), path(reference), path(floating), path(ref_segmentation), path(flo_segmentation) + tuple val(meta), path(fixed_image), path(moving_image), path(fixed_segmentation), path(moving_segmentation) output: - tuple val(meta), path("*_reference_registered.nii.gz") , emit: ref_reg - tuple val(meta), path("*_floating_registered.nii.gz") , emit: flo_reg - tuple val(meta), path("*_reference_segmentation.nii.gz") , emit: ref_seg, optional: true - tuple val(meta), path("*_floating_segmentation.nii.gz") , emit: flo_seg, optional: true - tuple val(meta), path("*_forward_field.nii.gz") , emit: fwd_field, optional: true - tuple val(meta), path("*_backward_field.nii.gz") , emit: bak_field, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*_warped.nii.gz") , emit: image_warped + tuple val(meta), path("*_warped_reference.nii.gz") , emit: fixed_warped + tuple val(meta), path("*_forward0_warp.nii.gz") , emit: warp + tuple val(meta), path("*_backward0_warp.nii.gz") , emit: inverse_warp + tuple val(meta), path("*_warped_segmentation.nii.gz") , emit: segmentation_warped, optional: true + tuple val(meta), path("*_warped_reference_segmentation.nii.gz") , emit: fixed_segmentation_warped, optional: true + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when script: def prefix = task.ext.prefix ?: "${meta.id}" - def field = task.ext.field ? "--fwd_field ${prefix}_forward_field.nii.gz --bak_field ${prefix}_backward_field.nii.gz " : "" - def threads = task.ext.threads ? "--threads " + task.ext.threads : "" + def field = task.ext.field ? "--fwd_field ${prefix}_forward0_warp.nii.gz --bak_field ${prefix}_backward0_warp.nii.gz " : "" def affine = task.ext.affine ? "--affine_only " : "" - + fixed_segmentation = "--ref_seg ${fixed_segmentation ?: "${prefix}__warped_segmentation.nii.gz" }" + moving_segmentation = "--flo_seg ${moving_segmentation ?: "${prefix}__warped_reference_segmentation.nii.gz" }" """ export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1 export OMP_NUM_THREADS=1 export OPENBLAS_NUM_THREADS=1 - if [[ -f "$ref_segmentation" ]]; - then - reference_segmentation=$ref_segmentation - else - reference_segmentation="${prefix}_reference_segmentation.nii.gz" - fi - - if [[ -f "$flo_segmentation" ]]; - then - floating_segmentation=$flo_segmentation - else - floating_segmentation="${prefix}_floating_segmentation.nii.gz" - fi - - mri_easyreg \ - --ref $reference --flo $floating \ - --ref_seg \${reference_segmentation} \ - --flo_seg \${floating_segmentation} \ - --flo_reg ${prefix}_floating_registered.nii.gz \ - --ref_reg ${prefix}_reference_registered.nii.gz \ - $field $threads $affine + mri_easyreg --ref $fixed_image \ + --flo $moving_image \ + --flo_reg ${prefix}_warped.nii.gz \ + --ref_reg ${prefix}_warped_reference.nii.gz \ + $fixed_segmentation $moving_segmentation \ + --threads $task.cpus $field $affine cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -67,12 +51,12 @@ process REGISTRATION_EASYREG { """ mri_easyreg -h - touch ${prefix}_reference_registered.nii.gz - touch ${prefix}_floating_registered.nii.gz - touch ${prefix}_reference_segmentation.nii.gz - touch ${prefix}_floating_segmentation.nii.gz - touch ${prefix}_forward_field.nii.gz - touch ${prefix}_backward_field.nii.gz + touch ${prefix}_warped.nii.gz + touch ${prefix}_warped_reference.nii.gz + touch ${prefix}_warped_segmentation.nii.gz + touch ${prefix}_warped_reference_segmentation.nii.gz + touch ${prefix}_forward0_warp.nii.gz + touch ${prefix}_backward0_warp.nii.gz cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-neuro/registration/easyreg/meta.yml b/modules/nf-neuro/registration/easyreg/meta.yml index e47e6f6d..ccfe70f7 100644 --- a/modules/nf-neuro/registration/easyreg/meta.yml +++ b/modules/nf-neuro/registration/easyreg/meta.yml @@ -21,118 +21,117 @@ input: description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - reference: + - fixed_image: type: file - description: the reference image in .nii(.gz) or .mgz format (note that, since - the method is symmetric, the choice of reference vs floating is arbitrary). + description: Reference image in .nii(.gz) or .mgz format (note that, since the method is symmetric, the choice of reference vs floating is arbitrary). pattern: "*.{nii,nii.gz,mgz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - floating: + - moving_image: type: file - description: the floating image in .nii(.gz) or .mgz format. + description: Image to register in .nii(.gz) or .mgz format. pattern: "*.{nii,nii.gz,mgz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - ref_segmentation: + - fixed_segmentation: type: file - description: file with the SynthSeg v2 (non-robust) segmentation + parcellation - of the reference image. If it does not exist, EasyReg will create it. If it - already exists (e.g., from a previous EasyReg run), then EasyReg will read - it from disk (which is faster than segmenting). + description: | + File with the SynthSeg v2 (non-robust) segmentation + parcellation of the reference image. + If it does not exist, EasyReg will create it. pattern: "*.{nii,nii.gz}" + mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - flo_segmentation: + - moving_segmentation: type: file - description: file with the SynthSeg v2 (non-robust) segmentation + parcellation - of the floating image. If it does not exist, EasyReg will create it. If it - already exists (e.g., from a previous EasyReg run), then EasyReg will read - it from disk (which is faster than segmenting). + description: | + File with the SynthSeg v2 (non-robust) segmentation + parcellation of the floating image. + If it does not exist, EasyReg will create it. pattern: "*.{nii,nii.gz}" + mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format output: - ref_reg: + image_warped: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_reference_registered.nii.gz": + - "*_warped.nii.gz": type: file - description: this is the file where the deformed (registered) reference image - is written. - pattern: "*_reference_registered.nii.gz" + description: Image warped onto the reference. + pattern: "*_warped.nii.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - flo_reg: + - edam: http://edamontology.org/format_4001 # NIFTI format + fixed_warped: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_floating_registered.nii.gz": + - "*_warped_reference.nii.gz": type: file - description: this is the file where the deformed (registered) floating image - is written. - pattern: "*_floating_registered.nii.gz" + description: Reference warped. + pattern: "*_warped_reference.nii.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - ref_seg: + - edam: http://edamontology.org/format_4001 # NIFTI format + warp: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_reference_segmentation.nii.gz": + - "*_forward0_warp.nii.gz": type: file - description: file with the SynthSeg v2 (non-robust) segmentation + parcellation - of the reference image. Will produce image only if not passed as input. - pattern: "*_reference_segmentation.nii.gz" + description: Forward deformation field, composed of all registration stages (affine+deformation). + pattern: "*_forward0_warp.nii.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - flo_seg: + - edam: http://edamontology.org/format_4001 # NIFTI format + inverse_warp: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_floating_segmentation.nii.gz": + - "*_backward0_warp.nii.gz": type: file - description: file with the SynthSeg v2 (non-robust) segmentation + parcellation - of the floating image. Will produce image only if not passed as input. - pattern: "*_floating_segmentation.nii.gz" + description: Backward deformation field, composed of all registration stages (inv-deformation+inv-affine). + pattern: "*_backward0_warp.nii.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - fwd_field: + - edam: http://edamontology.org/format_4001 # NIFTI format + fixed_segmentation_warped: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_forward_field.nii.gz": + - "*_warped_segmentation_reference.nii.gz": type: file - description: this is the file where the forward deformation field is written. - The deformation includes both the affine and nonlinear components. Must - be a nifti (.nii/.nii.gz) or .mgz file; it is encoded as the real world - (RAS) coordinates of the target location for each voxel. - pattern: "*_forward_field.nii.gz" + description: | + SynthSeg v2 (non-robust) segmentation + parcellation on the reference image. + Will produce image only if not passed as input. + pattern: "*_warped_segmentation_reference.nii.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format - bak_field: + - edam: http://edamontology.org/format_4001 # NIFTI format + optional: true + segmentation_warped: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_backward_field.nii.gz": + - "*_warped_segmentation.nii.gz": type: file - description: this is the file where the backward deformation field is written. - It must also be a nifty or mgz file. - pattern: "*_backward_field.nii.gz" + description: | + SynthSeg v2 (non-robust) segmentation + parcellation on the warped image. + Will produce image only if not passed as input. + pattern: "*_warped_segmentation.nii.gz" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + - edam: http://edamontology.org/format_4001 # NIFTI format + optional: true versions: - versions.yml: type: file @@ -142,5 +141,6 @@ output: - edam: http://edamontology.org/format_3750 # YAML authors: - "@ThoumyreStanislas" + - "@AlexVCaron" maintainers: - "@ThoumyreStanislas" diff --git a/modules/nf-neuro/registration/easyreg/tests/main.nf.test b/modules/nf-neuro/registration/easyreg/tests/main.nf.test index 40f35f4f..4855a21d 100644 --- a/modules/nf-neuro/registration/easyreg/tests/main.nf.test +++ b/modules/nf-neuro/registration/easyreg/tests/main.nf.test @@ -44,13 +44,12 @@ nextflow_process { ch_b0 = ch_split_test_data.b0.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz"), - [], - [] + file("\${test_data_directory}/b0.nii.gz") ] } input[0] = ch_t1 .join(ch_b0) + .map{ meta, t1, b0 -> [meta, t1, b0, [], []] } """ } } @@ -58,12 +57,12 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - file(process.out.ref_seg.get(0).get(1)).name, - file(process.out.flo_seg.get(0).get(1)).name, - niftiMD5SUM(process.out.ref_reg.get(0).get(1), 6), - niftiMD5SUM(process.out.flo_reg.get(0).get(1), 6), - niftiMD5SUM(process.out.fwd_field.get(0).get(1), 6), - niftiMD5SUM(process.out.bak_field.get(0).get(1), 6), + file(process.out.fixed_segmentation_warped.get(0).get(1)).name, + file(process.out.segmentation_warped.get(0).get(1)).name, + niftiMD5SUM(process.out.fixed_warped.get(0).get(1), 6), + niftiMD5SUM(process.out.image_warped.get(0).get(1), 6), + niftiMD5SUM(process.out.warp.get(0).get(1), 6), + niftiMD5SUM(process.out.inverse_warp.get(0).get(1), 6), process.out.versions ).match() } ) @@ -90,13 +89,12 @@ nextflow_process { ch_b0 = ch_split_test_data.b0.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz"), - [], - [] + file("\${test_data_directory}/b0.nii.gz") ] } input[0] = ch_t1 .join(ch_b0) + .map{ meta, t1, b0 -> [meta, t1, b0, [], []] } """ } } diff --git a/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap b/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap index cb847b08..a40373e5 100644 --- a/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap @@ -1,21 +1,21 @@ { "registration - easyreg": { "content": [ - "test_reference_segmentation.nii.gz", - "test_floating_segmentation.nii.gz", - "test_reference_registered.nii.gz:md5:header,c5e41f89848f91c53a9a7be44970d4b1,data,1501221fe23cd62bfdafb33367cadf4d", - "test_floating_registered.nii.gz:md5:header,ec5893cd9ea024e630c4444bd914c331,data,d75ae3fc935cd5cc70ea6797a4c70775", - "test_forward_field.nii.gz:md5:header,0db0a80786ff39864cc17506ed1a0146,data,e4fa6c626729cbf236c34680e5c76df4", - "test_backward_field.nii.gz:md5:header,74c92ee4cd3c4abfecf3da6cdb1d4650,data,8f26afa5c3de21469466213498542486", + "test__warped_reference_segmentation.nii.gz", + "test__warped_segmentation.nii.gz", + "test_warped_reference.nii.gz:md5:header,c5e41f89848f91c53a9a7be44970d4b1,data,1501221fe23cd62bfdafb33367cadf4d", + "test_warped.nii.gz:md5:header,ec5893cd9ea024e630c4444bd914c331,data,d75ae3fc935cd5cc70ea6797a4c70775", + "test_forward0_warp.nii.gz:md5:header,0db0a80786ff39864cc17506ed1a0146,data,e4fa6c626729cbf236c34680e5c76df4", + "test_backward0_warp.nii.gz:md5:header,74c92ee4cd3c4abfecf3da6cdb1d4650,data,8f26afa5c3de21469466213498542486", [ "versions.yml:md5,4661210880c42a986923e8257f64c760" ] ], "meta": { - "nf-test": "0.9.0-rc1", - "nextflow": "24.04.4" + "nf-test": "0.9.0", + "nextflow": "25.04.6" }, - "timestamp": "2024-09-12T16:01:24.00559" + "timestamp": "2025-07-19T02:11:25.288399742" }, "registration - easyreg - stub-run": { "content": [ @@ -25,8 +25,8 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-05-30T18:56:08.423992682" + "timestamp": "2025-07-19T01:06:31.625578918" } } \ No newline at end of file diff --git a/modules/nf-neuro/registration/synthregistration/main.nf b/modules/nf-neuro/registration/synthregistration/main.nf index 87eb32c7..19b65029 100644 --- a/modules/nf-neuro/registration/synthregistration/main.nf +++ b/modules/nf-neuro/registration/synthregistration/main.nf @@ -4,17 +4,23 @@ process REGISTRATION_SYNTHREGISTRATION { container "freesurfer/synthmorph:4" containerOptions { - (workflow.containerEngine == 'docker') ? '--entrypoint "" --env PYTHONPATH="/freesurfer/env/lib/python3.11/site-packages"' : "--env PYTHONPATH='/freesurfer/env/lib/python3.11/site-packages'" + (workflow.containerEngine == 'docker') ? '--entrypoint ""' : "" } input: - tuple val(meta), path(moving), path(fixed) + tuple val(meta), path(fixed_image), path(moving_image) output: - tuple val(meta), path("*__output_warped.nii.gz") , emit: warped_image - tuple val(meta), path("*__deform_warp.nii.gz") , emit: warp - tuple val(meta), path("*__affine_warp.lta") , emit: affine - path "versions.yml" , emit: versions + tuple val(meta), path("*__warped.nii.gz") , emit: image_warped + tuple val(meta), path("*__forward1_affine.lta") , emit: affine, optional: true + tuple val(meta), path("*__forward0_warp.nii.gz") , emit: warp, optional: true + tuple val(meta), path("*__backward1_warp.nii.gz") , emit: inverse_warp, optional: true + tuple val(meta), path("*__backward0_affine.lta") , emit: inverse_affine, optional: true + tuple val(meta), path("*__forward*.{lta,nii.gz}") , emit: image_transform + tuple val(meta), path("*__backward*.{lta,nii.gz}") , emit: inverse_image_transform + tuple val(meta), path("*__backward*.{lta,nii.gz}") , emit: tractogram_transform + tuple val(meta), path("*__forward*.{lta,nii.gz}") , emit: inverse_tractogram_transform + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -22,25 +28,100 @@ process REGISTRATION_SYNTHREGISTRATION { script: def prefix = task.ext.prefix ?: "${meta.id}" - def affine = task.ext.affine ? "-m " + task.ext.affine : "-m affine" - def warp = task.ext.warp ? "-m " + task.ext.warp : "-m deform" - def header = task.ext.header ? "-H" : "" - def gpu = task.ext.gpu ? "-g" : "" - def lambda = task.ext.lambda ? "-r " + task.ext.lambda : "" - def steps = task.ext.steps ? "-n " + task.ext.steps : "" - def extent = task.ext.extent ? "-e " + task.ext.extent : "" - def weight = task.ext.weight ? "-w " + task.ext.weight : "" + def models = task.ext.models ?: ["affine", "deform"] + def weights = (task.ext.weight ?: [null] * models.size()).collect{ it ? "-w $it" : "none" }.join(" ") + def use_gpu = task.ext.use_gpu ? "-g" : "" + def regularization = "-r ${task.ext.regularization ?: 0.5}" + def steps = "-n ${task.ext.steps ?: 7 }" + def extent = "-e ${task.ext.extent ?: 256}" + def update_header = task.ext.disable_resampling ? "-H" : "" """ export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1 export OMP_NUM_THREADS=1 export OPENBLAS_NUM_THREADS=1 - mri_synthmorph -j $task.cpus ${affine} -t ${prefix}__affine_warp.lta $moving $fixed - mri_synthmorph -j $task.cpus ${warp} ${gpu} ${lambda} ${steps} ${extent} ${weight} -i ${prefix}__affine_warp.lta -t ${prefix}__deform_warp.nii.gz -o ${prefix}__output_warped.nii.gz $moving $fixed + export CUDA_VISIBLE_DEVICES="-1" + + echo "Available memory : ${task.memory}" + + moving=$moving_image + mv $fixed_image fixed.nii.gz + + declare -A extension=( ["affine"]="lta" \ + ["rigid"]="lta" \ + ["deform"]="nii.gz" \ + ["joint"]="nii.gz" ) + + weights=( $weights ) + + i=0 + skip=0 + j=${models.size()} + initializer="" + for model in ${models.join(" ")} + do + echo "Processing model: \$model" + # Post-incrementation ensure no error on last index = 0 + ((j--)) + + weight="" + if [ "\${weights[i + skip]}" != "none" ] + then + weight="-w \${weights[i + skip]}" + + if [ "\$model" = "joint" ] + then + # Pre-incrementation ensure no error on first index = 0 + ((++skip)) + if [ "\${weights[i + skip]}" = "none" ] + then + echo "Joint deformations need 2 weights, only 1 given" + exit 1 + else + weight="\$weight -w \${weights[i + skip]}" + fi + fi + fi + + args="" + if [ \$model = "joint" ] || [ \$model = "deform" ] + then + args="$regularization $steps" + else + args="$update_header" + fi + + if [ \$initializer ] + then + args="\$args -i \$initializer" + fi + + mri_synthmorph register \$moving fixed.nii.gz -v -m \$model \$weight \$args \ + -t ${prefix}__forward\${j}_\$model.\${extension[\$model]} \ + -o warped.nii.gz -j $task.cpus $extent $use_gpu + + if [ \$initializer ] + then + rm \$initializer + fi + + if [ \${extension[\$model]} = "lta" ] + then + initializer=${prefix}__forward\${j}_\$model.\${extension[\$model]} + else + moving=warped.nii.gz + fi + + # Pre-incrementation ensure no error on first index = 0 + ((++i)) + + done + + mv warped.nii.gz ${prefix}__warped.nii.gz cat <<-END_VERSIONS > versions.yml "${task.process}": - synthmoprh: 4 + synthmorph: 4 END_VERSIONS """ @@ -50,13 +131,15 @@ process REGISTRATION_SYNTHREGISTRATION { """ mri_synthmorph -h - touch ${prefix}__output_warped.nii.gz - touch ${prefix}__deform_warp.nii.gz - touch ${prefix}__affine_warp.lta + touch ${prefix}__warped.nii.gz + touch ${prefix}__forward1_affine.lta + touch ${prefix}__forward0_warp.nii.gz + touch ${prefix}__backward1_warp.nii.gz + touch ${prefix}__backward0_affine.lta cat <<-END_VERSIONS > versions.yml "${task.process}": - synthmoprh: 4 + synthmorph: 4 END_VERSIONS """ } diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthregistration/meta.yml index 67eae3b2..16bca14c 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthregistration/meta.yml @@ -21,57 +21,186 @@ tools: homepage: https://surfer.nmr.mgh.harvard.edu/ doi: 10.1016/j.neuroimage.2012.01.021 identifier: "" + - SynthMorph: + description: "Synthmorph registration method" + homepage: "https://martinos.org/malte/synthmorph/" + doi: 10.1109/TMI.2021.3116879 + identifier: "" +args: + - models: + type: list + description: List of transformation models to apply to the moving image in series. + default: "[\"affine\", \"deform\"]" + choices: + - rigid + - affine + - deform + - joint + - weights: + type: list + description: | + List of weights to apply to each model. Must supply one per model on none. + Use "none" to specify no weight for a given model. When using the "joint" + model, you must add 2 weights in the list for affine and warp. + default: "" + - use_gpu: + type: boolean + description: Use GPU to accelerate computations (must enable GPU support). + default: false + - regularization: + type: float + description: Regularizationto add to deformation steps. + default: 0.5 + - steps: + type: integer + description: Number of iteration for the optimisation of deformations. + default: 7 + - extent: + type: integer + description: Size of the deformation grid in voxels. + default: 256 + choices: + - 192 + - 256 + - disable_resampling: + type: boolean + description: Update image header instead of performing resampling of the output image. + default: false input: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - moving: + - fixed_image: type: file - description: Nifti volume moving for registration + description: Nifti volume fixed for registration pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format - - fixed: + - edam: http://edamontology.org/format_4001 + - moving_image: type: file - description: Nifti volume fixed for registration + description: Nifti volume moving for registration pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 output: - warped_image: + image_warped: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__output_warped.nii.gz": + - "*_warped.{nii,nii.gz}": type: file description: Warped image - pattern: "*__output_warped.nii.gz" + pattern: "*_warped.{nii,nii.gz}" ontologies: - - edam: http://edamontology.org/format_3989 # GZIP format + - edam: http://edamontology.org/format_4001 # NIFTI format + affine: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__forward1_affine.lta": + type: file + description: Affine transformation matrix file. + pattern: "*__forward1_affine.lta" + optional: true + ontologies: [] warp: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__deform_warp.nii.gz": + - "*__forward0_warp.nii.gz": + type: file + description: Deformation field file. + pattern: "*__forward0_warp.nii.gz" + optional: true + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format + inverse_warp: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__backward1_warp.nii.gz": + type: file + description: Inverse deformation field file. + pattern: "*__backward1_warp.nii.gz" + optional: true + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format + inverse_affine: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__backward0_affine.lta": + type: file + description: Inverse affine transformation matrix file. + pattern: "*__backward0_affine.lta" + optional: true + ontologies: [] + image_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__forward*.{nii,nii.gz,mat,lta}": type: list - description: Nifti volume containing warp field from moving to fixed - pattern: "*__deform_warp.nii.gz" - affine: + description: | + Tuple, Transformation files to warp images in the correct order + for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. + pattern: "*__forward*.{nii,nii.gz,mat,lta}" + ontologies: [] + inverse_image_transform: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__affine_warp.lta": + - "*__backward*.{nii,nii.gz,mat,lta}": type: list - description: Affine transformation from moving to fixed - pattern: "*__affine_warp.lta" + description: | + Tuple, Transformation files to warp images in the correct order for + REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*__backward*.{nii,nii.gz,mat,lta}" + ontologies: [] + tractogram_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__backward*.{nii,nii.gz,mat,lta}": + type: list + description: | + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*__backward*.{nii,nii.gz,mat,lta}" + ontologies: [] + inverse_tractogram_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__forward*.{nii,nii.gz,mat,lta}": + type: list + description: | + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + pattern: "*__forward*.{nii,nii.gz,mat,lta}" + ontologies: [] versions: - versions.yml: type: file @@ -81,3 +210,4 @@ output: - edam: http://edamontology.org/format_3750 # YAML authors: - "@anroy1" + - "@AlexVCaron" diff --git a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test index a880ed8c..5209aa36 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test +++ b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test @@ -45,10 +45,15 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - file(process.out.warped_image.get(0).get(1)).name, - file(process.out.warp.get(0).get(1)).name, - file(process.out.affine.get(0).get(1)).name, - process.out.versions + process.out + .findAll{ channel -> !channel.key.isInteger() && channel.value } + .collectEntries{ channel -> + [(channel.key): ["versions"].contains(channel.key) + ? channel.value + : channel.value.collect{ subject -> + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } + } ] + } ).match() } ) } diff --git a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap index 2bb83c4a..16f3d8cb 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap @@ -1,29 +1,66 @@ { "registration - synthregistration": { "content": [ - "test__output_warped.nii.gz", - "test__deform_warp.nii.gz", - "test__affine_warp.lta", - [ - "versions.yml:md5,6f946408922f25f1a8182d35615b6d7b" - ] + { + "affine": [ + [ + { + "id": "test", + "single_end": false + }, + "test__forward1_affine.lta" + ] + ], + "image_transform": [ + [ + { + "id": "test", + "single_end": false + }, + "test__forward0_deform.nii.gz", + "test__forward1_affine.lta" + ] + ], + "image_warped": [ + [ + { + "id": "test", + "single_end": false + }, + "test__warped.nii.gz" + ] + ], + "inverse_tractogram_transform": [ + [ + { + "id": "test", + "single_end": false + }, + "test__forward0_deform.nii.gz", + "test__forward1_affine.lta" + ] + ], + "versions": [ + "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" + ] + } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "24.04.3" + "nf-test": "0.9.0", + "nextflow": "25.04.6" }, - "timestamp": "2024-12-18T13:10:28.733204" + "timestamp": "2025-07-19T23:30:21.67250369" }, "registration - synthregistration - stub-run": { "content": [ [ - "versions.yml:md5,6f946408922f25f1a8182d35615b6d7b" + "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" ] ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.2" + "nextflow": "25.04.6" }, - "timestamp": "2025-05-30T18:56:18.76904087" + "timestamp": "2025-07-19T04:08:35.236332874" } } \ No newline at end of file diff --git a/modules/nf-neuro/registration/synthregistration/tests/nextflow.config b/modules/nf-neuro/registration/synthregistration/tests/nextflow.config index 20888b8f..b38ad2c3 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/nextflow.config +++ b/modules/nf-neuro/registration/synthregistration/tests/nextflow.config @@ -1,10 +1,11 @@ process { withName: "REGISTRATION_SYNTHREGISTRATION" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - memory = "32G" + memory = "26G" ext.affine = "affine" ext.warp = "deform" ext.lambda = 0.9 ext.steps = 9 + ext.extent = 192 } } From a2e7f0ec1194fceb012823610d38a131d23c2524 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Sun, 20 Jul 2025 18:51:08 +0000 Subject: [PATCH 06/37] realign registration subworkflow. update meta. fixes all around --- subworkflows/nf-neuro/registration/main.nf | 90 ++++----- subworkflows/nf-neuro/registration/meta.yml | 163 +++++++++++----- .../nf-neuro/registration/tests/main.nf.test | 6 +- .../registration/tests/main.nf.test.snap | 178 ++++++++++++++---- .../registration/tests/nextflow.config | 11 +- .../registration/tests/nextflow_ants.config | 11 ++ .../tests/nextflow_easyreg.config | 1 - .../tests/nextflow_synthregistration.config | 1 - 8 files changed, 311 insertions(+), 150 deletions(-) create mode 100644 subworkflows/nf-neuro/registration/tests/nextflow_ants.config diff --git a/subworkflows/nf-neuro/registration/main.nf b/subworkflows/nf-neuro/registration/main.nf index 57c1417e..2af3cb63 100644 --- a/subworkflows/nf-neuro/registration/main.nf +++ b/subworkflows/nf-neuro/registration/main.nf @@ -8,7 +8,7 @@ params.run_synthmorph = false workflow REGISTRATION { - // The subworkflow requires at least ch_image and ch_ref as inputs to + // The subworkflow requires at least ch_fixed_image and ch_moving_image as inputs to // properly perform the registration. Supplying a ch_metric will select // the REGISTRATION_ANATTODWI module meanwhile NOT supplying a ch_metric // will select the REGISTRATION_ANTS (SyN or SyNQuick) module. Alternatively, @@ -16,15 +16,13 @@ workflow REGISTRATION { // REGISTRATION_EASYREG or REGISTRATION_SYNTHMORPH take: - ch_image // channel: [ val(meta), image ] - ch_ref // channel: [ val(meta), reference ] - ch_metric // channel: [ val(meta), metric ], optional - ch_mask // channel: [ val(meta), mask ], optional - ch_segmentation // channel: [ val(meta), segmentation ], optional - ch_ref_segmentation // channel: [ val(meta), ref-segmentation ], optional - + ch_fixed_image // channel: [ val(meta), image ] + ch_moving_image // channel: [ val(meta), reference ] + ch_metric // channel: [ val(meta), metric ], optional + ch_fixed_mask // channel: [ val(meta), mask ], optional + ch_segmentation // channel: [ val(meta), segmentation ], optional + ch_moving_segmentation // channel: [ val(meta), segmentation ], optional main: - ch_versions = Channel.empty() if ( params.run_easyreg ) { @@ -35,9 +33,9 @@ workflow REGISTRATION { // - join [ meta, reference, image | null, ref-segmentation | null ] // - join [ meta, reference, image | null, ref-segmentation | null, segmentation | null ] // - map [ meta, reference, image | [], ref-segmentation | [], segmentation | [] ] - ch_register = ch_ref - .join(ch_image, remainder: true) - .join(ch_ref_segmentation, remainder: true) + ch_register = ch_moving_image + .join(ch_fixed_image, remainder: true) + .join(ch_moving_segmentation, remainder: true) .join(ch_segmentation, remainder: true) .map{ it[0..1] + [it[2] ?: [], it[3] ?: [], it[4] ?: []] } @@ -45,45 +43,41 @@ workflow REGISTRATION { ch_versions = ch_versions.mix(REGISTRATION_EASYREG.out.versions.first()) // ** Set compulsory outputs ** // + image_warped = REGISTRATION_EASYREG.out.image_warped affine = Channel.empty() - warp = REGISTRATION_EASYREG.out.fwd_field + warp = REGISTRATION_EASYREG.out.warp inverse_affine = Channel.empty() - inverse_warp = REGISTRATION_EASYREG.out.bak_field - image_warped = REGISTRATION_EASYREG.out.flo_reg - image_transform = REGISTRATION_EASYREG.out.fwd_field - inverse_image_transform = REGISTRATION_EASYREG.out.bak_field - tractogram_transform = REGISTRATION_EASYREG.out.bak_field - inverse_tractogram_transform = REGISTRATION_EASYREG.out.fwd_field + inverse_warp = REGISTRATION_EASYREG.out.inverse_warp + image_transform = REGISTRATION_EASYREG.out.warp + inverse_image_transform = REGISTRATION_EASYREG.out.inverse_warp + tractogram_transform = REGISTRATION_EASYREG.out.inverse_warp + inverse_tractogram_transform = REGISTRATION_EASYREG.out.warp // ** Set optional outputs. ** // // If segmentations are not provided as inputs, // easyreg will outputs synthseg segmentations - ref_warped = REGISTRATION_EASYREG.out.ref_reg - out_segmentation = ch_segmentation.mix( REGISTRATION_EASYREG.out.flo_seg ) - out_ref_segmentation = ch_ref_segmentation.mix( REGISTRATION_EASYREG.out.ref_seg ) + ref_warped = REGISTRATION_EASYREG.out.fixed_warped + out_segmentation = ch_segmentation.mix( REGISTRATION_EASYREG.out.segmentation_warped ) + out_ref_segmentation = ch_moving_segmentation.mix( REGISTRATION_EASYREG.out.fixed_segmentation_warped ) } else if ( params.run_synthmorph ) { // ** Registration using synthmorph ** // - ch_register = ch_image - .join(ch_ref) + ch_register = ch_fixed_image + .join(ch_moving_image) REGISTRATION_SYNTHREGISTRATION ( ch_register ) ch_versions = ch_versions.mix(REGISTRATION_SYNTHREGISTRATION.out.versions.first()) // ** Set compulsory outputs ** // + image_warped = REGISTRATION_SYNTHREGISTRATION.out.image_warped affine = REGISTRATION_SYNTHREGISTRATION.out.affine warp = REGISTRATION_SYNTHREGISTRATION.out.warp - inverse_affine = Channel.empty() // FIXME : this transformation should be available - inverse_warp = Channel.empty() // FIXME : this transformation should be available - - image_warped = REGISTRATION_SYNTHREGISTRATION.out.warped_image - // FIXME : this is .lta, should be .mat, but we need a custom container for that - image_transform = REGISTRATION_SYNTHREGISTRATION.out.warp - .join(REGISTRATION_SYNTHREGISTRATION.out.affine) - inverse_image_transform = Channel.empty() // FIXME : this transformation should be available - tractogram_transform = Channel.empty() // FIXME : this transformation should be available - inverse_tractogram_transform = REGISTRATION_SYNTHREGISTRATION.out.warp - .join(REGISTRATION_SYNTHREGISTRATION.out.affine) + inverse_affine = REGISTRATION_SYNTHREGISTRATION.out.inverse_affine + inverse_warp = REGISTRATION_SYNTHREGISTRATION.out.inverse_warp + image_transform = REGISTRATION_SYNTHREGISTRATION.out.image_transform + inverse_image_transform = REGISTRATION_SYNTHREGISTRATION.out.inverse_image_transform + tractogram_transform = REGISTRATION_SYNTHREGISTRATION.out.tractogram_transform + inverse_tractogram_transform = REGISTRATION_SYNTHREGISTRATION.out.inverse_tractogram_transform // ** and optional outputs. ** // ref_warped = Channel.empty() @@ -100,8 +94,8 @@ workflow REGISTRATION { // Branches : // - anat_to_dwi : has a metric at index 3 // - ants_syn : doesn't have a metric at index 3 ( [] or null ) - ch_register = ch_image - .join(ch_ref) + ch_register = ch_fixed_image + .join(ch_moving_image) .join(ch_metric, remainder: true) .map{ it[0..2] + [it[3] ?: []] } .branch{ @@ -114,12 +108,11 @@ workflow REGISTRATION { ch_versions = ch_versions.mix(REGISTRATION_ANATTODWI.out.versions.first()) // ** Set compulsory outputs ** // + image_warped = REGISTRATION_ANATTODWI.out.anat_warped affine = REGISTRATION_ANATTODWI.out.affine warp = REGISTRATION_ANATTODWI.out.warp inverse_affine = REGISTRATION_ANATTODWI.out.inverse_affine inverse_warp = REGISTRATION_ANATTODWI.out.inverse_warp - - image_warped = REGISTRATION_ANATTODWI.out.t1_warped image_transform = REGISTRATION_ANATTODWI.out.image_transform inverse_image_transform = REGISTRATION_ANATTODWI.out.inverse_image_transform tractogram_transform = REGISTRATION_ANATTODWI.out.tractogram_transform @@ -133,35 +126,28 @@ workflow REGISTRATION { // - join [ meta, image, metric | [], mask | null ] // - map [ meta, image, mask | [] ] ch_register = ch_register.ants_syn - .join(ch_mask, remainder: true) + .join(ch_fixed_mask, remainder: true) .map{ it[0..2] + [it[4] ?: []] } REGISTRATION_ANTS ( ch_register ) ch_versions = ch_versions.mix(REGISTRATION_ANTS.out.versions.first()) // ** Set compulsory outputs ** // + image_warped = image_warped.mix(REGISTRATION_ANTS.out.image_warped) affine = affine.mix(REGISTRATION_ANTS.out.affine) warp = warp.mix(REGISTRATION_ANTS.out.warp) inverse_affine = inverse_affine.mix(REGISTRATION_ANTS.out.inverse_affine) inverse_warp = inverse_warp.mix(REGISTRATION_ANTS.out.inverse_warp) - - image_warped = image_warped - .mix(REGISTRATION_ANTS.out.image) - image_transform = image_transform - .mix(REGISTRATION_ANTS.out.image_transform) - inverse_image_transform = inverse_image_transform - .mix(REGISTRATION_ANTS.out.inverse_image_transform) - tractogram_transform = tractogram_transform - .mix(REGISTRATION_ANTS.out.tractogram_transform) - inverse_tractogram_transform = inverse_tractogram_transform - .mix(REGISTRATION_ANTS.out.inverse_tractogram_transform) + image_transform = image_transform.mix(REGISTRATION_ANTS.out.image_transform) + inverse_image_transform = inverse_image_transform.mix(REGISTRATION_ANTS.out.inverse_image_transform) + tractogram_transform = tractogram_transform.mix(REGISTRATION_ANTS.out.tractogram_transform) + inverse_tractogram_transform = inverse_tractogram_transform.mix(REGISTRATION_ANTS.out.inverse_tractogram_transform) // **and optional outputs **// ref_warped = Channel.empty() out_segmentation = Channel.empty() out_ref_segmentation = Channel.empty() } - emit: image_warped = image_warped // channel: [ val(meta), image ] ref_warped = ref_warped // channel: [ val(meta), ref ] diff --git a/subworkflows/nf-neuro/registration/meta.yml b/subworkflows/nf-neuro/registration/meta.yml index 55e059e0..2b17c43c 100644 --- a/subworkflows/nf-neuro/registration/meta.yml +++ b/subworkflows/nf-neuro/registration/meta.yml @@ -2,16 +2,37 @@ name: "registration" description: | Subworkflow to perform registration between a moving and a fixed image (e.g. T1 -> DWI). It requires as input at least a moving (ch_image) and a reference (ch_ref) image to properly - perform registration. Three modes are available: - 1) if a metric file is supplied (ch_metric), the subworkflow will use the REGISTER_ANATTODWI - module calling AntsRegistration, with the metric as additional target. - 2) if NO metric file is supplied, the subworkflow will use the REGISTRATION_ANTS module calling - antsRegistrationSyN.sh or antsRegistrationSyNQuick.sh. - 3) alternatively, if an alternative model parameter is activated, the subworkflow will use the specified module - This subworkflow outputs transformation files that can be used with the ANTSAPPLYTRANSFORMS module - to warp any new image. Simply provide your moving image, reference image, and transformations files - to the module to register a new image in the current space. Similar steps can be used to register - bundles/tractograms using the BUNDLEREGISTRATION module. + perform registration. + + Output transformations curated for use with the REGISTRATION_ANTSAPPLYTRANSFORMS subworkflows + are available under the names image_transform and tractogram_transform, and their inverses. + + Registration suites: + - EasyReg (ML): params.run_easyreg = true + + module: REGISTRATION_EASYREG + + Run freesurfer EasyReg any-to-any modality registration. + + NOTE: Outputs a combined warp field only, no affine transformations are available. CANNOT BE LINKED WITH THE BUNDLE_SEG SUBWORKFLOW. + + - Synthmorph (ML): params.run_synthmorph = true + + module: REGISTRATION_SYNTHREGISTRATION + + Run SynthMorph any-to-any modality registration. By default, the algorithm is configured to + run a chain of affin+deformable transformations, making it suitable for use with most modules + and subworkflows like BUNDLE_SEG. + + NOTE: the output affine transformation file is in .lta format and needs to be converted to .mat to be used with ANTs using the REGISTRATION_CONVERT module. + + - ANTs (SyN+SyN Quick): params.run_easyreg = false && params.run_synthmorph = false + + module: REGISTRATION_ANTS or REGISTRATION_ANATTODWI + + Run ANTs registration using antsRegistrationSyN.sh (quick version also available). + + NOTE : Transformation to DWI space is available. To trigger it, supply a metric file (ch_metric) in DWI space (e.g. FA map) in addition to the moving (ch_image) and reference (ch_ref) images. keywords: - Registration - Transformation @@ -23,89 +44,128 @@ components: - registration/easyreg - registration/synthregistration input: - - ch_image: + - ch_fixed_image: type: file description: | - The input channel containing the moving image files. Typically your anatomical image to be - registered to dwi space. - Structure: [ val(meta), path(image) ] + The input channel containing the fixed image files. If performing + registration to DWI space, this is the reference image (e.g. b0 image). + Structure: [ val(meta), path(fixed_image) ] pattern: "*.{nii,nii.gz}" - - ch_ref: + mandatory: true + - ch_moving_image: type: file description: | - The input channel containing the fixed image files. Typically a reference image from the dwi - space (e.g. b0 image, etc.). - Structure: [ val(meta), path(ref) ] + Input channel containing the moving image files. If performing + registration to DWI space, this is the anatomical image to be registered. + Structure: [ val(meta), path(image) ] pattern: "*.{nii,nii.gz}" + mandatory: true - ch_metric: type: file description: | - The input channel containing the metric files. Supplying this channel will make the subworkflow - use the module REGISTER_ANATTODWI calling AntsRegistration using the moving, reference and metric - image. For a T1 -> DWI registration, this is typically a FA map. + FOR USE WITH REGISTRATION TO DWI SPACE ONLY. The input channel containing the metric files, typically a FA map. Structure: [ val(meta), path(metric) ] pattern: "*.{nii,nii.gz}" - - ch_mask: + mandatory: false + - ch_fixed_mask: type: file description: | - The input channel containing the mask files. Supplying this channel only affect the subworkflow - if the ch_metric is NOT supplied. This channel is only being used if the module called is - REGISTRATION_ANTS, see the description section above for more details. + FOR USE WITH ANTS SYN REGISTRATION ONLY. The input channel containing the mask file in fixed image space. Structure: [ val(meta), path(mask) ] pattern: "*.{nii,nii.gz}" + mandatory: false - ch_segmentation: type: file description: | - The input channel containing the the SynthSeg v2 (non-robust) segmentation + parcellation of the moving (floating in Easyreg naming convention) image. - If it does not exist, Easyreg will create it. If it already exists (e.g., from a previous EasyReg run), - then EasyReg will read it from disk (which is faster than segmenting). + FOR USE WITH SYNTHMORPH REGISTRATION ONLY. The input channel containing the SynthSeg v2 (non-robust) + segmentation + parcellation in fixed image space (reference in Easyreg naming convention) image. pattern: "*.{nii,nii.gz}" - - ch_ref_segmentation: + mandatory: false + - ch_moving_segmentation: type: file description: | - The input channel containing the SynthSeg v2 (non-robust) segmentation + parcellation of the fixed (reference in Easyreg naming convention) image. - If it does not exist, Easyreg will create it. If it already exists (e.g., from a previous EasyReg run), - then EasyReg will read it from disk (which is faster than segmenting). + FOR USE WITH SYNTHMORPH REGISTRATION ONLY. The input channel containing the SynthSeg v2 (non-robust) + segmentation + parcellation in moving image space (floating in Easyreg naming convention) image. pattern: "*.{nii,nii.gz}" + mandatory: false output: - image_warped: type: file description: | - Channel containing warped moving images. Typically, this would be the warped T1 in DWI space. + Channel containing images warped in fixed space. Structure: [ val(meta), path(image) ] pattern: "*.{nii,nii.gz}" - - transfo_image: + - ref_warped: type: file description: | - Channel containing the image transformation files. This channel contains the necessary transformation - files (warp and affine) to perform the anatomical -> dwi space registration. Those files could be - used in the future to bring anatomical labels into DWI space for connectomics. - Structure: [ val(meta), [ path(warp), path(affine) ] ] - pattern: "*.{nii,nii.gz,mat}" - - transfo_trk: + ONLY PROVIDED BY REGISTRATION_EASYREG. Channel containing the reference image warped in moving space. + Structure: [ val(meta), path(image) ] + pattern: "*.{nii,nii.gz}" + optional: true + - affine: type: file description: | - Channel containing the tractogram transformation files. This channel contains the necessary transformation - files (inverseAffine, inverseWarp) to perform the dwi -> anatomical space registration. Those files could - be used to register tractograms or bundle in the subject's anatomical space. - Structure: [ val(meta), [ path(inverseAffine), path(inverseWarp) ] - pattern: "*.{nii,nii.gz,mat}" - - ref_warped: + Channel containing the affine forward transformation matrix file. + Structure: [ val(meta), path(affine) ] + pattern: "*__forward*.{lta,mat}" + optional: true + - warp: type: file description: | - Channel containing warped reference image. Typically, this would be the warped DWI in T1 space. - Structure: [ val(meta), path(ref) ] - pattern: "*.{nii,nii.gz}" + Channel containing the forward deformation field file. + Structure: [ val(meta), path(warp) ] + pattern: "*__forward*.{nii,nii.gz}" + - inverse_warp: + type: file + description: | + Channel containing the inverse deformation field file. + Structure: [ val(meta), path(inverse_warp) ] + pattern: "*__backward*.{nii,nii.gz}" + - inverse_affine: + type: file + description: | + Channel containing the inverse affine transformation matrix file. + Structure: [ val(meta), path(inverse_affine) ] + pattern: "*__backward*.{lta,mat}" + optional: true + - image_transform: + type: list + description: | + Tuple, Transformation files to warp images in the correct order + for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. + pattern: "*__forward*.{nii,nii.gz,mat,lta}" + - inverse_image_transform: + type: list + description: | + Tuple, Transformation files to warp images in the correct order for + REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*__backward*.{nii,nii.gz,mat,lta}" + - tractogram_transform: + type: list + description: | + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*__backward*.{nii,nii.gz,mat,lta}" + - inverse_tractogram_transform: + type: list + description: | + Tuple, Transformation files to warp tractograms in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + pattern: "*__forward*.{nii,nii.gz,mat,lta}" - out_segmentation: type: file description: | - Channel containing the file with the SynthSeg v2 (non-robust) segmentation + parcellation of the moving (floating in Easyreg naming convention) image. + ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) + segmentation + parcellation in moving space (floating in Easyreg naming convention). pattern: "*.{nii,nii.gz}" + optional: true - out_ref_segmentation: type: file description: | - Channel containing the file with the SynthSeg v2 (non-robust) segmentation + parcellation of the fixed (reference in Easyreg naming convention) image. + ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) + segmentation + parcellation in fixed space (reference in Easyreg naming convention). pattern: "*.{nii,nii.gz}" + optional: true - versions: type: file description: | @@ -114,3 +174,4 @@ output: pattern: "versions.yml" authors: - "@gagnonanthony" + - "@AlexVCaron" diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test b/subworkflows/nf-neuro/registration/tests/main.nf.test index 062ec1ec..e3e9268d 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_workflow { name "Test Subworkflow REGISTRATION" script "../main.nf" workflow "REGISTRATION" + config "./nextflow.config" tag "subworkflows" tag "subworkflows_nfneuro" @@ -33,7 +34,7 @@ nextflow_workflow { } test("registration - antsRegistration") { - config "./nextflow.config" + config "./nextflow_ants.config" when { workflow { """ @@ -96,7 +97,7 @@ nextflow_workflow { } test("registration - SyNQuick") { - config "./nextflow.config" + config "./nextflow_ants.config" when { workflow { """ @@ -247,7 +248,6 @@ nextflow_workflow { { assert workflow.out .findAll{ channel -> !channel.key.isInteger() } .every{ channel -> ["ref_warped", - "tractogram_transform", "segmentation", "ref_segmentation"].contains(channel.key) ? channel.value.size() == 0 diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 738c7127..5a7ef622 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -2,13 +2,21 @@ "registration - synthregistration": { "content": [ { + "affine": [ + [ + { + "id": "test" + }, + "test__forward1_affine.lta" + ] + ], "image_transform": [ [ { "id": "test" }, - "test__deform_warp.nii.gz", - "test__affine_warp.lta" + "test__forward0_warp.nii.gz", + "test__forward1_affine.lta" ] ], "image_warped": [ @@ -16,7 +24,24 @@ { "id": "test" }, - "test__output_warped.nii.gz" + "test__warped.nii.gz" + ] + ], + "inverse_affine": [ + [ + { + "id": "test" + }, + "test__backward0_affine.lta" + ] + ], + "inverse_image_transform": [ + [ + { + "id": "test" + }, + "test__backward0_affine.lta", + "test__backward1_warp.nii.gz" ] ], "inverse_tractogram_transform": [ @@ -24,12 +49,37 @@ { "id": "test" }, - "test__deform_warp.nii.gz", - "test__affine_warp.lta" + "test__forward0_warp.nii.gz", + "test__forward1_affine.lta" + ] + ], + "inverse_warp": [ + [ + { + "id": "test" + }, + "test__backward1_warp.nii.gz" + ] + ], + "tractogram_transform": [ + [ + { + "id": "test" + }, + "test__backward0_affine.lta", + "test__backward1_warp.nii.gz" ] ], "versions": [ - "versions.yml:md5,8a5fc770044eef3575fe68a3f7792976" + "versions.yml:md5,f0fa799dd0d27d1974ea409d9c9e5da7" + ], + "warp": [ + [ + { + "id": "test" + }, + "test__forward0_warp.nii.gz" + ] ] } ], @@ -37,7 +87,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.6" }, - "timestamp": "2025-07-18T01:59:59.744051543" + "timestamp": "2025-07-20T03:29:30.180373035" }, "registration - easyreg": { "content": [ @@ -47,7 +97,7 @@ { "id": "test" }, - "test_forward_field.nii.gz" + "test_forward0_warp.nii.gz" ] ], "image_warped": [ @@ -55,7 +105,7 @@ { "id": "test" }, - "test_floating_registered.nii.gz" + "test_warped.nii.gz" ] ], "inverse_image_transform": [ @@ -63,7 +113,7 @@ { "id": "test" }, - "test_backward_field.nii.gz" + "test_backward0_warp.nii.gz" ] ], "inverse_tractogram_transform": [ @@ -71,7 +121,15 @@ { "id": "test" }, - "test_forward_field.nii.gz" + "test_forward0_warp.nii.gz" + ] + ], + "inverse_warp": [ + [ + { + "id": "test" + }, + "test_backward0_warp.nii.gz" ] ], "ref_segmentation": [ @@ -79,7 +137,7 @@ { "id": "test" }, - "test_reference_segmentation.nii.gz" + "test_warped_reference_segmentation.nii.gz" ] ], "ref_warped": [ @@ -87,7 +145,7 @@ { "id": "test" }, - "test_reference_registered.nii.gz" + "test_warped_reference.nii.gz" ] ], "segmentation": [ @@ -95,7 +153,7 @@ { "id": "test" }, - "test_floating_segmentation.nii.gz" + "test_warped_segmentation.nii.gz" ] ], "tractogram_transform": [ @@ -103,11 +161,19 @@ { "id": "test" }, - "test_backward_field.nii.gz" + "test_backward0_warp.nii.gz" ] ], "versions": [ "versions.yml:md5,3f38c911476c605480c02e484fcf6e9f" + ], + "warp": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz" + ] ] } ], @@ -120,13 +186,21 @@ "registration - antsRegistration": { "content": [ { + "affine": [ + [ + { + "id": "test" + }, + "test__forward1_affine.mat" + ] + ], "image_transform": [ [ { "id": "test" }, - "test__output0ForwardWarp.nii.gz", - "test__output1ForwardAffine.mat" + "test__forward0_warp.nii.gz", + "test__forward1_affine.mat" ] ], "image_warped": [ @@ -134,7 +208,15 @@ { "id": "test" }, - "test__t1_warped.nii.gz" + "test__b0_warped.nii.gz" + ] + ], + "inverse_affine": [ + [ + { + "id": "test" + }, + "test__backward0_affine.mat" ] ], "inverse_image_transform": [ @@ -142,8 +224,8 @@ { "id": "test" }, - "test__output0BackwardAffine.mat", - "test__output1BackwardWarp.nii.gz" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], "inverse_tractogram_transform": [ @@ -151,8 +233,16 @@ { "id": "test" }, - "test__output0ForwardWarp.nii.gz", - "test__output1ForwardAffine.mat" + "test__forward0_warp.nii.gz", + "test__forward1_affine.mat" + ] + ], + "inverse_warp": [ + [ + { + "id": "test" + }, + "test__backward1_warp.nii.gz" ] ], "tractogram_transform": [ @@ -160,8 +250,8 @@ { "id": "test" }, - "test__output0BackwardAffine.mat", - "test__output1BackwardWarp.nii.gz" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], "versions": [ @@ -178,13 +268,21 @@ "registration - SyNQuick": { "content": [ { + "affine": [ + [ + { + "id": "test" + }, + "test__forward1_affine.mat" + ] + ], "image_transform": [ [ { "id": "test" }, - "test__output0ForwardWarp.nii.gz", - "test__output1ForwardAffine.mat" + "test__forward0_warp.nii.gz", + "test__forward1_affine.mat" ] ], "image_warped": [ @@ -195,13 +293,21 @@ "test__t1_warped.nii.gz" ] ], + "inverse_affine": [ + [ + { + "id": "test" + }, + "test__backward0_affine.mat" + ] + ], "inverse_image_transform": [ [ { "id": "test" }, - "test__output0BackwardAffine.mat", - "test__output1BackwardWarp.nii.gz" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], "inverse_tractogram_transform": [ @@ -209,8 +315,16 @@ { "id": "test" }, - "test__output0ForwardWarp.nii.gz", - "test__output1ForwardAffine.mat" + "test__forward0_warp.nii.gz", + "test__forward1_affine.mat" + ] + ], + "inverse_warp": [ + [ + { + "id": "test" + }, + "test__backward1_warp.nii.gz" ] ], "tractogram_transform": [ @@ -218,8 +332,8 @@ { "id": "test" }, - "test__output0BackwardAffine.mat", - "test__output1BackwardWarp.nii.gz" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], "versions": [ diff --git a/subworkflows/nf-neuro/registration/tests/nextflow.config b/subworkflows/nf-neuro/registration/tests/nextflow.config index 8f8c6c2e..0293c16f 100644 --- a/subworkflows/nf-neuro/registration/tests/nextflow.config +++ b/subworkflows/nf-neuro/registration/tests/nextflow.config @@ -1,12 +1,3 @@ process { - withName: "REGISTRATION_ANATTODWI" { - ext.cpus = 1 - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - } - withName: "REGISTRATION_ANTS" { - ext.quick = true - ext.threads = 1 - ext.random_seed = 44 - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - } + publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } } diff --git a/subworkflows/nf-neuro/registration/tests/nextflow_ants.config b/subworkflows/nf-neuro/registration/tests/nextflow_ants.config new file mode 100644 index 00000000..df0bf888 --- /dev/null +++ b/subworkflows/nf-neuro/registration/tests/nextflow_ants.config @@ -0,0 +1,11 @@ +process { + withName: "REGISTRATION_ANATTODWI" { + ext.cpus = 1 + } + + withName: "REGISTRATION_ANTS" { + ext.quick = true + ext.threads = 1 + ext.random_seed = 44 + } +} diff --git a/subworkflows/nf-neuro/registration/tests/nextflow_easyreg.config b/subworkflows/nf-neuro/registration/tests/nextflow_easyreg.config index a4c0bd3f..694f85d8 100644 --- a/subworkflows/nf-neuro/registration/tests/nextflow_easyreg.config +++ b/subworkflows/nf-neuro/registration/tests/nextflow_easyreg.config @@ -1,6 +1,5 @@ process { withName: "REGISTRATION_EASYREG" { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.field = true } } diff --git a/subworkflows/nf-neuro/registration/tests/nextflow_synthregistration.config b/subworkflows/nf-neuro/registration/tests/nextflow_synthregistration.config index b0a76764..ec7d0967 100644 --- a/subworkflows/nf-neuro/registration/tests/nextflow_synthregistration.config +++ b/subworkflows/nf-neuro/registration/tests/nextflow_synthregistration.config @@ -1,6 +1,5 @@ process { withName: "REGISTRATION_SYNTHREGISTRATION" { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.affine = "affine" ext.warp = "deform" ext.lambda = 0.9 From 4cac67290af5a64214ba1d53ee7e148827c38b41 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Mon, 28 Jul 2025 16:05:17 +0000 Subject: [PATCH 07/37] organize and fix registration modules configuration. Handle edge cases. Add output conversion to synthmorph in subworkflow (now all outputs are ITK based) --- modules/nf-neuro/registration/convert/main.nf | 87 ++++--- .../nf-neuro/registration/convert/meta.yml | 112 ++++++--- .../registration/convert/tests/main.nf.test | 222 +++++------------- .../convert/tests/main.nf.test.snap | 178 +++----------- ...extflow_default.config => nextflow.config} | 0 .../convert/tests/nextflow_antsfs.config | 9 - .../convert/tests/nextflow_fsants.config | 9 - .../convert/tests/nextflow_fslants.config | 9 - .../convert/tests/nextflow_fslfs.config | 9 - modules/nf-neuro/registration/easyreg/main.nf | 11 +- .../nf-neuro/registration/easyreg/meta.yml | 5 + .../easyreg/tests/nextflow.config | 7 +- .../registration/synthregistration/main.nf | 29 ++- .../registration/synthregistration/meta.yml | 2 +- .../synthregistration/tests/main.nf.test.snap | 55 ++++- .../synthregistration/tests/nextflow.config | 7 +- subworkflows/nf-neuro/registration/main.nf | 177 +++++++++----- subworkflows/nf-neuro/registration/meta.yml | 4 +- .../nf-neuro/registration/tests/ants.config | 17 ++ ...nextflow_easyreg.config => easyreg.config} | 3 +- .../nf-neuro/registration/tests/main.nf.test | 139 ++++++----- .../registration/tests/main.nf.test.snap | 99 +++----- .../registration/tests/nextflow_ants.config | 11 - ...ration.config => synthregistration.config} | 6 +- 24 files changed, 561 insertions(+), 646 deletions(-) rename modules/nf-neuro/registration/convert/tests/{nextflow_default.config => nextflow.config} (100%) delete mode 100644 modules/nf-neuro/registration/convert/tests/nextflow_antsfs.config delete mode 100644 modules/nf-neuro/registration/convert/tests/nextflow_fsants.config delete mode 100644 modules/nf-neuro/registration/convert/tests/nextflow_fslants.config delete mode 100644 modules/nf-neuro/registration/convert/tests/nextflow_fslfs.config create mode 100644 subworkflows/nf-neuro/registration/tests/ants.config rename subworkflows/nf-neuro/registration/tests/{nextflow_easyreg.config => easyreg.config} (60%) delete mode 100644 subworkflows/nf-neuro/registration/tests/nextflow_ants.config rename subworkflows/nf-neuro/registration/tests/{nextflow_synthregistration.config => synthregistration.config} (56%) diff --git a/modules/nf-neuro/registration/convert/main.nf b/modules/nf-neuro/registration/convert/main.nf index 60757e8c..03fcc58b 100644 --- a/modules/nf-neuro/registration/convert/main.nf +++ b/modules/nf-neuro/registration/convert/main.nf @@ -6,12 +6,11 @@ process REGISTRATION_CONVERT { containerOptions "--env FSLOUTPUTTYPE='NIFTI_GZ'" input: - tuple val(meta), path(deform), path(affine), path(source), path(target), path(fs_license) + tuple val(meta), path(transformation), val(input_type), val(output_type), path(reference), path(affine_source), path(fs_license) output: - tuple val(meta), path("*out_warp.{nii,nii.gz,mgz,m3z}") , emit: deform_transform, optional: true - tuple val(meta), path("*out_affine.{txt,lta,mat,dat}") , emit: affine_transform, optional: true - path "versions.yml" , emit: versions + tuple val(meta), path("*out_{affine,warp}.{nii,nii.gz,mgz,m3z,txt,lta,mat,dat}") , emit: transformation + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -20,19 +19,47 @@ process REGISTRATION_CONVERT { def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - //For arguments definition, lta_convert -h - def invert = task.ext.invert ? "--invert" : "" - def source_geometry_affine = "$source" ? "--src " + "$source" : "" - def target_geometry_affine = "$target" ? "--trg " + "$target" : "" - def in_format_affine = task.ext.in_format_affine ? "--in" + task.ext.in_format_affine + " " + "$affine" : "--inlta " + "$affine" - def out_format_affine = task.ext.out_format_affine ? "--out" + task.ext.out_format_affine : "--outitk" + def transform_types = [ + affine: [lta: "lta", fsl: "mat", mni: "xfm", reg: "dat", niftyreg: "txt", itk: "txt", vox: "txt"], + warp: [m3z: "m3z", fsl: "nii.gz", lps: "nii.gz", itk: "nii.gz", ras: "nii.gz", vox: "mgz"] + ] + def spaces = ["ras2ras", "vox2vox", "register_dat"] + + // Validation transformation type and coercion with conversion type + def in_extension = transformation.name.tokenize('.')[1..-1].join('.') + def transform_type = transform_types.affine.find{ it.value == in_extension } ? "affine" : "warp" + if ( transform_type == "warp" && !transform_types.warp.containsKey(output_type) ) { + error "Invalid combination of transformation type and conversion type: ${transform_type} to ${output_type}." + } - //For arguments definition, mri_warp_convert -h - def source_geometry_deform = "$source" ? "--insrcgeom " + "$source" : "" - def in_format_deform = task.ext.in_format_deform ? "--in" + task.ext.in_format_deform + " " + "$deform" : "--inras " + "$deform" - def out_format_deform = task.ext.out_format_deform ? "--out" + task.ext.out_format_deform : "--outitk" - def downsample = task.ext.downsample ? "--downsample" : "" + def output_name = "${prefix}__out_${transform_type}.${transform_types[transform_type][output_type]}" + def command = transform_type == "affine" ? "lta_convert" : "mri_warp_convert" + + if ( transform_type == "affine" ) { + // Affine transformations are defined on the target space + args += " --in$input_type $transformation --out$output_type $output_name --trg $reference" + + // Validate source geometry is available for conversion to .lta + if ( output_type == "lta" ) { + if ( !affine_source ) error "Source geometry must be provided for conversion to .lta." + args += " --src $affine_source" + } + + if ( task.ext.invert ) args += " --invert" + if ( task.ext.conform ) args += " --trgconform" + if ( task.ext.output_space ) { + if ( !spaces.contains(task.ext.output_space) ) { + error "Invalid output space: ${task.ext.output_space}. Valid options are: ${spaces.join(', ')}" + } + args += " --outspace " + task.ext.output_space + } + } + else { + // Deformable transformations are defined on the source space + args += " --insrcgeom $reference --in$input_type $transformation --out$output_type $output_name" + if ( task.ext.downsample ) args += " --downsample" + } """ export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=$task.cpus export OMP_NUM_THREADS=1 @@ -40,34 +67,7 @@ process REGISTRATION_CONVERT { cp $fs_license \$FREESURFER_HOME/license.txt - if [[ -f "$affine" ]]; - then - declare -A affine_dictionnary=( ["--outlta"]="lta" \ - ["--outfsl"]="mat" \ - ["--outmni"]="xfm" \ - ["--outreg"]="dat" \ - ["--outniftyreg"]="txt" \ - ["--outitk"]="txt" \ - ["--outvox"]="txt" ) - - ext_affine=\${affine_dictionnary[${out_format_affine}]} - - lta_convert ${invert} ${source_geometry_affine} ${target_geometry_affine} ${in_format_affine} ${out_format_affine} ${prefix}__out_affine.\${ext_affine} - fi - - if [[ -f "$affine" ]]; - then - declare -A deform_dictionnary=( ["--outm3z"]="m3z" \ - ["--outfsl"]="nii.gz" \ - ["--outlps"]="nii.gz" \ - ["--outitk"]="nii.gz" \ - ["--outras"]="nii.gz" \ - ["--outvox"]="mgz" ) - - ext_deform=\${deform_dictionnary[${out_format_deform}]} - - mri_warp_convert ${source_geometry_deform} ${downsample} ${in_format_deform} ${out_format_deform} ${prefix}__out_warp.\${ext_deform} - fi + $command $args rm \$FREESURFER_HOME/license.txt @@ -78,7 +78,6 @@ process REGISTRATION_CONVERT { """ stub: - def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" """ diff --git a/modules/nf-neuro/registration/convert/meta.yml b/modules/nf-neuro/registration/convert/meta.yml index 93d6666a..7dea3ccd 100644 --- a/modules/nf-neuro/registration/convert/meta.yml +++ b/modules/nf-neuro/registration/convert/meta.yml @@ -15,39 +15,92 @@ tools: homepage: https://surfer.nmr.mgh.harvard.edu/ doi: 10.1016/j.neuroimage.2012.01.021 identifier: "" +args: + - invert: + type: boolean + description: FOR AFFINE CONVERSION ONLY. Invert the transformation. + default: false + - conform: + type: boolean + description: FOR AFFINE CONVERSION ONLY. Conform target geometry before conversion (see freesurfer documentation). + default: false + - output_space: + type: string + description: FOR AFFINE CONVERSION ONLY. Reference space to convert to. Default is ras2ras. + default: "ras2ras" + choices: + - ras2ras + - vox2vox + - register_dat + - downsample: + type: boolean + description: FOR WARP CONVERSION ONLY. Downsample the input warp to 2mm isotropic resolution. + default: false input: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - deform: + - transformation: type: file - description: Deform transform to convert. Default usage expects Freesurfer .mgz - format from mri_synthmorph - pattern: "*.{nii,nii.gz,mgz,m3z}" - mandatory: false - ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format - - affine: - type: file - description: Affine transform to convert. Default usage expects Freesurfer .lta - format from mri_synthmorph - pattern: "*.{lta,txt,xfm,dat}" - mandatory: false + description: Input transformation to convert. + pattern: "*.{nii,nii.gz,mgz,m3z,lta,txt,xfm,dat}" + mandatory: true ontologies: [] - - source: + - input_type: + type: string + description: | + Type of input transformation : + - affine : lta, fsl, mni, reg, niftyreg, itk, vox + - deform : m3z, fsl, lps, itk, ras, vox + mandatory: true + choices: + - lta + - fsl + - mni + - reg + - niftyreg + - itk + - vox + - m3z + - fsl + - lps + - ras + - vox + - output_type: + type: string + description: | + Type of output transformation : + - affine : lta, fsl, mni, reg, niftyreg, itk + - deform : m3z, fsl, lps, itk, ras, vox + mandatory: true + choices: + - lta + - fsl + - mni + - reg + - niftyreg + - itk + - vox + - m3z + - fsl + - lps + - ras + - vox + - reference: type: file - description: Moving Nifti volume used for registration. Defines source image - geometry + description: | + Reference volume used for registration. For affine transformations, it's usually the target + image, and for warp the moving (source) image. Validate with the tools you used to generate + the transformation. pattern: "*.{nii,nii.gz}" - mandatory: false + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - target: + - affine_source: type: file - description: Fixed Nifti volume used for registration. Defines target image - geometry. (optional) + description: ONLY USED FOR CONVERSION OF AFFINES IN LTA FORMAT. Moving (source) Nifti volume used for registration. pattern: "*.{nii,nii.gz}" mandatory: false ontologies: @@ -62,28 +115,18 @@ input: mandatory: true ontologies: [] output: - deform_transform: + transformation: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*out_warp.{nii,nii.gz,mgz,m3z}": + - "*out_{affine,warp}.{nii,nii.gz,mgz,m3z,txt,lta,mat,dat}": type: file - description: Deform transform. Default usage outputs ANTs (ITK) format .nii.gz - pattern: "*out_warp.{nii,nii.gz,mgz,m3z}" + description: Affine or warp converted to the desired format. + pattern: "*out_{affine,warp}.{nii,nii.gz,mgz,m3z,txt,lta,mat,dat}" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - affine_transform: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*out_affine.{txt,lta,mat,dat}": - type: map - description: Affine transform. Default usage outputs ANTs (ITK) format .txt - pattern: "*out_affine.{txt,lta,mat,dat}" versions: - versions.yml: type: file @@ -93,3 +136,4 @@ output: - edam: http://edamontology.org/format_3750 # YAML authors: - "@anroy1" + - "@AlexVCaron" diff --git a/modules/nf-neuro/registration/convert/tests/main.nf.test b/modules/nf-neuro/registration/convert/tests/main.nf.test index bfb5ad0b..086b8702 100644 --- a/modules/nf-neuro/registration/convert/tests/main.nf.test +++ b/modules/nf-neuro/registration/convert/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_process { name "Test Process REGISTRATION_CONVERT" script "../main.nf" process "REGISTRATION_CONVERT" + config "./nextflow.config" tag "modules" tag "modules_nfneuro" @@ -25,10 +26,7 @@ nextflow_process { } } - test("registration - convert - default") { - - config "./nextflow_default.config" - + test("registration - convert - deformation - ras to itk (lps)") { when { process { """ @@ -38,29 +36,28 @@ nextflow_process { reslice: it.simpleName == "freesurfer_reslice" transforms: it.simpleName == "freesurfer_transforms" } - ch_transforms = ch_split_test_data.transforms.map{ + ch_transform = ch_split_test_data.transforms.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/fs_deform.nii.gz"), - [] + file("\${test_data_directory}/fs_deform.nii.gz") ] } - ch_reslice = ch_split_test_data.reslice.map{ + ch_reference = ch_split_test_data.reslice.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/t1_reslice.nii.gz"), - [] + file("\${test_data_directory}/t1_reslice.nii.gz") ] } - ch_freesurfer = ch_split_test_data.freesurfer.map{ + ch_license = ch_split_test_data.freesurfer.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/license.txt") ] } - input[0] = ch_transforms - .join(ch_reslice) - .join(ch_freesurfer) + input[0] = ch_transform + .join(ch_reference) + .join(ch_license) + .map{ meta, transform, reference, license -> [ meta, transform, "ras", "lps", reference, [], license ] } """ } } @@ -73,10 +70,7 @@ nextflow_process { } } - test("registration - convert - affine") { - - config "./nextflow_default.config" - + test("registration - convert - affine - lta to fsl") { when { process { """ @@ -86,29 +80,28 @@ nextflow_process { reslice: it.simpleName == "freesurfer_reslice" transforms: it.simpleName == "freesurfer_transforms" } - ch_transforms = ch_split_test_data.transforms.map{ + ch_transform = ch_split_test_data.transforms.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/fs_deform.nii.gz"), file("\${test_data_directory}/fs_affine.lta") ] } - ch_reslice = ch_split_test_data.reslice.map{ + ch_reference = ch_split_test_data.reslice.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/t1_reslice.nii.gz"), file("\${test_data_directory}/fa_reslice.nii.gz") ] } - ch_freesurfer = ch_split_test_data.freesurfer.map{ + ch_license = ch_split_test_data.freesurfer.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/license.txt") ] } - input[0] = ch_transforms - .join(ch_reslice) - .join(ch_freesurfer) + input[0] = ch_transform + .join(ch_reference) + .join(ch_license) + .map{ meta, transform, reference, license -> [ meta, transform, "lta", "fsl", reference, [], license ] } """ } } @@ -121,10 +114,7 @@ nextflow_process { } } - test("registration - convert - fsants") { - - config "./nextflow_fsants.config" - + test("registration - convert - mixed - to itk") { when { process { """ @@ -136,75 +126,34 @@ nextflow_process { } ch_transforms = ch_split_test_data.transforms.map{ test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/fs_deform.nii.gz"), - file("\${test_data_directory}/fs_affine.lta") + [[ id:'test1' ], [ id:'test2' ]], + [ + file("\${test_data_directory}/fs_deform.nii.gz"), + file("\${test_data_directory}/fs_affine.lta") + ], + [ "ras", "lta" ], + [ "itk" ] ] } - ch_reslice = ch_split_test_data.reslice.map{ + ch_reference = ch_split_test_data.reslice.map{ test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/t1_reslice.nii.gz"), - file("\${test_data_directory}/fa_reslice.nii.gz") + [[ id:'test1' ], [ id:'test2' ]], + [ + file("\${test_data_directory}/t1_reslice.nii.gz"), + file("\${test_data_directory}/fa_reslice.nii.gz") + ] ] } - ch_freesurfer = ch_split_test_data.freesurfer.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/license.txt") - ] + ch_license = ch_split_test_data.freesurfer.map{ + test_data_directory -> file("\${test_data_directory}/license.txt") } input[0] = ch_transforms - .join(ch_reslice) - .join(ch_freesurfer) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("registration - convert - fslfs") { - - config "./nextflow_fslfs.config" - - when { - process { - """ - ch_split_test_data = LOAD_DATA.out.test_data_directory - .branch{ - freesurfer: it.simpleName == "freesurfer" - reslice: it.simpleName == "freesurfer_reslice" - transforms: it.simpleName == "freesurfer_transforms" + .join(ch_reference) + .transpose() + .combine(ch_license) + .map{ meta, transform, intype, outtype, reference, license -> + [ meta, transform, intype, outtype, reference, [], license ] } - ch_transforms = ch_split_test_data.transforms.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/fsl_deform.nii.gz"), - file("\${test_data_directory}/fsl_affine.mat") - ] - } - ch_reslice = ch_split_test_data.reslice.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/t1_reslice.nii.gz"), - file("\${test_data_directory}/fa_reslice.nii.gz") - ] - } - ch_freesurfer = ch_split_test_data.freesurfer.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/license.txt") - ] - } - input[0] = ch_transforms - .join(ch_reslice) - .join(ch_freesurfer) """ } } @@ -212,19 +161,12 @@ nextflow_process { then { assertAll( { assert process.success }, - { assert snapshot( - file(process.out.affine_transform.get(0).get(1)).name, - process.out.deform_transform, - process.out.versions - ).match() } + { assert snapshot(process.out).match() } ) } } - test("registration - convert - fslants") { - - config "./nextflow_fslants.config" - + test("registration - convert - affine - to lta (needs source)") { when { process { """ @@ -234,77 +176,35 @@ nextflow_process { reslice: it.simpleName == "freesurfer_reslice" transforms: it.simpleName == "freesurfer_transforms" } - ch_transforms = ch_split_test_data.transforms.map{ + ch_transform = ch_split_test_data.transforms.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/fsl_deform.nii.gz"), file("\${test_data_directory}/fsl_affine.mat") ] } - ch_reslice = ch_split_test_data.reslice.map{ + ch_reference = ch_split_test_data.reslice.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/t1_reslice.nii.gz"), file("\${test_data_directory}/fa_reslice.nii.gz") ] } - ch_freesurfer = ch_split_test_data.freesurfer.map{ + ch_source = ch_split_test_data.reslice.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/license.txt") + file("\${test_data_directory}/t1_reslice.nii.gz") ] } - input[0] = ch_transforms - .join(ch_reslice) - .join(ch_freesurfer) - """ - } - } - - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } - - test("registration - convert - antsfs") { - - config "./nextflow_antsfs.config" - - when { - process { - """ - ch_split_test_data = LOAD_DATA.out.test_data_directory - .branch{ - freesurfer: it.simpleName == "freesurfer" - reslice: it.simpleName == "freesurfer_reslice" - transforms: it.simpleName == "freesurfer_transforms" - } - ch_transforms = ch_split_test_data.transforms.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/ants_deform.nii.gz"), - file("\${test_data_directory}/ants_affine.txt") - ] - } - ch_reslice = ch_split_test_data.reslice.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/t1_reslice.nii.gz"), - file("\${test_data_directory}/fa_reslice.nii.gz") - ] - } - ch_freesurfer = ch_split_test_data.freesurfer.map{ + ch_license = ch_split_test_data.freesurfer.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/license.txt") ] } - input[0] = ch_transforms - .join(ch_reslice) - .join(ch_freesurfer) + input[0] = ch_transform + .map{ meta, transform -> [meta, transform, "fsl", "lta"] } + .join(ch_reference) + .join(ch_source) + .join(ch_license) """ } } @@ -313,8 +213,7 @@ nextflow_process { assertAll( { assert process.success }, { assert snapshot( - file(process.out.affine_transform.get(0).get(1)).name, - process.out.deform_transform, + file(process.out.transformation.get(0).get(1)).name, process.out.versions ).match() } ) @@ -334,29 +233,28 @@ nextflow_process { reslice: it.simpleName == "freesurfer_reslice" transforms: it.simpleName == "freesurfer_transforms" } - ch_transforms = ch_split_test_data.transforms.map{ + ch_transform = ch_split_test_data.transforms.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/fs_deform.nii.gz"), - [] ] } - ch_reslice = ch_split_test_data.reslice.map{ + ch_reference = ch_split_test_data.reslice.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/t1_reslice.nii.gz"), - [] ] } - ch_freesurfer = ch_split_test_data.freesurfer.map{ + ch_license = ch_split_test_data.freesurfer.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/license.txt") ] } - input[0] = ch_transforms - .join(ch_reslice) - .join(ch_freesurfer) + input[0] = ch_transform + .join(ch_reference) + .join(ch_license) + .map{ meta, transform, reference, license -> [ meta, transform, "ras", "itk", reference, [], license ] } """ } } diff --git a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap index 86d456c7..79d15fd5 100644 --- a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap @@ -1,54 +1,30 @@ { - "registration - convert - fsants": { + "registration - convert - stub-run": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "test__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test__out_affine.txt:md5,5f989a979be61faa578ad619377a8a07" - ] - ], - "2": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" - ], - "affine_transform": [ - [ - { - "id": "test" - }, - "test__out_affine.txt:md5,5f989a979be61faa578ad619377a8a07" - ] - ], - "deform_transform": [ - [ - { - "id": "test" - }, - "test__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" - ] - ], - "versions": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" - ] - } + [ + "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + ] ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.3" + "nextflow": "25.04.2" }, - "timestamp": "2025-06-04T03:19:41.033223181" + "timestamp": "2025-05-30T21:45:21.615899949" }, - "registration - convert - default": { + "registration - convert - affine - to lta (needs source)": { + "content": [ + "test__out_affine.lta", + [ + "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "25.04.6" + }, + "timestamp": "2025-07-25T15:15:22.167873891" + }, + "registration - convert - affine - lta to fsl": { "content": [ { "0": [ @@ -56,24 +32,18 @@ { "id": "test" }, - "test__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + "test__out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" ] ], "1": [ - - ], - "2": [ "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" ], - "affine_transform": [ - - ], - "deform_transform": [ + "transformation": [ [ { "id": "test" }, - "test__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + "test__out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" ] ], "versions": [ @@ -83,67 +53,30 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-04T03:23:23.394821601" - }, - "registration - convert - antsfs": { - "content": [ - "test__out_affine.lta", - [ - [ - { - "id": "test" - }, - "test__out_warp.nii.gz:md5,599fbe3a6b85d61c0c67cea8be4972b7" - ] - ], - [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.3" + "nextflow": "25.04.6" }, - "timestamp": "2025-06-04T03:22:34.322609153" + "timestamp": "2025-07-25T15:15:03.099213703" }, - "registration - convert - fslants": { + "registration - convert - mixed - to itk": { "content": [ { "0": [ [ { - "id": "test" + "id": "test1" }, - "test__out_warp.nii.gz:md5,94feb8f0e648256eaa5ae0a47e5702c6" + "test1__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" ] ], "1": [ - [ - { - "id": "test" - }, - "test__out_affine.txt:md5,074e8ac5777a91ba0808cd58c5a0cc44" - ] - ], - "2": [ "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" ], - "affine_transform": [ + "transformation": [ [ { - "id": "test" + "id": "test1" }, - "test__out_affine.txt:md5,074e8ac5777a91ba0808cd58c5a0cc44" - ] - ], - "deform_transform": [ - [ - { - "id": "test" - }, - "test__out_warp.nii.gz:md5,94feb8f0e648256eaa5ae0a47e5702c6" + "test1__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" ] ], "versions": [ @@ -153,11 +86,11 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.3" + "nextflow": "25.04.6" }, - "timestamp": "2025-06-04T03:24:33.171811516" + "timestamp": "2025-07-25T15:15:12.599002015" }, - "registration - convert - affine": { + "registration - convert - deformation - ras to itk (lps)": { "content": [ { "0": [ @@ -169,25 +102,9 @@ ] ], "1": [ - [ - { - "id": "test" - }, - "test__out_affine.txt:md5,5f989a979be61faa578ad619377a8a07" - ] - ], - "2": [ "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" ], - "affine_transform": [ - [ - { - "id": "test" - }, - "test__out_affine.txt:md5,5f989a979be61faa578ad619377a8a07" - ] - ], - "deform_transform": [ + "transformation": [ [ { "id": "test" @@ -202,29 +119,8 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.3" - }, - "timestamp": "2025-06-04T03:21:57.24523274" - }, - "registration - convert - fslfs": { - "content": [ - "test__out_affine.lta", - [ - [ - { - "id": "test" - }, - "test__out_warp.nii.gz:md5,df432a27c586e57cad93af7509941cd4" - ] - ], - [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.3" + "nextflow": "25.04.6" }, - "timestamp": "2025-06-04T03:15:42.966436752" + "timestamp": "2025-07-25T14:54:35.309900291" } } diff --git a/modules/nf-neuro/registration/convert/tests/nextflow_default.config b/modules/nf-neuro/registration/convert/tests/nextflow.config similarity index 100% rename from modules/nf-neuro/registration/convert/tests/nextflow_default.config rename to modules/nf-neuro/registration/convert/tests/nextflow.config diff --git a/modules/nf-neuro/registration/convert/tests/nextflow_antsfs.config b/modules/nf-neuro/registration/convert/tests/nextflow_antsfs.config deleted file mode 100644 index 0b93daa8..00000000 --- a/modules/nf-neuro/registration/convert/tests/nextflow_antsfs.config +++ /dev/null @@ -1,9 +0,0 @@ -process { - withName: "REGISTRATION_CONVERT" { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - ext.in_format_affine = "itk" - ext.out_format_affine = "lta" - ext.in_format_deform = "itk" - ext.out_format_deform = "ras" - } -} diff --git a/modules/nf-neuro/registration/convert/tests/nextflow_fsants.config b/modules/nf-neuro/registration/convert/tests/nextflow_fsants.config deleted file mode 100644 index 000a4d92..00000000 --- a/modules/nf-neuro/registration/convert/tests/nextflow_fsants.config +++ /dev/null @@ -1,9 +0,0 @@ -process { - withName: "REGISTRATION_CONVERT" { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - ext.in_format_affine = "lta" - ext.out_format_affine = "itk" - ext.in_format_deform = "ras" - ext.out_format_deform = "itk" - } -} diff --git a/modules/nf-neuro/registration/convert/tests/nextflow_fslants.config b/modules/nf-neuro/registration/convert/tests/nextflow_fslants.config deleted file mode 100644 index 82e10d53..00000000 --- a/modules/nf-neuro/registration/convert/tests/nextflow_fslants.config +++ /dev/null @@ -1,9 +0,0 @@ -process { - withName: "REGISTRATION_CONVERT" { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - ext.in_format_affine = "fsl" - ext.out_format_affine = "itk" - ext.in_format_deform = "fsl" - ext.out_format_deform = "itk" - } -} diff --git a/modules/nf-neuro/registration/convert/tests/nextflow_fslfs.config b/modules/nf-neuro/registration/convert/tests/nextflow_fslfs.config deleted file mode 100644 index 6e1b2e0c..00000000 --- a/modules/nf-neuro/registration/convert/tests/nextflow_fslfs.config +++ /dev/null @@ -1,9 +0,0 @@ -process { - withName: "REGISTRATION_CONVERT" { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - ext.in_format_affine = "fsl" - ext.out_format_affine = "lta" - ext.in_format_deform = "fsl" - ext.out_format_deform = "ras" - } -} diff --git a/modules/nf-neuro/registration/easyreg/main.nf b/modules/nf-neuro/registration/easyreg/main.nf index 57c01870..e6ee6a5d 100644 --- a/modules/nf-neuro/registration/easyreg/main.nf +++ b/modules/nf-neuro/registration/easyreg/main.nf @@ -12,8 +12,8 @@ process REGISTRATION_EASYREG { output: tuple val(meta), path("*_warped.nii.gz") , emit: image_warped tuple val(meta), path("*_warped_reference.nii.gz") , emit: fixed_warped - tuple val(meta), path("*_forward0_warp.nii.gz") , emit: warp - tuple val(meta), path("*_backward0_warp.nii.gz") , emit: inverse_warp + tuple val(meta), path("*_forward0_warp.nii.gz") , emit: warp, optional: true + tuple val(meta), path("*_backward0_warp.nii.gz") , emit: inverse_warp, optional: true tuple val(meta), path("*_warped_segmentation.nii.gz") , emit: segmentation_warped, optional: true tuple val(meta), path("*_warped_reference_segmentation.nii.gz") , emit: fixed_segmentation_warped, optional: true path "versions.yml" , emit: versions @@ -23,8 +23,7 @@ process REGISTRATION_EASYREG { script: def prefix = task.ext.prefix ?: "${meta.id}" - def field = task.ext.field ? "--fwd_field ${prefix}_forward0_warp.nii.gz --bak_field ${prefix}_backward0_warp.nii.gz " : "" - def affine = task.ext.affine ? "--affine_only " : "" + def affine_only = task.ext.affine_only ? "--affine_only " : "" fixed_segmentation = "--ref_seg ${fixed_segmentation ?: "${prefix}__warped_segmentation.nii.gz" }" moving_segmentation = "--flo_seg ${moving_segmentation ?: "${prefix}__warped_reference_segmentation.nii.gz" }" """ @@ -36,8 +35,10 @@ process REGISTRATION_EASYREG { --flo $moving_image \ --flo_reg ${prefix}_warped.nii.gz \ --ref_reg ${prefix}_warped_reference.nii.gz \ + --fwd_field ${prefix}_forward0_warp.nii.gz \ + --bak_field ${prefix}_backward0_warp.nii.gz \ $fixed_segmentation $moving_segmentation \ - --threads $task.cpus $field $affine + --threads $task.cpus $affine_only cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-neuro/registration/easyreg/meta.yml b/modules/nf-neuro/registration/easyreg/meta.yml index ccfe70f7..3d45328e 100644 --- a/modules/nf-neuro/registration/easyreg/meta.yml +++ b/modules/nf-neuro/registration/easyreg/meta.yml @@ -15,6 +15,11 @@ tools: homepage: https://surfer.nmr.mgh.harvard.edu/ doi: 10.1016/j.neuroimage.2012.01.021 identifier: "" +args: + - affine_only: + type: boolean + description: Only perform affine registration + default: false input: - - meta: type: map diff --git a/modules/nf-neuro/registration/easyreg/tests/nextflow.config b/modules/nf-neuro/registration/easyreg/tests/nextflow.config index 71494b4d..8873712e 100644 --- a/modules/nf-neuro/registration/easyreg/tests/nextflow.config +++ b/modules/nf-neuro/registration/easyreg/tests/nextflow.config @@ -1,9 +1,8 @@ process { - memory = '10G' withName: "REGISTRATION_EASYREG" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - ext.field = true - ext.affine = true - ext.threads = 1 + ext.affine_only = true + memory = '10G' + cpus = 1 } } diff --git a/modules/nf-neuro/registration/synthregistration/main.nf b/modules/nf-neuro/registration/synthregistration/main.nf index 19b65029..414b63fd 100644 --- a/modules/nf-neuro/registration/synthregistration/main.nf +++ b/modules/nf-neuro/registration/synthregistration/main.nf @@ -11,16 +11,16 @@ process REGISTRATION_SYNTHREGISTRATION { tuple val(meta), path(fixed_image), path(moving_image) output: - tuple val(meta), path("*__warped.nii.gz") , emit: image_warped - tuple val(meta), path("*__forward1_affine.lta") , emit: affine, optional: true - tuple val(meta), path("*__forward0_warp.nii.gz") , emit: warp, optional: true - tuple val(meta), path("*__backward1_warp.nii.gz") , emit: inverse_warp, optional: true - tuple val(meta), path("*__backward0_affine.lta") , emit: inverse_affine, optional: true - tuple val(meta), path("*__forward*.{lta,nii.gz}") , emit: image_transform - tuple val(meta), path("*__backward*.{lta,nii.gz}") , emit: inverse_image_transform - tuple val(meta), path("*__backward*.{lta,nii.gz}") , emit: tractogram_transform - tuple val(meta), path("*__forward*.{lta,nii.gz}") , emit: inverse_tractogram_transform - path "versions.yml" , emit: versions + tuple val(meta), path("*__warped.nii.gz") , emit: image_warped + tuple val(meta), path("*__forward{0,1,_standalone}_affine.lta") , emit: affine, optional: true + tuple val(meta), path("*__forward0_deform.nii.gz") , emit: warp, optional: true + tuple val(meta), path("*__backward1_deform.nii.gz") , emit: inverse_warp, optional: true + tuple val(meta), path("*__backward{0,_standalone}_affine.lta") , emit: inverse_affine, optional: true + tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: image_transform + tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: inverse_image_transform + tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: tractogram_transform + tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: inverse_tractogram_transform + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -58,6 +58,7 @@ process REGISTRATION_SYNTHREGISTRATION { skip=0 j=${models.size()} initializer="" + init_assoc="" for model in ${models.join(" ")} do echo "Processing model: \$model" @@ -98,16 +99,22 @@ process REGISTRATION_SYNTHREGISTRATION { mri_synthmorph register \$moving fixed.nii.gz -v -m \$model \$weight \$args \ -t ${prefix}__forward\${j}_\$model.\${extension[\$model]} \ + -T ${prefix}__backward\${i}_\$model.\${extension[\$model]} \ -o warped.nii.gz -j $task.cpus $extent $use_gpu if [ \$initializer ] then - rm \$initializer + # rm \$initializer \$init_assoc + # Retag initializer file to standalone using sed + # - replace the number after forward/backward to standalone + mv \$initializer \$(echo "\$initializer" | sed -r 's/(_forward|_backward)[[:digit:]]+/\\1_standalone/') + mv \$init_assoc \$(echo "\$init_assoc" | sed -r 's/(_forward|_backward)[[:digit:]]+/\\1_standalone/') fi if [ \${extension[\$model]} = "lta" ] then initializer=${prefix}__forward\${j}_\$model.\${extension[\$model]} + init_assoc=${prefix}__backward\${i}_\$model.\${extension[\$model]} else moving=warped.nii.gz fi diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthregistration/meta.yml index 16bca14c..26af5c6c 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthregistration/meta.yml @@ -64,7 +64,7 @@ args: - 256 - disable_resampling: type: boolean - description: Update image header instead of performing resampling of the output image. + description: Update image header instead of performing resampling of the image grid. default: false input: - - meta: diff --git a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap index 16f3d8cb..0cd594c3 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap @@ -8,7 +8,7 @@ "id": "test", "single_end": false }, - "test__forward1_affine.lta" + "test__forward_standalone_affine.lta" ] ], "image_transform": [ @@ -17,8 +17,7 @@ "id": "test", "single_end": false }, - "test__forward0_deform.nii.gz", - "test__forward1_affine.lta" + "test__forward0_deform.nii.gz" ] ], "image_warped": [ @@ -30,18 +29,62 @@ "test__warped.nii.gz" ] ], + "inverse_affine": [ + [ + { + "id": "test", + "single_end": false + }, + "test__backward_standalone_affine.lta" + ] + ], + "inverse_image_transform": [ + [ + { + "id": "test", + "single_end": false + }, + "test__backward1_deform.nii.gz" + ] + ], "inverse_tractogram_transform": [ [ { "id": "test", "single_end": false }, - "test__forward0_deform.nii.gz", - "test__forward1_affine.lta" + "test__forward0_deform.nii.gz" + ] + ], + "inverse_warp": [ + [ + { + "id": "test", + "single_end": false + }, + "test__backward1_deform.nii.gz" + ] + ], + "tractogram_transform": [ + [ + { + "id": "test", + "single_end": false + }, + "test__backward1_deform.nii.gz" ] ], "versions": [ "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" + ], + "warp": [ + [ + { + "id": "test", + "single_end": false + }, + "test__forward0_deform.nii.gz" + ] ] } ], @@ -49,7 +92,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.6" }, - "timestamp": "2025-07-19T23:30:21.67250369" + "timestamp": "2025-07-28T15:53:09.741422131" }, "registration - synthregistration - stub-run": { "content": [ diff --git a/modules/nf-neuro/registration/synthregistration/tests/nextflow.config b/modules/nf-neuro/registration/synthregistration/tests/nextflow.config index b38ad2c3..a08f4c71 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/nextflow.config +++ b/modules/nf-neuro/registration/synthregistration/tests/nextflow.config @@ -1,11 +1,10 @@ process { withName: "REGISTRATION_SYNTHREGISTRATION" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - memory = "26G" - ext.affine = "affine" - ext.warp = "deform" - ext.lambda = 0.9 + ext.models = ["affine", "deform"] + ext.regularization = 0.9 ext.steps = 9 ext.extent = 192 + memory = '18G' } } diff --git a/subworkflows/nf-neuro/registration/main.nf b/subworkflows/nf-neuro/registration/main.nf index 2af3cb63..81f62b9a 100644 --- a/subworkflows/nf-neuro/registration/main.nf +++ b/subworkflows/nf-neuro/registration/main.nf @@ -2,10 +2,12 @@ include { REGISTRATION_ANATTODWI } from '../../../modules/nf-neuro/registration include { REGISTRATION_ANTS } from '../../../modules/nf-neuro/registration/ants/main' include { REGISTRATION_EASYREG } from '../../../modules/nf-neuro/registration/easyreg/main' include { REGISTRATION_SYNTHREGISTRATION } from '../../../modules/nf-neuro/registration/synthregistration/main' +include { REGISTRATION_CONVERT } from '../../../modules/nf-neuro/registration/convert/main' params.run_easyreg = false params.run_synthmorph = false + workflow REGISTRATION { // The subworkflow requires at least ch_fixed_image and ch_moving_image as inputs to @@ -22,8 +24,10 @@ workflow REGISTRATION { ch_fixed_mask // channel: [ val(meta), mask ], optional ch_segmentation // channel: [ val(meta), segmentation ], optional ch_moving_segmentation // channel: [ val(meta), segmentation ], optional + ch_freesurfer_license // channel: [ license ], optional main: ch_versions = Channel.empty() + ch_mqc = Channel.empty() if ( params.run_easyreg ) { // ** Registration using Easyreg ** // @@ -43,20 +47,20 @@ workflow REGISTRATION { ch_versions = ch_versions.mix(REGISTRATION_EASYREG.out.versions.first()) // ** Set compulsory outputs ** // - image_warped = REGISTRATION_EASYREG.out.image_warped - affine = Channel.empty() - warp = REGISTRATION_EASYREG.out.warp - inverse_affine = Channel.empty() - inverse_warp = REGISTRATION_EASYREG.out.inverse_warp - image_transform = REGISTRATION_EASYREG.out.warp - inverse_image_transform = REGISTRATION_EASYREG.out.inverse_warp - tractogram_transform = REGISTRATION_EASYREG.out.inverse_warp - inverse_tractogram_transform = REGISTRATION_EASYREG.out.warp + out_image_warped = REGISTRATION_EASYREG.out.image_warped + out_affine = Channel.empty() + out_warp = REGISTRATION_EASYREG.out.warp + out_inverse_affine = Channel.empty() + out_inverse_warp = REGISTRATION_EASYREG.out.inverse_warp + out_image_transform = REGISTRATION_EASYREG.out.warp + out_inverse_image_transform = REGISTRATION_EASYREG.out.inverse_warp + out_tractogram_transform = REGISTRATION_EASYREG.out.inverse_warp + out_inverse_tractogram_transform = REGISTRATION_EASYREG.out.warp // ** Set optional outputs. ** // // If segmentations are not provided as inputs, // easyreg will outputs synthseg segmentations - ref_warped = REGISTRATION_EASYREG.out.fixed_warped + out_ref_warped = REGISTRATION_EASYREG.out.fixed_warped out_segmentation = ch_segmentation.mix( REGISTRATION_EASYREG.out.segmentation_warped ) out_ref_segmentation = ch_moving_segmentation.mix( REGISTRATION_EASYREG.out.fixed_segmentation_warped ) } @@ -68,19 +72,83 @@ workflow REGISTRATION { REGISTRATION_SYNTHREGISTRATION ( ch_register ) ch_versions = ch_versions.mix(REGISTRATION_SYNTHREGISTRATION.out.versions.first()) - // ** Set compulsory outputs ** // - image_warped = REGISTRATION_SYNTHREGISTRATION.out.image_warped - affine = REGISTRATION_SYNTHREGISTRATION.out.affine - warp = REGISTRATION_SYNTHREGISTRATION.out.warp - inverse_affine = REGISTRATION_SYNTHREGISTRATION.out.inverse_affine - inverse_warp = REGISTRATION_SYNTHREGISTRATION.out.inverse_warp - image_transform = REGISTRATION_SYNTHREGISTRATION.out.image_transform - inverse_image_transform = REGISTRATION_SYNTHREGISTRATION.out.inverse_image_transform - tractogram_transform = REGISTRATION_SYNTHREGISTRATION.out.tractogram_transform - inverse_tractogram_transform = REGISTRATION_SYNTHREGISTRATION.out.inverse_tractogram_transform + // Tag all synthmorph transforms per type, and index if in a chain. This info will be + // used after conversion to sort out the transforms from the conversion module. + ch_convert_affine = REGISTRATION_SYNTHREGISTRATION.out.affine + .map{ meta, affine -> [meta, [tag: "affine"], affine] } + ch_convert_warp = REGISTRATION_SYNTHREGISTRATION.out.warp + .map{ meta, warp -> [meta, [tag: "warp"], warp] } + ch_convert_inverse_affine = REGISTRATION_SYNTHREGISTRATION.out.inverse_affine + .map{ meta, inverse_affine -> [meta, [tag: "inverse_affine"], inverse_affine] } + ch_convert_inverse_warp = REGISTRATION_SYNTHREGISTRATION.out.inverse_warp + .map{ meta, inverse_warp -> [meta, [tag: "inverse_warp"], inverse_warp] } + ch_convert_image_transform = REGISTRATION_SYNTHREGISTRATION.out.image_transform + .map{ meta, transforms -> [meta, [tag: "image_transform"], 0.. [meta, tag + [idx: idx], transform]} + ch_convert_inverse_image_transform = REGISTRATION_SYNTHREGISTRATION.out.inverse_image_transform + .map{ meta, transforms -> [meta, [tag: "inverse_image_transform"], 0.. [meta, tag + [idx: idx], transform]} + + // Mix all transforms into a single channel for conversion + ch_convert = ch_convert_affine.view{ "affine $it" } + .mix(ch_convert_warp.view{ "warp $it" }) + .mix(ch_convert_inverse_affine.view{ "inv-affine $it" }) + .mix(ch_convert_inverse_warp.view{ "inv-warp $it" }) + .mix(ch_convert_image_transform.view{ "image-transform $it" }) + .mix(ch_convert_inverse_image_transform.view{ "inv-image-transform $it" }) + .combine(ch_fixed_image, by: 0) + .combine(ch_moving_image, by: 0) + .map{ meta, tag, transform, fixed, moving -> + def extension = transform.name.tokenize('.')[1..-1].join(".") + return [ + meta + tag + [cache: meta], + transform, + extension == "lta" ? "lta" : "ras", + "itk", + extension == "lta" ? fixed : moving, + [], + ]} + .combine(ch_freesurfer_license) + + REGISTRATION_CONVERT ( ch_convert ) + ch_versions = ch_versions.mix(REGISTRATION_CONVERT.out.versions.first()) + + // Un-mix conversion outputs using the tags. Save indexes for output sorting + ch_conversion_outputs = REGISTRATION_CONVERT.out.transformation + .branch{ meta, transform -> + affine: meta.tag == "affine" + return [meta.cache, transform] + warp: meta.tag == "warp" + return [meta.cache, transform] + inverse_affine: meta.tag == "inverse_affine" + return [meta.cache, transform] + inverse_warp: meta.tag == "inverse_warp" + return [meta.cache, transform] + image_transform: meta.tag == "image_transform" + return [meta.cache, [idx: meta.idx, trans: transform]] + inverse_image_transform: meta.tag == "inverse_image_transform" + return [meta.cache, [idx: meta.idx, trans: transform]] + } + + // ** Set compulsory outputs ** // + out_image_warped = REGISTRATION_SYNTHREGISTRATION.out.image_warped + out_affine = ch_conversion_outputs.affine + out_warp = ch_conversion_outputs.warp + out_inverse_affine = ch_conversion_outputs.inverse_affine + out_inverse_warp = ch_conversion_outputs.inverse_warp + out_image_transform = ch_conversion_outputs.image_transform + .groupTuple() + .map{ meta, trans -> [meta, trans.sort{ t1, t2 -> t1.idx <=> t2.idx }.collect{ it.trans }] } + out_inverse_image_transform = ch_conversion_outputs.inverse_image_transform + .groupTuple() + .map{ meta, trans -> [meta, trans.sort{ t1, t2 -> t1.idx <=> t2.idx }.collect{ it.trans }] } + out_tractogram_transform = out_inverse_image_transform + out_inverse_tractogram_transform = out_image_transform // ** and optional outputs. ** // - ref_warped = Channel.empty() + out_ref_warped = Channel.empty() out_segmentation = Channel.empty() out_ref_segmentation = Channel.empty() } @@ -106,17 +174,18 @@ workflow REGISTRATION { // ** Registration using ANAT TO DWI ** // REGISTRATION_ANATTODWI ( ch_register.anat_to_dwi ) ch_versions = ch_versions.mix(REGISTRATION_ANATTODWI.out.versions.first()) + ch_mqc = ch_mqc.mix(REGISTRATION_ANATTODWI.out.mqc) // ** Set compulsory outputs ** // - image_warped = REGISTRATION_ANATTODWI.out.anat_warped - affine = REGISTRATION_ANATTODWI.out.affine - warp = REGISTRATION_ANATTODWI.out.warp - inverse_affine = REGISTRATION_ANATTODWI.out.inverse_affine - inverse_warp = REGISTRATION_ANATTODWI.out.inverse_warp - image_transform = REGISTRATION_ANATTODWI.out.image_transform - inverse_image_transform = REGISTRATION_ANATTODWI.out.inverse_image_transform - tractogram_transform = REGISTRATION_ANATTODWI.out.tractogram_transform - inverse_tractogram_transform = REGISTRATION_ANATTODWI.out.inverse_tractogram_transform + out_image_warped = REGISTRATION_ANATTODWI.out.anat_warped + out_affine = REGISTRATION_ANATTODWI.out.affine + out_warp = REGISTRATION_ANATTODWI.out.warp + out_inverse_affine = REGISTRATION_ANATTODWI.out.inverse_affine + out_inverse_warp = REGISTRATION_ANATTODWI.out.inverse_warp + out_image_transform = REGISTRATION_ANATTODWI.out.image_transform + out_inverse_image_transform = REGISTRATION_ANATTODWI.out.inverse_image_transform + out_tractogram_transform = REGISTRATION_ANATTODWI.out.tractogram_transform + out_inverse_tractogram_transform = REGISTRATION_ANATTODWI.out.inverse_tractogram_transform // ** Registration using ANTS SYN SCRIPTS ** // // Registration using antsRegistrationSyN.sh or antsRegistrationSyNQuick.sh, has @@ -131,39 +200,41 @@ workflow REGISTRATION { REGISTRATION_ANTS ( ch_register ) ch_versions = ch_versions.mix(REGISTRATION_ANTS.out.versions.first()) + ch_mqc = ch_mqc.mix(REGISTRATION_ANTS.out.mqc) // ** Set compulsory outputs ** // - image_warped = image_warped.mix(REGISTRATION_ANTS.out.image_warped) - affine = affine.mix(REGISTRATION_ANTS.out.affine) - warp = warp.mix(REGISTRATION_ANTS.out.warp) - inverse_affine = inverse_affine.mix(REGISTRATION_ANTS.out.inverse_affine) - inverse_warp = inverse_warp.mix(REGISTRATION_ANTS.out.inverse_warp) - image_transform = image_transform.mix(REGISTRATION_ANTS.out.image_transform) - inverse_image_transform = inverse_image_transform.mix(REGISTRATION_ANTS.out.inverse_image_transform) - tractogram_transform = tractogram_transform.mix(REGISTRATION_ANTS.out.tractogram_transform) - inverse_tractogram_transform = inverse_tractogram_transform.mix(REGISTRATION_ANTS.out.inverse_tractogram_transform) + out_image_warped = out_image_warped.mix(REGISTRATION_ANTS.out.image_warped) + out_affine = out_affine.mix(REGISTRATION_ANTS.out.affine) + out_warp = out_warp.mix(REGISTRATION_ANTS.out.warp) + out_inverse_affine = out_inverse_affine.mix(REGISTRATION_ANTS.out.inverse_affine) + out_inverse_warp = out_inverse_warp.mix(REGISTRATION_ANTS.out.inverse_warp) + out_image_transform = out_image_transform.mix(REGISTRATION_ANTS.out.image_transform) + out_inverse_image_transform = out_inverse_image_transform.mix(REGISTRATION_ANTS.out.inverse_image_transform) + out_tractogram_transform = out_tractogram_transform.mix(REGISTRATION_ANTS.out.tractogram_transform) + out_inverse_tractogram_transform = out_inverse_tractogram_transform.mix(REGISTRATION_ANTS.out.inverse_tractogram_transform) // **and optional outputs **// - ref_warped = Channel.empty() + out_ref_warped = Channel.empty() out_segmentation = Channel.empty() out_ref_segmentation = Channel.empty() } emit: - image_warped = image_warped // channel: [ val(meta), image ] - ref_warped = ref_warped // channel: [ val(meta), ref ] + image_warped = out_image_warped // channel: [ val(meta), image ] + ref_warped = out_ref_warped // channel: [ val(meta), ref ] // Individual transforms - affine = affine // channel: [ val(meta), ] - warp = warp // channel: [ val(meta), ] - inverse_affine = inverse_affine // channel: [ val(meta), ] - inverse_warp = inverse_warp // channel: [ val(meta), ] + affine = out_affine // channel: [ val(meta), ] + warp = out_warp // channel: [ val(meta), ] + inverse_warp = out_inverse_warp // channel: [ val(meta), ] + inverse_affine = out_inverse_affine // channel: [ val(meta), ] // Combined transforms - image_transform = image_transform // channel: [ val(meta), [ , ] ] - inverse_image_transform = inverse_image_transform // channel: [ val(meta), [ , ] ] - tractogram_transform = tractogram_transform // channel: [ val(meta), [ , ] ] - inverse_tractogram_transform = inverse_tractogram_transform // channel: [ val(meta), [ , ] ] + image_transform = out_image_transform // channel: [ val(meta), [ , ] ] + inverse_image_transform = out_inverse_image_transform // channel: [ val(meta), [ , ] ] + tractogram_transform = out_tractogram_transform // channel: [ val(meta), [ , ] ] + inverse_tractogram_transform = out_inverse_tractogram_transform // channel: [ val(meta), [ , ] ] // Segmentations - segmentation = out_segmentation // channel: [ val(meta), segmentation ] - ref_segmentation = out_ref_segmentation // channel: [ val(meta), ref-segmentation ] + segmentation = out_segmentation // channel: [ val(meta), segmentation ] + ref_segmentation = out_ref_segmentation // channel: [ val(meta), ref-segmentation ] - versions = ch_versions // channel: [ versions.yml ] + mqc = ch_mqc // channel: [ *mqc.*, ... ] + versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/nf-neuro/registration/meta.yml b/subworkflows/nf-neuro/registration/meta.yml index 2b17c43c..7dc35bad 100644 --- a/subworkflows/nf-neuro/registration/meta.yml +++ b/subworkflows/nf-neuro/registration/meta.yml @@ -152,14 +152,14 @@ output: Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. pattern: "*__forward*.{nii,nii.gz,mat,lta}" - - out_segmentation: + - segmentation: type: file description: | ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) segmentation + parcellation in moving space (floating in Easyreg naming convention). pattern: "*.{nii,nii.gz}" optional: true - - out_ref_segmentation: + - ref_segmentation: type: file description: | ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) diff --git a/subworkflows/nf-neuro/registration/tests/ants.config b/subworkflows/nf-neuro/registration/tests/ants.config new file mode 100644 index 00000000..41e8cce8 --- /dev/null +++ b/subworkflows/nf-neuro/registration/tests/ants.config @@ -0,0 +1,17 @@ +process { + withName: "REGISTRATION_ANATTODWI" { + ext.run_qc = true + cpus = 1 + } + + withName: "REGISTRATION_ANTS" { + ext.quick = true + ext.repro_mode = true + ext.transform = "a" + ext.initial_transform = "intensities" + ext.run_qc = true + ext.random_seed = 44 + + cpus = 1 + } +} diff --git a/subworkflows/nf-neuro/registration/tests/nextflow_easyreg.config b/subworkflows/nf-neuro/registration/tests/easyreg.config similarity index 60% rename from subworkflows/nf-neuro/registration/tests/nextflow_easyreg.config rename to subworkflows/nf-neuro/registration/tests/easyreg.config index 694f85d8..448110a8 100644 --- a/subworkflows/nf-neuro/registration/tests/nextflow_easyreg.config +++ b/subworkflows/nf-neuro/registration/tests/easyreg.config @@ -1,6 +1,7 @@ process { withName: "REGISTRATION_EASYREG" { - ext.field = true + ext.affine_only = true + memory = '10G' } } diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test b/subworkflows/nf-neuro/registration/tests/main.nf.test index e3e9268d..677cb68a 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test @@ -19,22 +19,22 @@ nextflow_workflow { tag "load_test_data" tag "stub" - options "-stub-run" + //options "-stub-run" setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { script "../../load_test_data/main.nf" process { """ - input[0] = Channel.from( [ "T1w.zip", "b0.zip", "dti.zip" ] ) + input[0] = Channel.from( [ "freesurfer.zip", "T1w.zip", "b0.zip", "dti.zip", "others.zip" ] ) input[1] = "test.load-test-data" """ } } } - test("registration - antsRegistration") { - config "./nextflow_ants.config" + test("registration - ANTs - Anat to DWI") { + config "./ants.config" when { workflow { """ @@ -44,16 +44,16 @@ nextflow_workflow { b0: it.simpleName == "b0" dti: it.simpleName == "dti" } - input[0] = ch_split_test_data.t1w.map{ + input[0] = ch_split_test_data.b0.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/T1w.nii.gz") + file("\${test_data_directory}/b0.nii.gz") ] } - input[1] = ch_split_test_data.b0.map{ + input[1] = ch_split_test_data.t1w.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz") + file("\${test_data_directory}/T1w.nii.gz") ] } input[2] = ch_split_test_data.dti.map{ @@ -65,6 +65,7 @@ nextflow_workflow { input[3] = Channel.empty() input[4] = Channel.empty() input[5] = Channel.empty() + input[6] = Channel.empty() """ } } @@ -96,31 +97,35 @@ nextflow_workflow { } } - test("registration - SyNQuick") { - config "./nextflow_ants.config" + test("registration - ANTs - SyNQuick") { + config "./ants.config" when { workflow { """ ch_split_test_data = LOAD_DATA.out.test_data_directory .branch{ t1w: it.simpleName == "T1w" - b0: it.simpleName == "b0" - dti: it.simpleName == "dti" + moving: it.simpleName == "others" } input[0] = ch_split_test_data.t1w.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/T1w.nii.gz") ]} - input[1] = ch_split_test_data.b0.map{ + input[1] = ch_split_test_data.moving.map{ test_data_directory -> [ [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz") + file("\${test_data_directory}/t1.nii.gz") ]} input[2] = Channel.empty() - input[3] = Channel.empty() + input[3] = ch_split_test_data.t1w.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/T1w_mask.nii.gz") + ]} input[4] = Channel.empty() input[5] = Channel.empty() + input[6] = Channel.empty() """ } } @@ -152,56 +157,57 @@ nextflow_workflow { } } - test("registration - easyreg") { - config "./nextflow_easyreg.config" - when { - workflow { - """ - ch_split_test_data = LOAD_DATA.out.test_data_directory - .branch{ - t1w: it.simpleName == "T1w" - b0: it.simpleName == "b0" - dti: it.simpleName == "dti" - } - input[0] = ch_split_test_data.t1w.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/T1w.nii.gz") - ] - } - input[1] = ch_split_test_data.b0.map{ - test_data_directory -> [ - [ id:'test' ], - file("\${test_data_directory}/b0.nii.gz") - ] - } - input[2] = Channel.empty() - input[3] = Channel.empty() - input[4] = Channel.empty() - input[5] = Channel.empty() - """ - } - } + // test("registration - easyreg") { + // config "./easyreg.config" + // when { + // workflow { + // """ + // ch_split_test_data = LOAD_DATA.out.test_data_directory + // .branch{ + // t1w: it.simpleName == "T1w" + // b0: it.simpleName == "b0" + // } + // input[0] = ch_split_test_data.t1w.map{ + // test_data_directory -> [ + // [ id:'test' ], + // file("\${test_data_directory}/T1w.nii.gz") + // ] + // } + // input[1] = ch_split_test_data.b0.map{ + // test_data_directory -> [ + // [ id:'test' ], + // file("\${test_data_directory}/b0.nii.gz") + // ] + // } + // input[2] = Channel.empty() + // input[3] = Channel.empty() + // input[4] = Channel.empty() + // input[5] = Channel.empty() + // input[6] = Channel.empty() + // """ + // } + // } - then { - assertAll( - { assert workflow.success}, - { assert snapshot( - workflow.out - .findAll{ channel -> !channel.key.isInteger() && channel.value } - .collectEntries{ channel -> - [(channel.key): ["versions"].contains(channel.key) - ? channel.value - : channel.value.collect{ subject -> - [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } - } ] - } - ).match() } - ) - } - } - test("registration - synthregistration") { - config "./nextflow_synthregistration.config" + // then { + // assertAll( + // { assert workflow.success}, + // { assert snapshot( + // workflow.out + // .findAll{ channel -> !channel.key.isInteger() && channel.value } + // .collectEntries{ channel -> + // [(channel.key): ["versions"].contains(channel.key) + // ? channel.value + // : channel.value.collect{ subject -> + // [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } + // } ] + // } + // ).match() } + // ) + // } + // } + + test("registration - Synthmorph") { + config "./synthregistration.config" when { workflow { """ @@ -209,7 +215,7 @@ nextflow_workflow { .branch{ t1w: it.simpleName == "T1w" b0: it.simpleName == "b0" - dti: it.simpleName == "dti" + freesurfer: it.simpleName == "freesurfer" } input[0] = ch_split_test_data.t1w.map{ test_data_directory -> [ @@ -227,6 +233,9 @@ nextflow_workflow { input[3] = Channel.empty() input[4] = Channel.empty() input[5] = Channel.empty() + input[6] = ch_split_test_data.freesurfer.map{ + test_data_directory -> file("\${test_data_directory}/license.txt") + } """ } } diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 5a7ef622..3fbc9857 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "registration - synthregistration": { + "registration - Synthmorph": { "content": [ { "affine": [ @@ -7,7 +7,7 @@ { "id": "test" }, - "test__forward1_affine.lta" + "test__out_affine.txt" ] ], "image_transform": [ @@ -15,8 +15,7 @@ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.lta" + "test__out_affine.txt" ] ], "image_warped": [ @@ -32,7 +31,7 @@ { "id": "test" }, - "test__backward0_affine.lta" + "test__out_affine.txt" ] ], "inverse_image_transform": [ @@ -40,8 +39,7 @@ { "id": "test" }, - "test__backward0_affine.lta", - "test__backward1_warp.nii.gz" + "test__out_affine.txt" ] ], "inverse_tractogram_transform": [ @@ -49,16 +47,7 @@ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.lta" - ] - ], - "inverse_warp": [ - [ - { - "id": "test" - }, - "test__backward1_warp.nii.gz" + "test__out_affine.txt" ] ], "tractogram_transform": [ @@ -66,20 +55,12 @@ { "id": "test" }, - "test__backward0_affine.lta", - "test__backward1_warp.nii.gz" + "test__out_affine.txt" ] ], "versions": [ + "versions.yml:md5,5f2030eca02186c4f9b3e76425f94bf1", "versions.yml:md5,f0fa799dd0d27d1974ea409d9c9e5da7" - ], - "warp": [ - [ - { - "id": "test" - }, - "test__forward0_warp.nii.gz" - ] ] } ], @@ -87,73 +68,65 @@ "nf-test": "0.9.0", "nextflow": "25.04.6" }, - "timestamp": "2025-07-20T03:29:30.180373035" + "timestamp": "2025-07-28T15:34:09.121403461" }, - "registration - easyreg": { + "registration - ANTs - SyNQuick": { "content": [ { - "image_transform": [ - [ - { - "id": "test" - }, - "test_forward0_warp.nii.gz" - ] - ], - "image_warped": [ + "affine": [ [ { "id": "test" }, - "test_warped.nii.gz" + "test__forward1_affine.mat" ] ], - "inverse_image_transform": [ + "image_transform": [ [ { "id": "test" }, - "test_backward0_warp.nii.gz" + "test__forward1_affine.mat" ] ], - "inverse_tractogram_transform": [ + "image_warped": [ [ { "id": "test" }, - "test_forward0_warp.nii.gz" + "test__t1_warped.nii.gz" ] ], - "inverse_warp": [ + "inverse_affine": [ [ { "id": "test" }, - "test_backward0_warp.nii.gz" + "test__backward0_affine.mat" ] ], - "ref_segmentation": [ + "inverse_image_transform": [ [ { "id": "test" }, - "test_warped_reference_segmentation.nii.gz" + "test__backward0_affine.mat" ] ], - "ref_warped": [ + "inverse_tractogram_transform": [ [ { "id": "test" }, - "test_warped_reference.nii.gz" + "test__forward1_affine.mat" ] ], - "segmentation": [ + "mqc": [ [ { "id": "test" }, - "test_warped_segmentation.nii.gz" + "test__registration_ants_mqc.gif" ] ], "tractogram_transform": [ @@ -161,19 +134,11 @@ { "id": "test" }, - "test_backward0_warp.nii.gz" + "test__backward0_affine.mat" ] ], "versions": [ - "versions.yml:md5,3f38c911476c605480c02e484fcf6e9f" - ], - "warp": [ - [ - { - "id": "test" - }, - "test_forward0_warp.nii.gz" - ] + "versions.yml:md5,7b059759af9e9bd4711e94db65e61095" ] } ], @@ -183,7 +148,7 @@ }, "timestamp": "2025-09-20T13:03:27.206157" }, - "registration - antsRegistration": { + "registration - ANTs - Anat to DWI": { "content": [ { "affine": [ @@ -208,7 +173,7 @@ { "id": "test" }, - "test__b0_warped.nii.gz" + "test__T1w_warped.nii.gz" ] ], "inverse_affine": [ @@ -245,6 +210,14 @@ "test__backward1_warp.nii.gz" ] ], + "mqc": [ + [ + { + "id": "test" + }, + "test_registration_anattodwi_mqc.gif" + ] + ], "tractogram_transform": [ [ { diff --git a/subworkflows/nf-neuro/registration/tests/nextflow_ants.config b/subworkflows/nf-neuro/registration/tests/nextflow_ants.config deleted file mode 100644 index df0bf888..00000000 --- a/subworkflows/nf-neuro/registration/tests/nextflow_ants.config +++ /dev/null @@ -1,11 +0,0 @@ -process { - withName: "REGISTRATION_ANATTODWI" { - ext.cpus = 1 - } - - withName: "REGISTRATION_ANTS" { - ext.quick = true - ext.threads = 1 - ext.random_seed = 44 - } -} diff --git a/subworkflows/nf-neuro/registration/tests/nextflow_synthregistration.config b/subworkflows/nf-neuro/registration/tests/synthregistration.config similarity index 56% rename from subworkflows/nf-neuro/registration/tests/nextflow_synthregistration.config rename to subworkflows/nf-neuro/registration/tests/synthregistration.config index ec7d0967..6e825fd7 100644 --- a/subworkflows/nf-neuro/registration/tests/nextflow_synthregistration.config +++ b/subworkflows/nf-neuro/registration/tests/synthregistration.config @@ -1,9 +1,9 @@ process { withName: "REGISTRATION_SYNTHREGISTRATION" { - ext.affine = "affine" - ext.warp = "deform" - ext.lambda = 0.9 + ext.models = ["affine"] + ext.regularization = 0.9 ext.steps = 9 + ext.extent = 192 } } From 2a016a8dded48be5e260826ca832e3d4beeb1427 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Mon, 28 Jul 2025 16:05:46 +0000 Subject: [PATCH 08/37] enable full registration subworkflow in bundle_seg wuubworkflow --- modules/nf-neuro/bundle/recognize/main.nf | 6 ++ .../bundle/recognize/tests/main.nf.test.snap | 4 +- subworkflows/nf-neuro/bundle_seg/main.nf | 49 ++++++++------- subworkflows/nf-neuro/bundle_seg/meta.yml | 45 +++++++++---- .../nf-neuro/bundle_seg/tests/main.nf.test | 63 +++++++++++++++++-- .../bundle_seg/tests/main.nf.test.snap | 16 ++++- .../nf-neuro/bundle_seg/tests/nextflow.config | 4 +- .../bundle_seg/tests/synthregistration.config | 11 ++++ 8 files changed, 153 insertions(+), 45 deletions(-) create mode 100644 subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config diff --git a/modules/nf-neuro/bundle/recognize/main.nf b/modules/nf-neuro/bundle/recognize/main.nf index 4e7b9b88..9b0de3b1 100644 --- a/modules/nf-neuro/bundle/recognize/main.nf +++ b/modules/nf-neuro/bundle/recognize/main.nf @@ -23,6 +23,12 @@ process BUNDLE_RECOGNIZE { def rbx_processes = task.cpus ? "--processes " + task.cpus : "--processes 1" def outlier_alpha = task.ext.outlier_alpha ? "--alpha " + task.ext.outlier_alpha : "" """ + if [[ "$transform" == *.txt ]]; then + ConvertTransformFile 3 $transform transform.mat --convertToAffineType \ + && transform="transform.mat" \ + || echo "TXT transform file conversion failed, using original file." + fi + mkdir recobundles/ scil_tractogram_segment_with_bundleseg ${tractograms} ${config} ${directory}/ ${transform} --inverse --out_dir recobundles/ \ -v DEBUG $minimal_vote_ratio $seed $rbx_processes diff --git a/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap b/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap index 1bb32334..757f5948 100644 --- a/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap +++ b/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap @@ -24,7 +24,7 @@ "nf-test": "0.9.2", "nextflow": "25.04.7" }, - "timestamp": "2025-09-17T17:40:02.174844814" + "timestamp": "2025-07-28T16:02:34.519025132" }, "bundle - recognize - stub-run": { "content": [ @@ -74,6 +74,6 @@ "nf-test": "0.9.2", "nextflow": "25.04.7" }, - "timestamp": "2025-09-17T17:39:29.968449034" + "timestamp": "2025-07-28T16:01:58.07707728" } } diff --git a/subworkflows/nf-neuro/bundle_seg/main.nf b/subworkflows/nf-neuro/bundle_seg/main.nf index 08dbcefa..c07fa5d1 100644 --- a/subworkflows/nf-neuro/bundle_seg/main.nf +++ b/subworkflows/nf-neuro/bundle_seg/main.nf @@ -1,19 +1,20 @@ include { BUNDLE_RECOGNIZE } from '../../../modules/nf-neuro/bundle/recognize/main' +include { REGISTRATION_CONVERT } from '../../../modules/nf-neuro/registration/convert/main' include { REGISTRATION } from '../../../subworkflows/nf-neuro/registration/main' def fetch_bundleseg_atlas(atlasUrl, configUrl, dest) { - def atlas = new File("$dest/atlas.zip").withOutputStream { out -> + def atlas = new File("$dest/atlas.zip").withOutputStream{ out -> new URL(atlasUrl).withInputStream { from -> out << from; } } - def config = new File("$dest/config.zip").withOutputStream { out -> + def config = new File("$dest/config.zip").withOutputStream{ out -> new URL(configUrl).withInputStream { from -> out << from; } } def atlasFile = new java.util.zip.ZipFile("$dest/atlas.zip") - atlasFile.entries().each { it -> + atlasFile.entries().each{ it -> def path = java.nio.file.Paths.get("$dest/atlas/" + it.name) if(it.directory){ java.nio.file.Files.createDirectories(path) @@ -28,7 +29,7 @@ def fetch_bundleseg_atlas(atlasUrl, configUrl, dest) { } def configFile = new java.util.zip.ZipFile("$dest/config.zip") - configFile.entries().each { it -> + configFile.entries().each{ it -> def path = java.nio.file.Paths.get("$dest/config/" + it.name) if(it.directory){ java.nio.file.Files.createDirectories(path) @@ -44,20 +45,24 @@ def fetch_bundleseg_atlas(atlasUrl, configUrl, dest) { } workflow BUNDLE_SEG { - take: - ch_fa // channel: [ val(meta), [ fa ] ] - ch_tractogram // channel: [ val(meta), [ tractogram ] ] - + ch_fa // channel: [ val(meta), [ fa ] ] + ch_tractogram // channel: [ val(meta), [ tractogram ] ] + ch_freesurfer_license // channel: [ val(meta), path(fs_license) ] main: + if ( params.run_easyreg ) error "The BUNDLE_SEG workflow does not support the easyreg registration method." + if ( params.run_synthmorph ) { + ch_freesurfer_license.ifEmpty{ error "Synthmorph registration need a Freesurfer License to run." } + } + ch_versions = Channel.empty() // ** Setting up Atlas reference channels. ** // if ( params.atlas_directory ) { - atlas_anat = Channel.fromPath("$params.atlas_directory/atlas/mni_masked.nii.gz", checkIfExists: true, relative: true) - atlas_config = Channel.fromPath("$params.atlas_directory/config/config_fss_1.json", checkIfExists: true, relative: true) - atlas_average = Channel.fromPath("$params.atlas_directory/atlas/atlas/", checkIfExists: true, relative: true) + ch_atlas_anat = Channel.fromPath("$params.atlas_directory/atlas/mni_masked.nii.gz", checkIfExists: true, relative: true) + ch_atlas_config = Channel.fromPath("$params.atlas_directory/config/config_fss_1.json", checkIfExists: true, relative: true) + ch_atlas_average = Channel.fromPath("$params.atlas_directory/atlas/atlas/", checkIfExists: true, relative: true) } else { if ( !file("$workflow.workDir/atlas/mni_masked.nii.gz").exists() ) { @@ -67,35 +72,37 @@ workflow BUNDLE_SEG { "${workflow.workDir}/" ) } - atlas_anat = Channel.fromPath("$workflow.workDir/atlas/mni_masked.nii.gz") - atlas_config = Channel.fromPath("$workflow.workDir/config/config_fss_1.json") - atlas_average = Channel.fromPath("$workflow.workDir/atlas/atlas/") + ch_atlas_anat = Channel.fromPath("$workflow.workDir/atlas/mni_masked.nii.gz") + ch_atlas_config = Channel.fromPath("$workflow.workDir/config/config_fss_1.json") + ch_atlas_average = Channel.fromPath("$workflow.workDir/atlas/atlas/") } // ** Register the atlas to subject's space. Set up atlas file as moving image ** // // ** and subject anat as fixed image. ** // + ch_atlas_anat = ch_fa + .combine(ch_atlas_anat) + .map{ meta, _fa, anat -> [meta, anat] } + REGISTRATION( - atlas_anat, + ch_atlas_anat, ch_fa, Channel.empty(), Channel.empty(), Channel.empty(), - Channel.empty() + Channel.empty(), + ch_freesurfer_license ) ch_versions = ch_versions.mix(REGISTRATION.out.versions.first()) // ** Perform bundle recognition and segmentation ** // ch_recognize_bundle = ch_tractogram .join(REGISTRATION.out.affine) - .combine(atlas_config) - .combine(atlas_average) + .combine(ch_atlas_config) + .combine(ch_atlas_average) BUNDLE_RECOGNIZE ( ch_recognize_bundle ) ch_versions = ch_versions.mix(BUNDLE_RECOGNIZE.out.versions.first()) - - emit: bundles = BUNDLE_RECOGNIZE.out.bundles // channel: [ val(meta), [ bundles ] ] - versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/nf-neuro/bundle_seg/meta.yml b/subworkflows/nf-neuro/bundle_seg/meta.yml index dd033ce0..bf4020db 100644 --- a/subworkflows/nf-neuro/bundle_seg/meta.yml +++ b/subworkflows/nf-neuro/bundle_seg/meta.yml @@ -8,10 +8,19 @@ description: | Diffusion MRI. Cham: Springer Nature Switzerland (2023) --------- Steps -------------------- - Antomical Registration (ANTs) + Anatomical Registration (ANTs) Use the FA map from the subject to register the atlas anatomical file and compute the transformations. Bundle Recognition (scilpy) Perform bundle recognition and extraction using BundleSeg. + + --------- Experimental features ----- + !!! DISCLAIMER !!! + The following features are experimental and may not work as expected. While we run tests to ensure + computational stability of the subworkflow, we cannot guarantee the correctness of the results. + Anatomical Registration (SynthMorph) : params.run_synthmorph = true + Synthmorph is a machine learning-based registration method developed by the Freesurfer team. It is made + available in this subworkflow by the REGISTRATION subworkflow, please refer to its implementation for + more details. keywords: - BundleSeg - WM bundles @@ -20,6 +29,23 @@ keywords: components: - registration/ants - bundle/recognize +args: + - run_synthmorph: + type: boolean + description: "Run SynthMorph registration instead of ANTs." + default: false + - atlas_directory: + type: directory + default: "" + description: | + Use an alternative atlas to the default BundleSeg one available on Zenodo (https://zenodo.org/records/10103446). + The folder MUST follow this specific structure: + atlas_directory + ├── atlas + │ └── pop_average + ├── centroids + ├── *.json (config file) + └── *.{nii,nii.gz} (atlas anatomical file) input: - ch_fa: type: file @@ -34,19 +60,12 @@ input: The input channel containing the whole-brain tractogram to be segmented. Structure: [ val(meta), path(tractogram) ] pattern: "*.trk" - - atlas_directory: - type: directory + - ch_freesurfer_license: + type: file description: | - The input channel containing the atlas directory. The folder MUST follow this specific structure: - atlas_directory - ├── atlas - │ └── pop_average - ├── centroids - ├── *.json (config file) - └── *.{nii,nii.gz} (atlas anatomical file) - If no directory is provided, the subworkflow will automatically fetch the atlas archive available on - Zenodo (https://zenodo.org/records/10103446). - Structure: [ path(directory) ] + ONLY USED WITH SYNTHMORPH REGISTRATION. The input channel containing the Freesurfer license file. + Structure: [ val(meta), path(license) ] + pattern: "*.txt" output: - bundles: type: file diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test index 6f5314cd..6dd357c8 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test @@ -15,37 +15,90 @@ nextflow_workflow { tag "load_test_data" tag "stub" - options "-stub-run" + // options "-stub-run" setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { script "../../load_test_data/main.nf" process { """ - input[0] = Channel.from( [ "tracking.zip" ] ) + input[0] = Channel.from( [ "tracking.zip", "freesurfer.zip" ] ) input[1] = "test.load-test-data" """ } } } - test("rbx - base - no_atlas_folder") { + test("rbx - download atlas - ants registration") { + when { + workflow { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + tracking: it.simpleName == "tracking" + freesurfer: it.simpleName == "freesurfer" + } + input[0] = ch_split_test_data.tracking.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/fa.nii.gz") + ] + } + input[1] = ch_split_test_data.tracking.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/pft.trk") + ] + } + input[2] = Channel.empty() + """ + } + } + + then { + assertAll( + { assert workflow.success }, + { assert snapshot( + workflow.out + .findAll{ channel -> !channel.key.isInteger() && channel.value } + .collectEntries{ channel -> + [(channel.key): ["versions"].contains(channel.key) + ? channel.value + : channel.value.collect{ subject -> + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } + } ] + } + ).match() } + ) + } + } + + test("rbx - download atlas - synthmorph registration") { + config "./synthregistration.config" when { workflow { """ - input[0] = LOAD_DATA.out.test_data_directory.map{ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + tracking: it.simpleName == "tracking" + freesurfer: it.simpleName == "freesurfer" + } + input[0] = ch_split_test_data.tracking.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/fa.nii.gz") ] } - input[1] = LOAD_DATA.out.test_data_directory.map{ + input[1] = ch_split_test_data.tracking.map{ test_data_directory -> [ [ id:'test' ], file("\${test_data_directory}/pft.trk") ] } + input[2] = ch_split_test_data.freesurfer.map{ + test_data_directory -> file("\${test_data_directory}/license.txt") + } """ } } diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index 464b86db..506c5bb7 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "rbx - base - no_atlas_folder": { + "rbx - download atlas - synthmorph registration": { "content": [ { "0": [ @@ -37,7 +37,19 @@ { "id": "test" }, - "test__AF_L_cleaned.trk" + "test__AF_L_cleaned.trk", + "test__CC_Fr_1_cleaned.trk", + "test__CG_L_An_cleaned.trk", + "test__CG_L_cleaned.trk", + "test__FPT_R_Brainstem_cleaned.trk", + "test__FPT_R_cleaned.trk", + "test__ILF_R_cleaned.trk", + "test__MCP_cleaned.trk", + "test__POPT_R_Brainstem_cleaned.trk", + "test__POPT_R_cleaned.trk", + "test__PYT_R_cleaned.trk", + "test__SCP_R_cleaned.trk", + "test__SLF_R_cleaned.trk" ] ], "versions": [ diff --git a/subworkflows/nf-neuro/bundle_seg/tests/nextflow.config b/subworkflows/nf-neuro/bundle_seg/tests/nextflow.config index 2089b09d..45e1b42c 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/nextflow.config +++ b/subworkflows/nf-neuro/bundle_seg/tests/nextflow.config @@ -1,11 +1,11 @@ process { withName: "REGISTRATION_ANTS" { + publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.quick = true ext.threads = 1 ext.random_seed = 44 ext.repro_mode = 1 - ext.transform = "r" - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + ext.transform = "a" } withName: "BUNDLE_RECOGNIZE" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } diff --git a/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config b/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config new file mode 100644 index 00000000..1798856e --- /dev/null +++ b/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config @@ -0,0 +1,11 @@ +process { + withName: "REGISTRATION_SYNTHREGISTRATION" { + ext.models = ["affine"] + ext.regularization = 0.9 + ext.steps = 9 + ext.extent = 192 + memory = '2G' + } +} + +params.run_synthmorph = true From 125c6ffdb301284034b593a2278ec9af6bacb108 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Mon, 28 Jul 2025 17:32:42 +0000 Subject: [PATCH 09/37] switch for registration sbwf in output_template_space. test synthmorph with it --- .../nf-neuro/registration/tractogram/main.nf | 22 +++-- .../nf-neuro/registration/tractogram/meta.yml | 2 +- .../nf-neuro/output_template_space/main.nf | 15 ++- .../nf-neuro/output_template_space/meta.yml | 32 +++++- .../output_template_space/tests/local.config | 14 +++ .../output_template_space/tests/main.nf.test | 98 +++++++++++++++++-- .../tests/main.nf.test.snap | 8 +- .../tests/nextflow.config | 1 + .../tests/nextflow_local.config | 54 ---------- .../tests/synthmorph.config | 9 ++ subworkflows/nf-neuro/tractoflow/main.nf | 1 + 11 files changed, 178 insertions(+), 78 deletions(-) create mode 100644 subworkflows/nf-neuro/output_template_space/tests/local.config delete mode 100644 subworkflows/nf-neuro/output_template_space/tests/nextflow_local.config create mode 100644 subworkflows/nf-neuro/output_template_space/tests/synthmorph.config diff --git a/modules/nf-neuro/registration/tractogram/main.nf b/modules/nf-neuro/registration/tractogram/main.nf index a6a33153..80b96628 100644 --- a/modules/nf-neuro/registration/tractogram/main.nf +++ b/modules/nf-neuro/registration/tractogram/main.nf @@ -5,7 +5,7 @@ process REGISTRATION_TRACTOGRAM { container "scilus/scilpy:2.2.0_cpu" input: - tuple val(meta), path(anat), path(transfo), path(tractogram), path(ref) /* optional, input = [] */, path(deformation) /* optional, input = [] */ + tuple val(meta), path(anat), path(affine), path(tractogram), path(ref) /* optional, value = [] */, path(deformation) /* optional, value = [] */ output: tuple val(meta), path("*__*.{trk,tck}"), emit: warped_tractogram @@ -31,17 +31,25 @@ process REGISTRATION_TRACTOGRAM { def no_empty = task.ext.no_empty ? "--no_empty" : "" """ + affine=$affine + if [[ "$affine" == *.txt ]]; then + ConvertTransformFile 3 $affine affine.mat --convertToAffineType \ + && affine="affine.mat" \ + || echo "TXT affine transform file conversion failed, using original file." + fi + for tractogram in ${tractogram}; do \ ext=\${tractogram#*.} bname=\$(basename \${tractogram} .\${ext} | sed 's/${prefix}_\\+//') - scil_tractogram_apply_transform \$tractogram $anat $transfo tmp.trk\ - $in_deformation\ - $inverse\ - $reverse_operation\ - $force\ - $reference + scil_tractogram_apply_transform.py \$tractogram $anat \$affine \ + ${prefix}__\${bname}${suffix}.\${ext} \ + $in_deformation \ + $inverse \ + $reverse_operation \ + $force \ + $reference scil_tractogram_remove_invalid tmp.trk ${prefix}__\${bname}${suffix}.\${ext}\ $cut_invalid\ diff --git a/modules/nf-neuro/registration/tractogram/meta.yml b/modules/nf-neuro/registration/tractogram/meta.yml index 531df2b7..a23ae8b3 100644 --- a/modules/nf-neuro/registration/tractogram/meta.yml +++ b/modules/nf-neuro/registration/tractogram/meta.yml @@ -24,7 +24,7 @@ input: pattern: "*.{nii,nii.gz}" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - transfo: + - affine: type: file description: ANTs affine transform pattern: "*.mat" diff --git a/subworkflows/nf-neuro/output_template_space/main.nf b/subworkflows/nf-neuro/output_template_space/main.nf index d7a770d9..c20d4e75 100644 --- a/subworkflows/nf-neuro/output_template_space/main.nf +++ b/subworkflows/nf-neuro/output_template_space/main.nf @@ -18,7 +18,7 @@ workflow OUTPUT_TEMPLATE_SPACE { ch_mask_files // channel: [ val(meta), [ mask_files ] ] ch_labels_files // channel: [ val(meta), [ labels_files ] ] ch_trk_files // channel: [ val(meta), [ trk_files ] ] - + ch_freesurfer_license // channel: [ val(freesurfer_license) ] main: ch_versions = Channel.empty() @@ -138,14 +138,19 @@ workflow OUTPUT_TEMPLATE_SPACE { ch_template = ch_anat .map{ meta, _anat -> meta } .combine(params.use_template_t2w ? ch_t2w_tpl : ch_t1w_tpl) + + ch_brain_mask = ch_anat + .map{ meta, _anat -> meta } + .combine(ch_brain_mask.TRUE) // ** Register the subject to the template space ** // REGISTRATION( ch_anat, ch_template, Channel.empty(), + ch_brain_mask, Channel.empty(), Channel.empty(), - Channel.empty() + ch_freesurfer_license ) ch_versions = ch_versions.mix(REGISTRATION.out.versions) @@ -178,10 +183,10 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** Apply the transformation to the tractograms ** // ch_tractograms_to_transform = ch_trk_files .join(REGISTRATION.out.image_warped) - .join(REGISTRATION.out.tractogram_transform) - .map{ it[0..1] + it[2..-1].flatten() } + .join(REGISTRATION.out.inverse_affine) + .join(REGISTRATION.out.inverse_warp, remainder: true) .map{ meta, trk, image, affine, warp -> - tuple(meta, image, affine, trk, [], warp) + [meta, image, affine, trk, [], warp ?: []] } REGISTRATION_TRACTOGRAM ( ch_tractograms_to_transform ) diff --git a/subworkflows/nf-neuro/output_template_space/meta.yml b/subworkflows/nf-neuro/output_template_space/meta.yml index bf31c6b9..e7945009 100644 --- a/subworkflows/nf-neuro/output_template_space/meta.yml +++ b/subworkflows/nf-neuro/output_template_space/meta.yml @@ -15,7 +15,15 @@ description: | - params.template_cohort: the cohort of the template (e.g., 1) An example of how to set the module's ext.args can be find in the - `test/nextflow.config` file. + `test/nextflow.config` file. Additional configuration for local templates + are also available in the `test/local.config` file. + + To select the registration technique used to register the input files, use the + following parameters : + - params.run_easyreg : Use Easyreg any-to-any registration model + - params.run_synthmorph : Use Synthmorph ML registration model + + Refer to the `registration` subworkflow and the modules it uses for configuration options. keywords: - template - TemplateFlow @@ -27,6 +35,27 @@ components: - image/applymask - betcrop/fslbetcrop - utils/templateflow +args: + - template: + type: string + description: Name of the template to use (see https://templateflow.org). + - templateflow_home: + type: string + description: Path to the templateflow local home directory where files are located and/or downloaded. + - template_res: + type: int + description: Template resolution to use or download. + - template_cohort: + type: string + description: Name/type of the cohort to use. + - run_easyreg: + type: boolean + description: Use Easyreg any-to-any registration model. + default: false + - run_synthmorph: + type: boolean + description: Use Synthmorph ML registration model. + default: false input: - ch_anat: type: file @@ -103,5 +132,6 @@ output: pattern: "versions.yml" authors: - "@gagnonanthony" + - "@AlexVCaron" maintainers: - "@gagnonanthony" diff --git a/subworkflows/nf-neuro/output_template_space/tests/local.config b/subworkflows/nf-neuro/output_template_space/tests/local.config new file mode 100644 index 00000000..11936ca6 --- /dev/null +++ b/subworkflows/nf-neuro/output_template_space/tests/local.config @@ -0,0 +1,14 @@ +process { + withName: "BET_T1W" { + ext.bet_f = 0.6 + ext.crop = false + ext.dilate = false + } + withName: "BET_T2W" { + ext.bet_f = 0.6 + ext.crop = false + ext.dilate = false + } +} + +params.templateflow_home = "$launchDir/templateflow_home" diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test index 3ea559b9..f8556d77 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_workflow { name "Test Subworkflow OUTPUT_TEMPLATE_SPACE" script "../main.nf" workflow "OUTPUT_TEMPLATE_SPACE" + config "./nextflow.config" tag "subworkflows" tag "subworkflows_nfneuro" @@ -21,22 +22,22 @@ nextflow_workflow { tag "load_test_data" tag "stub" - options "-stub-run" + //options "-stub-run" setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { script "../../load_test_data/main.nf" process { """ - input[0] = Channel.from( [ "tractometry.zip" ] ) + input[0] = Channel.from( [ "tractometry.zip", "freesurfer.zip" ] ) input[1] = "test.load-test-data" """ } } } - test("output to template MNI152NLin2009cAsym with local folder") { - config "./nextflow_local.config" + test("Template MNI152NLin2009cAsym - local templates") { + config "./local.config" when { workflow { """ @@ -77,6 +78,7 @@ nextflow_workflow { ] ] } + input[5] = Channel.empty() """ } } @@ -115,8 +117,7 @@ nextflow_workflow { } } - test("output to template MNI152NLin2009aAsym - without brain mask") { - config "./nextflow.config" + test("Template MNI152NLin2009aAsym - no brain mask") { when { workflow { """ @@ -157,6 +158,91 @@ nextflow_workflow { ] ] } + input[5] = Channel.empty() + """ + } + } + then { + assertAll( + { assert workflow.success }, + { assert snapshot( + workflow.out + .findAll{ channel -> !channel.key.isInteger() && channel.value } + .collectEntries{ channel -> + [(channel.key): ["versions"].contains(channel.key) + ? channel.value + : channel.value.collect{ subject -> + ["ch_t1w_tpl", "ch_t2w_tpl"].contains(channel.key) + ? file(subject).name + : [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry + ? file(entry).name + : "" } + } ] + } + ).match()}, + { assert workflow.out + .findAll{ channel -> !channel.key.isInteger() } + .every{ channel -> ["ch_registered_anat", + "ch_t1w_tpl", + "ch_t2w_tpl", + "ch_warped_labels_files", + "ch_warped_nifti_files", + "ch_warped_trk_files", + "versions"].contains(channel.key) + ? channel.value.every{ subject -> subject instanceof ArrayList + ? subject.every() + : subject } + : channel.value.size() == 0 } } + ) + } + } + + test("Template MNI152NLin2009aAsym - using synthmorph registration") { + config "./synthmorph.config" + when { + workflow { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + tractometry: it.simpleName == "tractometry" + freesurfer: it.simpleName == "freesurfer" + } + input[0] = ch_split_test_data.tractometry.map{ + test_data_directory -> [ + [ id: 'test' ], // meta map + file("\${test_data_directory}/mni_masked.nii.gz") + ] + } + input[1] = ch_split_test_data.tractometry.map{ + test_data_directory -> [ + [ id: 'test' ], // meta map + [ + file("\${test_data_directory}/IFGWM.nii.gz") + ] + ] + } + input[2] = Channel.empty() + input[3] = ch_split_test_data.tractometry.map{ + test_data_directory -> [ + [ id: 'test' ], // meta map + [ + file("\${test_data_directory}/IFGWM_labels_map.nii.gz") + ] + ] + } + input[4] = ch_split_test_data.tractometry.map{ + test_data_directory -> [ + [ id: 'test' ], // meta map + [ + file("\${test_data_directory}/IFGWM.trk"), + file("\${test_data_directory}/IFGWM_color.trk"), + file("\${test_data_directory}/IFGWM_uni.trk") + ] + ] + } + input[5] = ch_split_test_data.freesurfer.map{ + test_data_directory -> file("\${test_data_directory}/license.txt") + } """ } } diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap index a6bd94b7..9c6c0482 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "output to template MNI152NLin2009aAsym - without brain mask": { + "Template MNI152NLin2009aAsym - using synthmorph registration": { "content": [ { "ch_registered_anat": [ @@ -7,7 +7,7 @@ { "id": "test" }, - "test__t1_warped.nii.gz" + "test__warped.nii.gz" ] ], "ch_t1w_tpl": [ @@ -59,7 +59,7 @@ }, "timestamp": "2025-10-17T17:39:24.646305544" }, - "output to template MNI152NLin2009cAsym with local folder": { + "Template MNI152NLin2009aAsym - no brain mask": { "content": [ { "ch_registered_anat": [ @@ -67,7 +67,7 @@ { "id": "test" }, - "test__t1_warped.nii.gz" + "test__template__image_bet_warped.nii.gz" ] ], "ch_t1w_tpl": [ diff --git a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config index f35f49f8..05b1f615 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config +++ b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config @@ -1,5 +1,6 @@ process { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + withName: "REGISTRATION_ANTS" { ext.repro_mode = 1 ext.transform = "s" diff --git a/subworkflows/nf-neuro/output_template_space/tests/nextflow_local.config b/subworkflows/nf-neuro/output_template_space/tests/nextflow_local.config deleted file mode 100644 index 856d8cae..00000000 --- a/subworkflows/nf-neuro/output_template_space/tests/nextflow_local.config +++ /dev/null @@ -1,54 +0,0 @@ -process { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - withName: "BET_T1W" { - ext.bet_f = 0.6 - ext.crop = false - ext.dilate = false - } - withName: "BET_T2W" { - ext.bet_f = 0.6 - ext.crop = false - ext.dilate = false - } - withName: "REGISTRATION_ANTS" { - ext.repro_mode = 1 - ext.transform = "s" - ext.quick = true - } - withName: "WARPIMAGES" { - ext.interpolation = "Linear" - ext.dimensionality = 3 - ext.image_type = 0 - ext.output_dtype = "float" - ext.default_val = 0 - } - withName: "WARPMASKS" { - ext.interpolation = "NearestNeighbor" - ext.dimensionality = 3 - ext.image_type = 1 - ext.output_dtype = "int" - ext.default_val = 0 - } - withName: "WARPLABELS" { - ext.interpolation = "NearestNeighbor" - ext.dimensionality = 3 - ext.image_type = 1 - ext.output_dtype = "int" - ext.default_val = 0 - } - withName: "REGISTRATION_TRACTOGRAM" { - ext.inverse = true - ext.force = true - ext.cut_invalid = true - ext.remove_single_point = true - ext.remove_overlapping_points = true - ext.threshold = 0.001 - ext.no_empty = true - } -} - -params.templateflow_home = "$launchDir/templateflow_home" -params.template = "MNI152NLin2009cAsym" -params.templateflow_res = 1 -params.templateflow_cohort = null -params.use_template_t2w = false diff --git a/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config b/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config new file mode 100644 index 00000000..2904d8a6 --- /dev/null +++ b/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config @@ -0,0 +1,9 @@ +process { + withName: "REGISTRATION_SYNTHREGISTRATION" { + ext.models = ["affine"] + ext.extent = 192 + memory = "10G" + } +} + +params.run_synthmorph = true diff --git a/subworkflows/nf-neuro/tractoflow/main.nf b/subworkflows/nf-neuro/tractoflow/main.nf index 09694894..b19e3ca8 100644 --- a/subworkflows/nf-neuro/tractoflow/main.nf +++ b/subworkflows/nf-neuro/tractoflow/main.nf @@ -98,6 +98,7 @@ workflow TRACTOFLOW { RECONST_DTIMETRICS.out.fa, Channel.empty(), Channel.empty(), + Channel.empty(), Channel.empty() ) ch_versions = ch_versions.mix(T1_REGISTRATION.out.versions.first()) From 84bfdeaa4f7a80bad0cf56a096a44c9dcba3daa5 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Tue, 29 Jul 2025 01:53:48 +0000 Subject: [PATCH 10/37] lint subworkflows --- subworkflows/nf-neuro/bundle_seg/main.nf | 7 +- subworkflows/nf-neuro/bundle_seg/meta.yml | 15 ++- .../nf-neuro/bundle_seg/tests/main.nf.test | 2 +- .../bundle_seg/tests/main.nf.test.snap | 4 +- .../nf-neuro/output_template_space/main.nf | 15 ++- .../nf-neuro/output_template_space/meta.yml | 38 +++++++- .../output_template_space/tests/main.nf.test | 37 ++++---- .../tests/main.nf.test.snap | 58 ++++++++---- .../tests/nextflow.config | 4 + subworkflows/nf-neuro/registration/meta.yml | 11 +++ .../nf-neuro/registration/tests/main.nf.test | 94 +++++++++---------- .../registration/tests/main.nf.test.snap | 94 +++++++++++++++++++ 12 files changed, 278 insertions(+), 101 deletions(-) diff --git a/subworkflows/nf-neuro/bundle_seg/main.nf b/subworkflows/nf-neuro/bundle_seg/main.nf index c07fa5d1..ef6128cd 100644 --- a/subworkflows/nf-neuro/bundle_seg/main.nf +++ b/subworkflows/nf-neuro/bundle_seg/main.nf @@ -1,7 +1,6 @@ include { BUNDLE_RECOGNIZE } from '../../../modules/nf-neuro/bundle/recognize/main' -include { REGISTRATION_CONVERT } from '../../../modules/nf-neuro/registration/convert/main' -include { REGISTRATION } from '../../../subworkflows/nf-neuro/registration/main' +include { REGISTRATION } from '../registration/main' def fetch_bundleseg_atlas(atlasUrl, configUrl, dest) { @@ -50,13 +49,13 @@ workflow BUNDLE_SEG { ch_tractogram // channel: [ val(meta), [ tractogram ] ] ch_freesurfer_license // channel: [ val(meta), path(fs_license) ] main: - if ( params.run_easyreg ) error "The BUNDLE_SEG workflow does not support the easyreg registration method." if ( params.run_synthmorph ) { ch_freesurfer_license.ifEmpty{ error "Synthmorph registration need a Freesurfer License to run." } } ch_versions = Channel.empty() + ch_mqc = Channel.empty() // ** Setting up Atlas reference channels. ** // if ( params.atlas_directory ) { @@ -93,6 +92,7 @@ workflow BUNDLE_SEG { ch_freesurfer_license ) ch_versions = ch_versions.mix(REGISTRATION.out.versions.first()) + ch_mqc = ch_mqc.mix(REGISTRATION.out.mqc) // ** Perform bundle recognition and segmentation ** // ch_recognize_bundle = ch_tractogram @@ -104,5 +104,6 @@ workflow BUNDLE_SEG { ch_versions = ch_versions.mix(BUNDLE_RECOGNIZE.out.versions.first()) emit: bundles = BUNDLE_RECOGNIZE.out.bundles // channel: [ val(meta), [ bundles ] ] + mqc = ch_mqc // channel: [ *mqc.* ] versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/nf-neuro/bundle_seg/meta.yml b/subworkflows/nf-neuro/bundle_seg/meta.yml index bf4020db..28912faf 100644 --- a/subworkflows/nf-neuro/bundle_seg/meta.yml +++ b/subworkflows/nf-neuro/bundle_seg/meta.yml @@ -19,7 +19,7 @@ description: | computational stability of the subworkflow, we cannot guarantee the correctness of the results. Anatomical Registration (SynthMorph) : params.run_synthmorph = true Synthmorph is a machine learning-based registration method developed by the Freesurfer team. It is made - available in this subworkflow by the REGISTRATION subworkflow, please refer to its implementation for + available in this subworkflow by the REGISTRATION subworkflow, please refer to its documentation for more details. keywords: - BundleSeg @@ -27,8 +27,8 @@ keywords: - Tractogram - Segmentation components: - - registration/ants - bundle/recognize + - registration args: - run_synthmorph: type: boolean @@ -54,18 +54,21 @@ input: space and the subject's space. Structure: [ val(meta), path(fa) ] pattern: "*.{nii,nii.gz}" + mandatory: true - ch_tractogram: type: file description: | The input channel containing the whole-brain tractogram to be segmented. Structure: [ val(meta), path(tractogram) ] pattern: "*.trk" + mandatory: true - ch_freesurfer_license: type: file description: | ONLY USED WITH SYNTHMORPH REGISTRATION. The input channel containing the Freesurfer license file. Structure: [ val(meta), path(license) ] pattern: "*.txt" + mandatory: false output: - bundles: type: file @@ -73,6 +76,13 @@ output: Channel containing all the segmented bundle files. Structure: [ val(meta), path(bundles) ] pattern: "*.trk" + - mqc: + type: file + description: | + Channel containing QC data for MultiQC reports. + Structure: [ *mqc.* ] + pattern: "*mqc.*" + optional: true - versions: type: file description: | @@ -81,5 +91,6 @@ output: pattern: "versions.yml" authors: - "@gagnonanthony" + - "@AlexVCaron" maintainers: - "@gagnonanthony" diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test index 6dd357c8..3ad0e082 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test @@ -8,9 +8,9 @@ nextflow_workflow { tag "subworkflows" tag "subworkflows_nfneuro" tag "subworkflows/bundle_seg" + tag "subworkflows/registration" tag "bundle/recognize" - tag "registration/ants" tag "load_test_data" diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index 506c5bb7..72fbbce4 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -37,17 +37,15 @@ { "id": "test" }, - "test__AF_L_cleaned.trk", "test__CC_Fr_1_cleaned.trk", "test__CG_L_An_cleaned.trk", "test__CG_L_cleaned.trk", + "test__FPT_L_cleaned.trk", "test__FPT_R_Brainstem_cleaned.trk", "test__FPT_R_cleaned.trk", - "test__ILF_R_cleaned.trk", "test__MCP_cleaned.trk", "test__POPT_R_Brainstem_cleaned.trk", "test__POPT_R_cleaned.trk", - "test__PYT_R_cleaned.trk", "test__SCP_R_cleaned.trk", "test__SLF_R_cleaned.trk" ] diff --git a/subworkflows/nf-neuro/output_template_space/main.nf b/subworkflows/nf-neuro/output_template_space/main.nf index c20d4e75..b2ede8d8 100644 --- a/subworkflows/nf-neuro/output_template_space/main.nf +++ b/subworkflows/nf-neuro/output_template_space/main.nf @@ -22,6 +22,7 @@ workflow OUTPUT_TEMPLATE_SPACE { main: ch_versions = Channel.empty() + ch_mqc = Channel.empty() // ** First, let's assess if the desired template exists in ** // // ** the templateflow home directory (user-specified as params. ** // @@ -42,6 +43,7 @@ workflow OUTPUT_TEMPLATE_SPACE { params.templateflow_cohort != null ? params.templateflow_cohort : [] ] ) + // TODO: look into adding metadata and citations to MultiQC report ch_versions = ch_versions.mix(UTILS_TEMPLATEFLOW.out.versions) // ** Setting outputs ** // @@ -153,6 +155,7 @@ workflow OUTPUT_TEMPLATE_SPACE { ch_freesurfer_license ) ch_versions = ch_versions.mix(REGISTRATION.out.versions) + ch_mqc = ch_mqc.mix(REGISTRATION.out.mqc) // ** Apply the transformation to all files ** // // ** The channel ch_nifti_files contains all the files that ** // @@ -165,6 +168,7 @@ workflow OUTPUT_TEMPLATE_SPACE { WARPIMAGES ( ch_files_to_transform ) ch_versions = ch_versions.mix(WARPIMAGES.out.versions) + ch_mqc = ch_mqc.mix(WARPIMAGES.out.mqc) // ** Same process for the masks ** // ch_masks_to_transform = ch_mask_files @@ -172,6 +176,7 @@ workflow OUTPUT_TEMPLATE_SPACE { .join(REGISTRATION.out.image_transform) WARPMASK ( ch_masks_to_transform ) ch_versions = ch_versions.mix(WARPMASK.out.versions) + ch_mqc = ch_mqc.mix(WARPMASK.out.mqc) // ** Same process for the labels ** // ch_labels_to_transform = ch_labels_files @@ -179,6 +184,7 @@ workflow OUTPUT_TEMPLATE_SPACE { .join(REGISTRATION.out.image_transform) WARPLABELS ( ch_labels_to_transform ) ch_versions = ch_versions.mix(WARPLABELS.out.versions) + ch_mqc = ch_mqc.mix(WARPLABELS.out.mqc) // ** Apply the transformation to the tractograms ** // ch_tractograms_to_transform = ch_trk_files @@ -196,10 +202,11 @@ workflow OUTPUT_TEMPLATE_SPACE { ch_t1w_tpl = ch_t1w_tpl // channel: [ tpl-T1w ] ch_t2w_tpl = ch_t2w_tpl // channel: [ tpl-T2w ] ch_registered_anat = REGISTRATION.out.image_warped // channel: [ val(meta), [ image ] ] - ch_warped_nifti_files = WARPIMAGES.out.warped_image // channel: [ val(meta), [ warped_image ] ] - ch_warped_mask_files = WARPMASK.out.warped_image // channel: [ val(meta), [ warped_mask ] ] - ch_warped_labels_files = WARPLABELS.out.warped_image // channel: [ val(meta), [ warped_labels ] ] - ch_warped_trk_files = REGISTRATION_TRACTOGRAM.out.warped_tractogram // channel: [ val(meta), [ warped_tractogram ] ] + ch_registered_nifti_files = WARPIMAGES.out.warped_image // channel: [ val(meta), [ warped_image ] ] + ch_registered_mask_files = WARPMASK.out.warped_image // channel: [ val(meta), [ warped_mask ] ] + ch_registered_labels_files = WARPLABELS.out.warped_image // channel: [ val(meta), [ warped_labels ] ] + ch_registered_trk_files = REGISTRATION_TRACTOGRAM.out.warped_tractogram // channel: [ val(meta), [ warped_tractogram ] ] + mqc = ch_mqc // channel: [ mqc ] versions = ch_versions // channel: [ versions.yml ] } diff --git a/subworkflows/nf-neuro/output_template_space/meta.yml b/subworkflows/nf-neuro/output_template_space/meta.yml index e7945009..d51801fc 100644 --- a/subworkflows/nf-neuro/output_template_space/meta.yml +++ b/subworkflows/nf-neuro/output_template_space/meta.yml @@ -29,12 +29,12 @@ keywords: - TemplateFlow - registration components: - - registration/ants - registration/antsapplytransforms - registration/tractogram - image/applymask - betcrop/fslbetcrop - utils/templateflow + - registration args: - template: type: string @@ -93,6 +93,13 @@ input: Structure: [ val(meta), [path(trk1), path(trk2), path(trk3), ...] ] pattern: "*.trk" mandatory: false + - ch_freesurfer_license: + type: file + description: | + ONLY USED WITH SYNTHMORPH REGISTRATION. The input channel containing the Freesurfer license file. + Structure: [ val(meta), path(license) ] + pattern: "*.txt" + mandatory: false output: - ch_t1w_tpl: type: file @@ -109,21 +116,44 @@ output: - ch_registered_anat: type: file description: | - Channel containing the registered anatomical image into the template space. + Channel containing the anatomical image registered into the template space. Structure: [ val(meta), path(anat) ] pattern: "*.{nii,nii.gz}" - ch_registered_nifti_files: type: file description: | - Channel containing the registered NIfTI files into the template space. + Channel containing the NIfTI files registered into the template space. Structure: [ val(meta), [path(nifti1), path(nifti2), path(nifti3), ...] ] pattern: "*.{nii,nii.gz}" + optional: true + - ch_registered_mask_files: + type: file + description: | + Channel containing the mask files registered into the template space. + Structure: [ val(meta), [path(mask1), path(mask2), path(mask3), ...] ] + pattern: "*.{nii,nii.gz}" + optional: true + - ch_registered_labels_files: + type: file + description: | + Channel containing the label files registered into the template space. + Structure: [ val(meta), [path(label1), path(label2), path(label3), ...] ] + pattern: "*.{nii,nii.gz}" + optional: true - ch_registered_trk_files: type: file description: | - Channel containing the registered TRK files into the template space. + Channel containing the TRK files registered into the template space. Structure: [ val(meta), [path(trk1), path(trk2), path(trk3), ...] ] pattern: "*.trk" + optional: true + - mqc: + type: file + description: | + Channel containing the MultiQC report of the registration. + Structure: [ path(mqc) ] + pattern: "*mqc.*" + optional: true - versions: type: file description: | diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test index f8556d77..34ac8759 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test @@ -8,18 +8,14 @@ nextflow_workflow { tag "subworkflows" tag "subworkflows_nfneuro" tag "subworkflows/output_template_space" + tag "subworkflows/registration" + tag "load_test_data" - tag "registration" - tag "registration/ants" tag "registration/antsapplytransforms" tag "registration/tractogram" - tag "image" tag "image/applymask" - tag "betcrop" tag "betcrop/fslbetcrop" - tag "utils" tag "utils/templateflow" - tag "load_test_data" tag "stub" //options "-stub-run" @@ -102,12 +98,13 @@ nextflow_workflow { ).match()}, { assert workflow.out .findAll{ channel -> !channel.key.isInteger() } - .every{ channel -> ["ch_registered_anat", - "ch_t1w_tpl", + .every{ channel -> ["ch_t1w_tpl", "ch_t2w_tpl", - "ch_warped_labels_files", - "ch_warped_nifti_files", - "ch_warped_trk_files", + "ch_registered_anat", + "ch_registered_labels_files", + "ch_registered_nifti_files", + "ch_registered_trk_files", + "mqc", "versions"].contains(channel.key) ? channel.value.every{ subject -> subject instanceof ArrayList ? subject.every() @@ -182,12 +179,13 @@ nextflow_workflow { ).match()}, { assert workflow.out .findAll{ channel -> !channel.key.isInteger() } - .every{ channel -> ["ch_registered_anat", - "ch_t1w_tpl", + .every{ channel -> ["ch_t1w_tpl", "ch_t2w_tpl", - "ch_warped_labels_files", - "ch_warped_nifti_files", - "ch_warped_trk_files", + "ch_registered_anat", + "ch_registered_labels_files", + "ch_registered_nifti_files", + "ch_registered_trk_files", + "mqc", "versions"].contains(channel.key) ? channel.value.every{ subject -> subject instanceof ArrayList ? subject.every() @@ -269,9 +267,10 @@ nextflow_workflow { .every{ channel -> ["ch_registered_anat", "ch_t1w_tpl", "ch_t2w_tpl", - "ch_warped_labels_files", - "ch_warped_nifti_files", - "ch_warped_trk_files", + "ch_registered_labels_files", + "ch_registered_nifti_files", + "ch_registered_trk_files", + "mqc", "versions"].contains(channel.key) ? channel.value.every{ subject -> subject instanceof ArrayList ? subject.every() diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap index 9c6c0482..d10bdcbe 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap @@ -10,13 +10,7 @@ "test__warped.nii.gz" ] ], - "ch_t1w_tpl": [ - "template__image_bet.nii.gz" - ], - "ch_t2w_tpl": [ - "template__image_bet.nii.gz" - ], - "ch_warped_labels_files": [ + "ch_registered_labels_files": [ [ { "id": "test" @@ -24,7 +18,7 @@ "test__IFGWM_labels_map__warped.nii.gz" ] ], - "ch_warped_nifti_files": [ + "ch_registered_nifti_files": [ [ { "id": "test" @@ -32,7 +26,7 @@ "test__IFGWM__warped.nii.gz" ] ], - "ch_warped_trk_files": [ + "ch_registered_trk_files": [ [ { "id": "test" @@ -42,6 +36,20 @@ "test__IFGWM_uni.trk" ] ], + "ch_t1w_tpl": [ + "template__image_bet.nii.gz" + ], + "ch_t2w_tpl": [ + "template__image_bet.nii.gz" + ], + "mqc": [ + [ + { + "id": "test" + }, + "test_IFGWM_registration_antsapplytransforms_mqc.gif" + ] + ], "versions": [ "versions.yml:md5,08c023826481c9130c3914096cda7f63", "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", @@ -70,13 +78,7 @@ "test__template__image_bet_warped.nii.gz" ] ], - "ch_t1w_tpl": [ - "template__image_bet.nii.gz" - ], - "ch_t2w_tpl": [ - "template__image_bet.nii.gz" - ], - "ch_warped_labels_files": [ + "ch_registered_labels_files": [ [ { "id": "test" @@ -84,7 +86,7 @@ "test__IFGWM_labels_map__warped.nii.gz" ] ], - "ch_warped_nifti_files": [ + "ch_registered_nifti_files": [ [ { "id": "test" @@ -92,7 +94,7 @@ "test__IFGWM__warped.nii.gz" ] ], - "ch_warped_trk_files": [ + "ch_registered_trk_files": [ [ { "id": "test" @@ -102,6 +104,26 @@ "test__IFGWM_uni.trk" ] ], + "ch_t1w_tpl": [ + "template__image_bet.nii.gz" + ], + "ch_t2w_tpl": [ + "template__image_bet.nii.gz" + ], + "mqc": [ + [ + { + "id": "test" + }, + "test_IFGWM_registration_antsapplytransforms_mqc.gif" + ], + [ + { + "id": "test" + }, + "test__registration_ants_mqc.gif" + ] + ], "versions": [ "versions.yml:md5,08c023826481c9130c3914096cda7f63", "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", diff --git a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config index 05b1f615..28420258 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config +++ b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config @@ -5,6 +5,7 @@ process { ext.repro_mode = 1 ext.transform = "s" ext.quick = true + ext.run_qc = true } withName: "WARPIMAGES" { ext.interpolation = "Linear" @@ -12,6 +13,7 @@ process { ext.image_type = 0 ext.output_dtype = "float" ext.default_val = 0 + ext.run_qc = true } withName: "WARPMASKS" { ext.interpolation = "NearestNeighbor" @@ -19,6 +21,7 @@ process { ext.image_type = 1 ext.output_dtype = "int" ext.default_val = 0 + ext.run_qc = true } withName: "WARPLABELS" { ext.interpolation = "NearestNeighbor" @@ -26,6 +29,7 @@ process { ext.image_type = 1 ext.output_dtype = "int" ext.default_val = 0 + ext.run_qc = true } withName: "REGISTRATION_TRACTOGRAM" { ext.inverse = true diff --git a/subworkflows/nf-neuro/registration/meta.yml b/subworkflows/nf-neuro/registration/meta.yml index 7dc35bad..dacd7b5a 100644 --- a/subworkflows/nf-neuro/registration/meta.yml +++ b/subworkflows/nf-neuro/registration/meta.yml @@ -115,12 +115,14 @@ output: Channel containing the forward deformation field file. Structure: [ val(meta), path(warp) ] pattern: "*__forward*.{nii,nii.gz}" + optional: true - inverse_warp: type: file description: | Channel containing the inverse deformation field file. Structure: [ val(meta), path(inverse_warp) ] pattern: "*__backward*.{nii,nii.gz}" + optional: true - inverse_affine: type: file description: | @@ -157,6 +159,7 @@ output: description: | ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) segmentation + parcellation in moving space (floating in Easyreg naming convention). + Structure: [ val(meta), path(segmentation) ] pattern: "*.{nii,nii.gz}" optional: true - ref_segmentation: @@ -164,8 +167,16 @@ output: description: | ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) segmentation + parcellation in fixed space (reference in Easyreg naming convention). + Structure: [ val(meta), path(ref_segmentation) ] pattern: "*.{nii,nii.gz}" optional: true + - mqc: + type: file + description: | + Channel containing the MultiQC report data for the registration. + Structure: [ path(mqc) ] + pattern: "*mqc.*" + optional: true - versions: type: file description: | diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test b/subworkflows/nf-neuro/registration/tests/main.nf.test index 677cb68a..9c77ee83 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test @@ -157,54 +157,54 @@ nextflow_workflow { } } - // test("registration - easyreg") { - // config "./easyreg.config" - // when { - // workflow { - // """ - // ch_split_test_data = LOAD_DATA.out.test_data_directory - // .branch{ - // t1w: it.simpleName == "T1w" - // b0: it.simpleName == "b0" - // } - // input[0] = ch_split_test_data.t1w.map{ - // test_data_directory -> [ - // [ id:'test' ], - // file("\${test_data_directory}/T1w.nii.gz") - // ] - // } - // input[1] = ch_split_test_data.b0.map{ - // test_data_directory -> [ - // [ id:'test' ], - // file("\${test_data_directory}/b0.nii.gz") - // ] - // } - // input[2] = Channel.empty() - // input[3] = Channel.empty() - // input[4] = Channel.empty() - // input[5] = Channel.empty() - // input[6] = Channel.empty() - // """ - // } - // } + test("registration - easyreg") { + config "./easyreg.config" + when { + workflow { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + t1w: it.simpleName == "T1w" + b0: it.simpleName == "b0" + } + input[0] = ch_split_test_data.t1w.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/T1w.nii.gz") + ] + } + input[1] = ch_split_test_data.b0.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/b0.nii.gz") + ] + } + input[2] = Channel.empty() + input[3] = Channel.empty() + input[4] = Channel.empty() + input[5] = Channel.empty() + input[6] = Channel.empty() + """ + } + } - // then { - // assertAll( - // { assert workflow.success}, - // { assert snapshot( - // workflow.out - // .findAll{ channel -> !channel.key.isInteger() && channel.value } - // .collectEntries{ channel -> - // [(channel.key): ["versions"].contains(channel.key) - // ? channel.value - // : channel.value.collect{ subject -> - // [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } - // } ] - // } - // ).match() } - // ) - // } - // } + then { + assertAll( + { assert workflow.success}, + { assert snapshot( + workflow.out + .findAll{ channel -> !channel.key.isInteger() && channel.value } + .collectEntries{ channel -> + [(channel.key): ["versions"].contains(channel.key) + ? channel.value + : channel.value.collect{ subject -> + [ subject[0] ] + subject[1..-1].flatten().collect{ entry -> entry ? file(entry).name : "" } + } ] + } + ).match() } + ) + } + } test("registration - Synthmorph") { config "./synthregistration.config" diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 3fbc9857..336e1b66 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -70,6 +70,100 @@ }, "timestamp": "2025-07-28T15:34:09.121403461" }, + "registration - easyreg": { + "content": [ + { + "image_transform": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz" + ] + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test_warped.nii.gz" + ] + ], + "inverse_image_transform": [ + [ + { + "id": "test" + }, + "test_backward0_warp.nii.gz" + ] + ], + "inverse_tractogram_transform": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz" + ] + ], + "inverse_warp": [ + [ + { + "id": "test" + }, + "test_backward0_warp.nii.gz" + ] + ], + "ref_segmentation": [ + [ + { + "id": "test" + }, + "test__warped_reference_segmentation.nii.gz" + ] + ], + "ref_warped": [ + [ + { + "id": "test" + }, + "test_warped_reference.nii.gz" + ] + ], + "segmentation": [ + [ + { + "id": "test" + }, + "test__warped_segmentation.nii.gz" + ] + ], + "tractogram_transform": [ + [ + { + "id": "test" + }, + "test_backward0_warp.nii.gz" + ] + ], + "versions": [ + "versions.yml:md5,3f38c911476c605480c02e484fcf6e9f" + ], + "warp": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "25.04.6" + }, + "timestamp": "2025-07-29T01:50:43.433891046" + }, "registration - ANTs - SyNQuick": { "content": [ { From 6eaab677d303ecb28140436800e7c836fb972051 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Tue, 29 Jul 2025 02:14:14 +0000 Subject: [PATCH 11/37] lint modules --- .../nf-neuro/registration/tractogram/main.nf | 8 ++-- .../nf-neuro/registration/tractogram/meta.yml | 42 ++++++++++++++++++- .../nf-neuro/output_template_space/main.nf | 18 ++++---- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/modules/nf-neuro/registration/tractogram/main.nf b/modules/nf-neuro/registration/tractogram/main.nf index 80b96628..bc8c02bd 100644 --- a/modules/nf-neuro/registration/tractogram/main.nf +++ b/modules/nf-neuro/registration/tractogram/main.nf @@ -5,10 +5,10 @@ process REGISTRATION_TRACTOGRAM { container "scilus/scilpy:2.2.0_cpu" input: - tuple val(meta), path(anat), path(affine), path(tractogram), path(ref) /* optional, value = [] */, path(deformation) /* optional, value = [] */ + tuple val(meta), path(anat), path(affine), path(tractogram), path(ref), path(deformation) output: - tuple val(meta), path("*__*.{trk,tck}"), emit: warped_tractogram + tuple val(meta), path("*__*.{trk,tck}"), emit: tractogram path "versions.yml" , emit: versions when: @@ -22,7 +22,6 @@ process REGISTRATION_TRACTOGRAM { def inverse = task.ext.inverse ? "--inverse" : "" def reverse_operation = task.ext.reverse_operation ? "--reverse_operation" : "" - def force = task.ext.force ? "-f" : "" def cut_invalid = task.ext.cut_invalid ? "--cut_invalid" : "" def remove_single_point = task.ext.remove_single_point ? "--remove_single_point" : "" @@ -48,8 +47,7 @@ process REGISTRATION_TRACTOGRAM { $in_deformation \ $inverse \ $reverse_operation \ - $force \ - $reference + $reference -f scil_tractogram_remove_invalid tmp.trk ${prefix}__\${bname}${suffix}.\${ext}\ $cut_invalid\ diff --git a/modules/nf-neuro/registration/tractogram/meta.yml b/modules/nf-neuro/registration/tractogram/meta.yml index a23ae8b3..452e9fbb 100644 --- a/modules/nf-neuro/registration/tractogram/meta.yml +++ b/modules/nf-neuro/registration/tractogram/meta.yml @@ -12,6 +12,41 @@ tools: toolbox. homepage: https://github.com/scilus/scilpy.git identifier: "" +args: + - inverse: + type: boolean + description: | + If true, the inverse affine transform will be applied to the tractogram. + default: false + - reverse_operation: + type: boolean + description: | + If true, applies affine and deformation in reverse order (deformation first). + default: false + - cut_invalid: + type: boolean + description: | + Cut invalid streamlines after applying the transform rather than removing them. + default: false + - remove_single_point: + type: boolean + description: | + If true, removes single-point streamlines after applying the transform. + default: false + - remove_overlapping_points: + type: boolean + description: | + If true, remove streamlines with overlapping points after applying the transform. + default: false + - no_empty: + type: boolean + description: Don't save empty tractograms. + default: false + - threshold: + type: float + description: | + Maximum distance between two points to be considered overlapping, in mm. + default: 0.001 input: - - meta: type: map @@ -22,32 +57,37 @@ input: type: file description: FA nifti format as anatomical image pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - affine: type: file description: ANTs affine transform pattern: "*.mat" + mandatory: true ontologies: [] - tractogram: type: file description: Tractogram or list of tractograms to register pattern: "*.{trk,tck}" + mandatory: true ontologies: [] - ref: type: file description: Reference anatomy for tck/vtk/fib/dpy file support (.nii or .nii.gz) (optional) pattern: "*.{tck,vtk,fib,dpy}" + mandatory: false ontologies: [] - deformation: type: file description: Path to the file containing a deformation field (optional) pattern: "*.{nii,nii.gz}" + mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format output: - warped_tractogram: + tractogram: - - meta: type: map description: | diff --git a/subworkflows/nf-neuro/output_template_space/main.nf b/subworkflows/nf-neuro/output_template_space/main.nf index b2ede8d8..81b1f6c1 100644 --- a/subworkflows/nf-neuro/output_template_space/main.nf +++ b/subworkflows/nf-neuro/output_template_space/main.nf @@ -199,14 +199,14 @@ workflow OUTPUT_TEMPLATE_SPACE { ch_versions = ch_versions.mix(REGISTRATION_TRACTOGRAM.out.versions) emit: - ch_t1w_tpl = ch_t1w_tpl // channel: [ tpl-T1w ] - ch_t2w_tpl = ch_t2w_tpl // channel: [ tpl-T2w ] - ch_registered_anat = REGISTRATION.out.image_warped // channel: [ val(meta), [ image ] ] - ch_registered_nifti_files = WARPIMAGES.out.warped_image // channel: [ val(meta), [ warped_image ] ] - ch_registered_mask_files = WARPMASK.out.warped_image // channel: [ val(meta), [ warped_mask ] ] - ch_registered_labels_files = WARPLABELS.out.warped_image // channel: [ val(meta), [ warped_labels ] ] - ch_registered_trk_files = REGISTRATION_TRACTOGRAM.out.warped_tractogram // channel: [ val(meta), [ warped_tractogram ] ] - mqc = ch_mqc // channel: [ mqc ] - versions = ch_versions // channel: [ versions.yml ] + ch_t1w_tpl = ch_t1w_tpl // channel: [ tpl-T1w ] + ch_t2w_tpl = ch_t2w_tpl // channel: [ tpl-T2w ] + ch_registered_anat = REGISTRATION.out.image_warped // channel: [ val(meta), [ image ] ] + ch_registered_nifti_files = WARPIMAGES.out.warped_image // channel: [ val(meta), [ warped_image ] ] + ch_registered_mask_files = WARPMASK.out.warped_image // channel: [ val(meta), [ warped_mask ] ] + ch_registered_labels_files = WARPLABELS.out.warped_image // channel: [ val(meta), [ warped_labels ] ] + ch_registered_trk_files = REGISTRATION_TRACTOGRAM.out.tractogram // channel: [ val(meta), [ warped_tractogram ] ] + mqc = ch_mqc // channel: [ mqc ] + versions = ch_versions // channel: [ versions.yml ] } From 932548d41acc027ac52a445a13e596f72322b2b0 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 30 Jul 2025 01:19:58 +0000 Subject: [PATCH 12/37] extract extension variable --- modules/nf-neuro/registration/convert/main.nf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/nf-neuro/registration/convert/main.nf b/modules/nf-neuro/registration/convert/main.nf index 03fcc58b..4a463948 100644 --- a/modules/nf-neuro/registration/convert/main.nf +++ b/modules/nf-neuro/registration/convert/main.nf @@ -32,7 +32,8 @@ process REGISTRATION_CONVERT { error "Invalid combination of transformation type and conversion type: ${transform_type} to ${output_type}." } - def output_name = "${prefix}__out_${transform_type}.${transform_types[transform_type][output_type]}" + def out_extension = transform_types[transform_type][output_type] + def output_name = "${prefix}__out_${transform_type}.${out_extension}" def command = transform_type == "affine" ? "lta_convert" : "mri_warp_convert" if ( transform_type == "affine" ) { From 86c9a64baf733e591140e5c4206684999d048cab Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 30 Jul 2025 01:28:39 +0000 Subject: [PATCH 13/37] fix fiable errors (convert is still a mystery) --- modules/nf-neuro/registration/synthregistration/main.nf | 8 ++++---- modules/nf-neuro/registration/synthregistration/meta.yml | 2 +- .../registration/tractogram/tests/main.nf.test.snap | 6 ++++++ subworkflows/nf-neuro/registration/meta.yml | 1 + subworkflows/nf-neuro/registration/tests/main.nf.test | 1 + 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/nf-neuro/registration/synthregistration/main.nf b/modules/nf-neuro/registration/synthregistration/main.nf index 414b63fd..d6600196 100644 --- a/modules/nf-neuro/registration/synthregistration/main.nf +++ b/modules/nf-neuro/registration/synthregistration/main.nf @@ -47,10 +47,10 @@ process REGISTRATION_SYNTHREGISTRATION { moving=$moving_image mv $fixed_image fixed.nii.gz - declare -A extension=( ["affine"]="lta" \ - ["rigid"]="lta" \ - ["deform"]="nii.gz" \ - ["joint"]="nii.gz" ) + declare -A extension=( ["affine"]="lta" \ + ["rigid"]="lta" \ + ["deform"]="nii.gz" \ + ["joint"]="nii.gz" ) weights=( $weights ) diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthregistration/meta.yml index 26af5c6c..877f7607 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthregistration/meta.yml @@ -30,7 +30,7 @@ args: - models: type: list description: List of transformation models to apply to the moving image in series. - default: "[\"affine\", \"deform\"]" + default: '["affine", "deform"]' choices: - rigid - affine diff --git a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap index 93f75e88..531736c8 100644 --- a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap @@ -41,6 +41,9 @@ "test__bundle_6.trk:md5,125e50561b4b0c5fd8ee23867c28bc51" ] ] + ], + "versions": [ + "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" ] } ], @@ -88,6 +91,9 @@ }, "test__bundle_2_mni.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" ] + ], + "versions": [ + "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" ] } ], diff --git a/subworkflows/nf-neuro/registration/meta.yml b/subworkflows/nf-neuro/registration/meta.yml index dacd7b5a..8de10b50 100644 --- a/subworkflows/nf-neuro/registration/meta.yml +++ b/subworkflows/nf-neuro/registration/meta.yml @@ -41,6 +41,7 @@ keywords: components: - registration/anattodwi - registration/ants + - registration/convert - registration/easyreg - registration/synthregistration input: diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test b/subworkflows/nf-neuro/registration/tests/main.nf.test index 9c77ee83..93926bb0 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test @@ -13,6 +13,7 @@ nextflow_workflow { tag "registration/anattodwi" tag "registration" tag "registration/ants" + tag "registration/convert" tag "registration/easyreg" tag "registration/synthregistration" From e5b02ab34c89b4e5e04c857420d2ea73b74094c9 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 30 Jul 2025 01:57:41 +0000 Subject: [PATCH 14/37] just to see --- modules/nf-neuro/registration/convert/main.nf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nf-neuro/registration/convert/main.nf b/modules/nf-neuro/registration/convert/main.nf index 4a463948..b24ace8b 100644 --- a/modules/nf-neuro/registration/convert/main.nf +++ b/modules/nf-neuro/registration/convert/main.nf @@ -32,7 +32,7 @@ process REGISTRATION_CONVERT { error "Invalid combination of transformation type and conversion type: ${transform_type} to ${output_type}." } - def out_extension = transform_types[transform_type][output_type] + def out_extension = transform_types[transform_type]["$output_type"] def output_name = "${prefix}__out_${transform_type}.${out_extension}" def command = transform_type == "affine" ? "lta_convert" : "mri_warp_convert" From fe358e2dd7404c92ff49a97c81c2a32cc2255926 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 30 Jul 2025 02:59:53 +0000 Subject: [PATCH 15/37] re-enable stubbed subworkflow runs --- modules/nf-neuro/registration/convert/main.nf | 17 ++++++-- .../nf-neuro/bundle_seg/tests/main.nf.test | 2 +- .../bundle_seg/tests/main.nf.test.snap | 12 +----- .../output_template_space/tests/main.nf.test | 2 +- .../tests/main.nf.test.snap | 16 +------ .../preproc_dwi/tests/main.nf.test.snap | 2 +- .../nf-neuro/registration/tests/main.nf.test | 2 +- .../registration/tests/main.nf.test.snap | 42 +++++++++++++++---- .../tractoflow/tests/main.nf.test.snap | 10 ++--- 9 files changed, 58 insertions(+), 47 deletions(-) diff --git a/modules/nf-neuro/registration/convert/main.nf b/modules/nf-neuro/registration/convert/main.nf index b24ace8b..a48e064a 100644 --- a/modules/nf-neuro/registration/convert/main.nf +++ b/modules/nf-neuro/registration/convert/main.nf @@ -32,7 +32,7 @@ process REGISTRATION_CONVERT { error "Invalid combination of transformation type and conversion type: ${transform_type} to ${output_type}." } - def out_extension = transform_types[transform_type]["$output_type"] + def out_extension = transform_types[transform_type][output_type] def output_name = "${prefix}__out_${transform_type}.${out_extension}" def command = transform_type == "affine" ? "lta_convert" : "mri_warp_convert" @@ -80,7 +80,19 @@ process REGISTRATION_CONVERT { stub: def prefix = task.ext.prefix ?: "${meta.id}" + def transform_types = [ + affine: [lta: "lta", fsl: "mat", mni: "xfm", reg: "dat", niftyreg: "txt", itk: "txt", vox: "txt"], + warp: [m3z: "m3z", fsl: "nii.gz", lps: "nii.gz", itk: "nii.gz", ras: "nii.gz", vox: "mgz"] + ] + // Validation transformation type and coercion with conversion type + def in_extension = transformation.name.tokenize('.')[1..-1].join('.') + def transform_type = transform_types.affine.find{ it.value == in_extension } ? "affine" : "warp" + if ( transform_type == "warp" && !transform_types.warp.containsKey(output_type) ) { + error "Invalid combination of transformation type and conversion type: ${transform_type} to ${output_type}." + } + def out_extension = transform_types[transform_type][output_type] + def output_name = "${prefix}__out_${transform_type}.${out_extension}" """ set +e function handle_code () { @@ -93,8 +105,7 @@ process REGISTRATION_CONVERT { lta_convert --help mri_warp_convert --help - touch ${prefix}__out_warp.nii.gz - touch ${prefix}__out_affine.txt + touch $output_name cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test index 3ad0e082..256642f3 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test @@ -15,7 +15,7 @@ nextflow_workflow { tag "load_test_data" tag "stub" - // options "-stub-run" + options "-stub-run" setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index 72fbbce4..1f6e6bac 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -37,17 +37,7 @@ { "id": "test" }, - "test__CC_Fr_1_cleaned.trk", - "test__CG_L_An_cleaned.trk", - "test__CG_L_cleaned.trk", - "test__FPT_L_cleaned.trk", - "test__FPT_R_Brainstem_cleaned.trk", - "test__FPT_R_cleaned.trk", - "test__MCP_cleaned.trk", - "test__POPT_R_Brainstem_cleaned.trk", - "test__POPT_R_cleaned.trk", - "test__SCP_R_cleaned.trk", - "test__SLF_R_cleaned.trk" + "test__AF_L_cleaned.trk" ] ], "versions": [ diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test index 34ac8759..a7f635cf 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test @@ -18,7 +18,7 @@ nextflow_workflow { tag "utils/templateflow" tag "stub" - //options "-stub-run" + options "-stub-run" setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap index d10bdcbe..60dca327 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap @@ -42,14 +42,6 @@ "ch_t2w_tpl": [ "template__image_bet.nii.gz" ], - "mqc": [ - [ - { - "id": "test" - }, - "test_IFGWM_registration_antsapplytransforms_mqc.gif" - ] - ], "versions": [ "versions.yml:md5,08c023826481c9130c3914096cda7f63", "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", @@ -75,7 +67,7 @@ { "id": "test" }, - "test__template__image_bet_warped.nii.gz" + "test__t1_warped.nii.gz" ] ], "ch_registered_labels_files": [ @@ -111,12 +103,6 @@ "template__image_bet.nii.gz" ], "mqc": [ - [ - { - "id": "test" - }, - "test_IFGWM_registration_antsapplytransforms_mqc.gif" - ], [ { "id": "test" diff --git a/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap b/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap index 6d938a75..aebab1b2 100644 --- a/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap @@ -324,4 +324,4 @@ }, "timestamp": "2025-10-22T13:36:58.836905415" } -} \ No newline at end of file +} diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test b/subworkflows/nf-neuro/registration/tests/main.nf.test index 93926bb0..71137826 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test @@ -20,7 +20,7 @@ nextflow_workflow { tag "load_test_data" tag "stub" - //options "-stub-run" + options "-stub-run" setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 336e1b66..4b072c58 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -15,6 +15,7 @@ { "id": "test" }, + "test__out_warp.nii.gz", "test__out_affine.txt" ] ], @@ -39,7 +40,8 @@ { "id": "test" }, - "test__out_affine.txt" + "test__out_affine.txt", + "test__out_warp.nii.gz" ] ], "inverse_tractogram_transform": [ @@ -47,6 +49,7 @@ { "id": "test" }, + "test__out_warp.nii.gz", "test__out_affine.txt" ] ], @@ -55,7 +58,8 @@ { "id": "test" }, - "test__out_affine.txt" + "test__out_affine.txt", + "test__out_warp.nii.gz" ] ], "versions": [ @@ -68,7 +72,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.6" }, - "timestamp": "2025-07-28T15:34:09.121403461" + "timestamp": "2025-07-30T02:55:56.619117796" }, "registration - easyreg": { "content": [ @@ -118,7 +122,7 @@ { "id": "test" }, - "test__warped_reference_segmentation.nii.gz" + "test_warped_reference_segmentation.nii.gz" ] ], "ref_warped": [ @@ -134,7 +138,7 @@ { "id": "test" }, - "test__warped_segmentation.nii.gz" + "test_warped_segmentation.nii.gz" ] ], "tractogram_transform": [ @@ -162,7 +166,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.6" }, - "timestamp": "2025-07-29T01:50:43.433891046" + "timestamp": "2025-07-30T02:06:11.777613914" }, "registration - ANTs - SyNQuick": { "content": [ @@ -180,6 +184,7 @@ { "id": "test" }, + "test__forward0_warp.nii.gz", "test__forward1_affine.mat" ] ], @@ -204,7 +209,8 @@ { "id": "test" }, - "test__backward0_affine.mat" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], "inverse_tractogram_transform": [ @@ -212,9 +218,18 @@ { "id": "test" }, + "test__forward0_warp.nii.gz", "test__forward1_affine.mat" ] ], + "inverse_warp": [ + [ + { + "id": "test" + }, + "test__backward1_warp.nii.gz" + ] + ], "mqc": [ [ { @@ -228,11 +243,20 @@ { "id": "test" }, - "test__backward0_affine.mat" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], "versions": [ "versions.yml:md5,7b059759af9e9bd4711e94db65e61095" + ], + "warp": [ + [ + { + "id": "test" + }, + "test__forward0_warp.nii.gz" + ] ] } ], @@ -309,7 +333,7 @@ { "id": "test" }, - "test_registration_anattodwi_mqc.gif" + "test__registration_anattodwi_mqc.gif" ] ], "tractogram_transform": [ diff --git a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap index 4b37a05e..75db8890 100644 --- a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap @@ -31,8 +31,8 @@ { "id": "test" }, - "test__output0ForwardWarp.nii.gz", - "test__output1ForwardAffine.mat" + "test__forward0_warp.nii.gz", + "test__forward1_affine.mat" ] ], "csf_fodf": [ @@ -64,8 +64,8 @@ { "id": "test" }, - "test__output0BackwardAffine.mat", - "test__output1BackwardWarp.nii.gz" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], "dti_ad": [ @@ -363,7 +363,7 @@ { "id": "test" }, - "test__t1_warped.nii.gz" + "test__test_b0_warped.nii.gz" ] ], "t1_native": [ From 8c4a867a8774f93d6055358e76eca17e2145277f Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 30 Jul 2025 03:00:21 +0000 Subject: [PATCH 16/37] bump nextflow version used in tests --- .github/workflows/run_checks_suite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run_checks_suite.yml b/.github/workflows/run_checks_suite.yml index b8c0e4d3..acc862e8 100644 --- a/.github/workflows/run_checks_suite.yml +++ b/.github/workflows/run_checks_suite.yml @@ -6,7 +6,7 @@ on: description: "Nextflow version to use" required: false type: string - default: "24.04.4" + default: "25.04.6" nf_core_version: description: "nf-core version to use" required: false From bb870a3927bbf76d0b8e8621b7fbc488ff43f43d Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 30 Jul 2025 03:29:15 +0000 Subject: [PATCH 17/37] remove limitations on subworkflows (no need for bigmem when running stubs) --- .github/workflows/run_checks_suite.yml | 6 ------ .../nf-neuro/anatomical_segmentation/tests/main.nf.test | 9 ++------- .../anatomical_segmentation/tests/nextflow.config | 2 -- .../tests/nextflow_synthseg.config | 9 --------- .../anatomical_segmentation/tests/synthseg.config | 7 +++++++ .../nf-neuro/output_template_space/tests/nextflow.config | 1 + .../output_template_space/tests/synthmorph.config | 2 +- subworkflows/nf-neuro/registration/tests/ants.config | 3 --- subworkflows/nf-neuro/registration/tests/easyreg.config | 2 +- subworkflows/nf-neuro/registration/tests/nextflow.config | 1 + .../nf-neuro/registration/tests/synthregistration.config | 1 + 11 files changed, 14 insertions(+), 29 deletions(-) delete mode 100644 subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow_synthseg.config create mode 100644 subworkflows/nf-neuro/anatomical_segmentation/tests/synthseg.config diff --git a/.github/workflows/run_checks_suite.yml b/.github/workflows/run_checks_suite.yml index acc862e8..d1e396b3 100644 --- a/.github/workflows/run_checks_suite.yml +++ b/.github/workflows/run_checks_suite.yml @@ -194,12 +194,6 @@ jobs: path: modules/nf-neuro/betcrop/synthbet - runner: scilus-docker-large path: modules/nf-neuro/registration/synthregistration - - runner: scilus-docker-large - path: subworkflows/nf-neuro/preproc_t1 - - runner: scilus-docker-large - path: subworkflows/nf-neuro/registration - - runner: scilus-docker-large - path: subworkflows/nf-neuro/anatomical_segmentation exclude: - path: subworkflows/nf-neuro/load_test_data uses: ./.github/workflows/test_component.yml diff --git a/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test b/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test index 07390814..41654690 100644 --- a/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test +++ b/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test @@ -3,6 +3,7 @@ nextflow_workflow { name "Test Subworkflow ANATOMICAL_SEGMENTATION" script "../main.nf" workflow "ANATOMICAL_SEGMENTATION" + config "./nextflow.config" tag "subworkflows" tag "subworkflows_nfneuro" @@ -31,7 +32,6 @@ nextflow_workflow { } test("anatomical_segmentation - fslfast") { - config "./nextflow.config" when { workflow { """ @@ -86,7 +86,6 @@ nextflow_workflow { } test("anatomical_segmentation - freesurferseg") { - config "./nextflow.config" when { workflow { """ @@ -139,7 +138,6 @@ nextflow_workflow { } test("anatomical_segmentation - both") { - config "./nextflow.config" when { workflow { """ @@ -200,11 +198,8 @@ nextflow_workflow { } test("anatomical_segmentation - synthseg") { - config "./nextflow.config" + config "./synthseg.config" when { - params { - run_synthseg = true - } workflow { """ ch_split_test_data = LOAD_DATA.out.test_data_directory diff --git a/subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow.config b/subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow.config index 8730f1c4..0293c16f 100644 --- a/subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow.config +++ b/subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow.config @@ -1,5 +1,3 @@ process { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - } diff --git a/subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow_synthseg.config b/subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow_synthseg.config deleted file mode 100644 index 49ea1e16..00000000 --- a/subworkflows/nf-neuro/anatomical_segmentation/tests/nextflow_synthseg.config +++ /dev/null @@ -1,9 +0,0 @@ -process { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - withName: "SEGMENTATION_SYNTHSEG" { - memory = "16G" - ext.fast = true - } -} - -params.run_synthseg = true diff --git a/subworkflows/nf-neuro/anatomical_segmentation/tests/synthseg.config b/subworkflows/nf-neuro/anatomical_segmentation/tests/synthseg.config new file mode 100644 index 00000000..f9171df3 --- /dev/null +++ b/subworkflows/nf-neuro/anatomical_segmentation/tests/synthseg.config @@ -0,0 +1,7 @@ +process { + withName: "SEGMENTATION_SYNTHSEG" { + ext.fast = true + } +} + +params.run_synthseg = true diff --git a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config index 28420258..cfdcd7cf 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config +++ b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config @@ -1,5 +1,6 @@ process { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + cpus = 1 withName: "REGISTRATION_ANTS" { ext.repro_mode = 1 diff --git a/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config b/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config index 2904d8a6..17605070 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config +++ b/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config @@ -2,7 +2,7 @@ process { withName: "REGISTRATION_SYNTHREGISTRATION" { ext.models = ["affine"] ext.extent = 192 - memory = "10G" + memory = "2G" } } diff --git a/subworkflows/nf-neuro/registration/tests/ants.config b/subworkflows/nf-neuro/registration/tests/ants.config index 41e8cce8..9841628a 100644 --- a/subworkflows/nf-neuro/registration/tests/ants.config +++ b/subworkflows/nf-neuro/registration/tests/ants.config @@ -1,7 +1,6 @@ process { withName: "REGISTRATION_ANATTODWI" { ext.run_qc = true - cpus = 1 } withName: "REGISTRATION_ANTS" { @@ -11,7 +10,5 @@ process { ext.initial_transform = "intensities" ext.run_qc = true ext.random_seed = 44 - - cpus = 1 } } diff --git a/subworkflows/nf-neuro/registration/tests/easyreg.config b/subworkflows/nf-neuro/registration/tests/easyreg.config index 448110a8..29e56dc8 100644 --- a/subworkflows/nf-neuro/registration/tests/easyreg.config +++ b/subworkflows/nf-neuro/registration/tests/easyreg.config @@ -1,7 +1,7 @@ process { withName: "REGISTRATION_EASYREG" { ext.affine_only = true - memory = '10G' + memory = '4G' } } diff --git a/subworkflows/nf-neuro/registration/tests/nextflow.config b/subworkflows/nf-neuro/registration/tests/nextflow.config index 0293c16f..d37a9c66 100644 --- a/subworkflows/nf-neuro/registration/tests/nextflow.config +++ b/subworkflows/nf-neuro/registration/tests/nextflow.config @@ -1,3 +1,4 @@ process { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + cpus = 1 } diff --git a/subworkflows/nf-neuro/registration/tests/synthregistration.config b/subworkflows/nf-neuro/registration/tests/synthregistration.config index 6e825fd7..1798856e 100644 --- a/subworkflows/nf-neuro/registration/tests/synthregistration.config +++ b/subworkflows/nf-neuro/registration/tests/synthregistration.config @@ -4,6 +4,7 @@ process { ext.regularization = 0.9 ext.steps = 9 ext.extent = 192 + memory = '2G' } } From fb2516c31a78fff91ec61bd940ff074ff6ea2efe Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 30 Jul 2025 17:08:39 +0000 Subject: [PATCH 18/37] fix invalid streamline management --- .../nf-neuro/registration/tractogram/main.nf | 11 +++++- .../nf-neuro/registration/tractogram/meta.yml | 16 ++++++-- .../tractogram/tests/keep_invalid.config | 5 +++ .../tractogram/tests/main.nf.test | 36 +++++++++++++----- .../tractogram/tests/main.nf.test.snap | 37 ++++++++++++++++++- .../tractogram/tests/nextflow.config | 1 - .../tractogram/tests/nextflow_suffix.config | 14 ------- .../tractogram/tests/suffix.config | 5 +++ .../tests/nextflow.config | 1 - 9 files changed, 94 insertions(+), 32 deletions(-) create mode 100644 modules/nf-neuro/registration/tractogram/tests/keep_invalid.config delete mode 100644 modules/nf-neuro/registration/tractogram/tests/nextflow_suffix.config create mode 100644 modules/nf-neuro/registration/tractogram/tests/suffix.config diff --git a/modules/nf-neuro/registration/tractogram/main.nf b/modules/nf-neuro/registration/tractogram/main.nf index bc8c02bd..4aa61c19 100644 --- a/modules/nf-neuro/registration/tractogram/main.nf +++ b/modules/nf-neuro/registration/tractogram/main.nf @@ -23,7 +23,8 @@ process REGISTRATION_TRACTOGRAM { def inverse = task.ext.inverse ? "--inverse" : "" def reverse_operation = task.ext.reverse_operation ? "--reverse_operation" : "" - def cut_invalid = task.ext.cut_invalid ? "--cut_invalid" : "" + def invalid_management = task.ext.invalid_streamlines ?: "cut" + def cut_invalid = invalid_management == "cut" ? "--cut_invalid" : "" def remove_single_point = task.ext.remove_single_point ? "--remove_single_point" : "" def remove_overlapping_points = task.ext.remove_overlapping_points ? "--remove_overlapping_points" : "" def threshold = task.ext.threshold ? "--threshold " + task.ext.threshold : "" @@ -47,7 +48,13 @@ process REGISTRATION_TRACTOGRAM { $in_deformation \ $inverse \ $reverse_operation \ - $reference -f + $reference \ + --keep_invalid -f + + if [[ "$invalid_management" == "keep" ]]; then + echo "Skip invalid streamline detection: ${prefix}__\${bname}${suffix}.\${ext}" + continue + fi scil_tractogram_remove_invalid tmp.trk ${prefix}__\${bname}${suffix}.\${ext}\ $cut_invalid\ diff --git a/modules/nf-neuro/registration/tractogram/meta.yml b/modules/nf-neuro/registration/tractogram/meta.yml index 452e9fbb..6530330f 100644 --- a/modules/nf-neuro/registration/tractogram/meta.yml +++ b/modules/nf-neuro/registration/tractogram/meta.yml @@ -23,11 +23,18 @@ args: description: | If true, applies affine and deformation in reverse order (deformation first). default: false - - cut_invalid: - type: boolean + - invalid_streamlines: + type: string description: | - Cut invalid streamlines after applying the transform rather than removing them. - default: false + How to manage invalid streamlines after applying the transform. Either 'keep' invalid + streamlines in the tractogram, 'cut' invalid segments and keep the remainder or 'remove' + invalid streamlines entierly. NOTE : selecting 'keep' disables overlapping and single-point + streamlines detection. + default: "cut" + choices: + - keep + - cut + - remove - remove_single_point: type: boolean description: | @@ -107,3 +114,4 @@ output: - edam: http://edamontology.org/format_3750 # YAML authors: - "@scilus" + - "@AlexVCaron" diff --git a/modules/nf-neuro/registration/tractogram/tests/keep_invalid.config b/modules/nf-neuro/registration/tractogram/tests/keep_invalid.config new file mode 100644 index 00000000..b7dbc0ba --- /dev/null +++ b/modules/nf-neuro/registration/tractogram/tests/keep_invalid.config @@ -0,0 +1,5 @@ +process { + withName: "REGISTRATION_TRACTOGRAM" { + ext.invalid_streamlines = "keep" + } +} diff --git a/modules/nf-neuro/registration/tractogram/tests/main.nf.test b/modules/nf-neuro/registration/tractogram/tests/main.nf.test index 6acabd93..0adc8bf6 100644 --- a/modules/nf-neuro/registration/tractogram/tests/main.nf.test +++ b/modules/nf-neuro/registration/tractogram/tests/main.nf.test @@ -1,6 +1,5 @@ nextflow_process { - name "Test Process REGISTRATION_TRACTOGRAM" script "../main.nf" process "REGISTRATION_TRACTOGRAM" @@ -26,10 +25,7 @@ nextflow_process { } } - test("registration - tractogram_bundles") { - - when { process { """ @@ -53,13 +49,37 @@ nextflow_process { { assert snapshot(process.out).match() } ) } - } - test("registration - tractogram") { + test("registration - tractogram - custom suffix") { + config "./suffix.config" + when { + process { + """ + input[0] = LOAD_DATA.out.test_data_directory.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], // meta map + file("\${test_data_directory}/bundle_all_1mm.nii.gz", checkIfExists: true), + file("\${test_data_directory}/affine.txt", checkIfExists: true), + file("\${test_data_directory}/fibercup_atlas/subj_1/bundle_2.trk", checkIfExists: true), + [], + [] + ] + } + """ + } + } - config "./nextflow_suffix.config" + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + test("registration - tractogram - keep invalid") { + config "./keep_invalid.config" when { process { """ @@ -83,7 +103,6 @@ nextflow_process { { assert snapshot(process.out).match() } ) } - } test("registration - tractogram - stub-run") { @@ -113,6 +132,5 @@ nextflow_process { { assert snapshot(process.out.versions).match() } ) } - } } diff --git a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap index 531736c8..e8088aac 100644 --- a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap @@ -1,4 +1,39 @@ { + "registration - tractogram - keep invalid": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test__bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" + ] + ], + "1": [ + "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" + ], + "tractogram": [ + [ + { + "id": "test", + "single_end": false + }, + "test__bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" + ] + ], + "versions": [ + "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "25.04.6" + }, + "timestamp": "2025-07-30T17:00:29.348451708" + }, "registration - tractogram_bundles": { "content": [ { @@ -65,7 +100,7 @@ }, "timestamp": "2025-09-22T22:17:25.469054766" }, - "registration - tractogram": { + "registration - tractogram - custom suffix": { "content": [ { "0": [ diff --git a/modules/nf-neuro/registration/tractogram/tests/nextflow.config b/modules/nf-neuro/registration/tractogram/tests/nextflow.config index a32e45e8..a5cab34f 100644 --- a/modules/nf-neuro/registration/tractogram/tests/nextflow.config +++ b/modules/nf-neuro/registration/tractogram/tests/nextflow.config @@ -4,7 +4,6 @@ process { ext.inverse = true ext.force = true ext.reverse_operation = true - ext.cut_invalid = true ext.remove_single_point = true ext.remove_overlapping_points = true ext.threshold = 0.001 diff --git a/modules/nf-neuro/registration/tractogram/tests/nextflow_suffix.config b/modules/nf-neuro/registration/tractogram/tests/nextflow_suffix.config deleted file mode 100644 index c9553be0..00000000 --- a/modules/nf-neuro/registration/tractogram/tests/nextflow_suffix.config +++ /dev/null @@ -1,14 +0,0 @@ -process { - withName: "REGISTRATION_TRACTOGRAM" { - publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } - ext.inverse = true - ext.force = true - ext.reverse_operation = true - ext.cut_invalid = true - ext.remove_single_point = true - ext.remove_overlapping_points = true - ext.threshold = 0.001 - ext.no_empty = true - ext.suffix = 'mni' - } -} diff --git a/modules/nf-neuro/registration/tractogram/tests/suffix.config b/modules/nf-neuro/registration/tractogram/tests/suffix.config new file mode 100644 index 00000000..c0cca21e --- /dev/null +++ b/modules/nf-neuro/registration/tractogram/tests/suffix.config @@ -0,0 +1,5 @@ +process { + withName: "REGISTRATION_TRACTOGRAM" { + ext.suffix = 'mni' + } +} diff --git a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config index cfdcd7cf..39c89e79 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config +++ b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config @@ -35,7 +35,6 @@ process { withName: "REGISTRATION_TRACTOGRAM" { ext.inverse = true ext.force = true - ext.cut_invalid = true ext.remove_single_point = true ext.remove_overlapping_points = true ext.threshold = 0.001 From b91e73b2281c64dcec2676d0e0de3ec57fc3df69 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 31 Jul 2025 23:32:03 +0000 Subject: [PATCH 19/37] remove debug prints --- subworkflows/nf-neuro/registration/main.nf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subworkflows/nf-neuro/registration/main.nf b/subworkflows/nf-neuro/registration/main.nf index 81f62b9a..e7643d57 100644 --- a/subworkflows/nf-neuro/registration/main.nf +++ b/subworkflows/nf-neuro/registration/main.nf @@ -92,12 +92,12 @@ workflow REGISTRATION { .map{ meta, tag, idx, transform -> [meta, tag + [idx: idx], transform]} // Mix all transforms into a single channel for conversion - ch_convert = ch_convert_affine.view{ "affine $it" } - .mix(ch_convert_warp.view{ "warp $it" }) - .mix(ch_convert_inverse_affine.view{ "inv-affine $it" }) - .mix(ch_convert_inverse_warp.view{ "inv-warp $it" }) - .mix(ch_convert_image_transform.view{ "image-transform $it" }) - .mix(ch_convert_inverse_image_transform.view{ "inv-image-transform $it" }) + ch_convert = ch_convert_affine + .mix(ch_convert_warp) + .mix(ch_convert_inverse_affine) + .mix(ch_convert_inverse_warp) + .mix(ch_convert_image_transform) + .mix(ch_convert_inverse_image_transform) .combine(ch_fixed_image, by: 0) .combine(ch_moving_image, by: 0) .map{ meta, tag, transform, fixed, moving -> From 8bc4477f4defa4fbde5649a6a4ca52f1c57448b5 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 24 Sep 2025 03:17:02 +0000 Subject: [PATCH 20/37] fix prettier --- .../nf-neuro/registration/anattodwi/meta.yml | 154 +++++++++--------- .../nf-neuro/registration/easyreg/meta.yml | 12 +- .../registration/synthregistration/meta.yml | 6 +- 3 files changed, 86 insertions(+), 86 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index 05c5dc18..c6df1ae4 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -59,89 +59,89 @@ input: - edam: http://edamontology.org/format_4001 # NIFTI format output: anat_warped: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*_warped.{nii,nii.gz}": - type: file - description: Anatomical image warped to DWI space - pattern: "*_warped.{nii,nii.gz}" - ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_warped.{nii,nii.gz}": + type: file + description: Anatomical image warped to DWI space + pattern: "*_warped.{nii,nii.gz}" + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format affine: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*__forward1_affine.mat": - type: file - description: Affine transformation matrix file. - pattern: "*__forward1_affine.mat" - ontologies: [] + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__forward1_affine.mat": + type: file + description: Affine transformation matrix file. + pattern: "*__forward1_affine.mat" + ontologies: [] warp: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*__forward0_warp.nii.gz": - type: file - description: Deformation field file. - pattern: "*__forward0_warp.nii.gz" - ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__forward0_warp.nii.gz": + type: file + description: Deformation field file. + pattern: "*__forward0_warp.nii.gz" + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format inverse_warp: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*__backward1_warp.nii.gz": - type: file - description: Inverse deformation field file. - pattern: "*__backward1_warp.nii.gz" - ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__backward1_warp.nii.gz": + type: file + description: Inverse deformation field file. + pattern: "*__backward1_warp.nii.gz" + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format inverse_affine: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*__backward0_affine.mat": - type: file - description: Inverse affine transformation matrix file. - pattern: "*__backward0_affine.mat" - ontologies: [] + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__backward0_affine.mat": + type: file + description: Inverse affine transformation matrix file. + pattern: "*__backward0_affine.mat" + ontologies: [] image_transform: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii,nii.gz,mat}": - type: list - description: | - Tuple, Transformation files to warp images in the correct order - for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. - pattern: "*__forward*.{nii,nii.gz,mat}" - ontologies: [] + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__forward*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Transformation files to warp images in the correct order + for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. + pattern: "*__forward*.{nii,nii.gz,mat}" + ontologies: [] inverse_image_transform: - - - meta: - type: map - description: | - Groovy Map containing sample information - e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii,nii.gz,mat}": - type: list - description: | - Tuple, Transformation files to warp images in the correct order for - REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__backward*.{nii,nii.gz,mat}" - ontologies: [] + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*__backward*.{nii,nii.gz,mat}": + type: list + description: | + Tuple, Transformation files to warp images in the correct order for + REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. + pattern: "*__backward*.{nii,nii.gz,mat}" + ontologies: [] tractogram_transform: - - meta: type: map diff --git a/modules/nf-neuro/registration/easyreg/meta.yml b/modules/nf-neuro/registration/easyreg/meta.yml index 3d45328e..15cda984 100644 --- a/modules/nf-neuro/registration/easyreg/meta.yml +++ b/modules/nf-neuro/registration/easyreg/meta.yml @@ -70,7 +70,7 @@ output: description: Image warped onto the reference. pattern: "*_warped.nii.gz" ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format fixed_warped: - - meta: type: map @@ -82,7 +82,7 @@ output: description: Reference warped. pattern: "*_warped_reference.nii.gz" ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format warp: - - meta: type: map @@ -94,7 +94,7 @@ output: description: Forward deformation field, composed of all registration stages (affine+deformation). pattern: "*_forward0_warp.nii.gz" ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format inverse_warp: - - meta: type: map @@ -106,7 +106,7 @@ output: description: Backward deformation field, composed of all registration stages (inv-deformation+inv-affine). pattern: "*_backward0_warp.nii.gz" ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format fixed_segmentation_warped: - - meta: type: map @@ -120,7 +120,7 @@ output: Will produce image only if not passed as input. pattern: "*_warped_segmentation_reference.nii.gz" ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format optional: true segmentation_warped: - - meta: @@ -135,7 +135,7 @@ output: Will produce image only if not passed as input. pattern: "*_warped_segmentation.nii.gz" ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format optional: true versions: - versions.yml: diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthregistration/meta.yml index 877f7607..4ecc512e 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthregistration/meta.yml @@ -98,7 +98,7 @@ output: description: Warped image pattern: "*_warped.{nii,nii.gz}" ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format affine: - - meta: type: map @@ -123,7 +123,7 @@ output: pattern: "*__forward0_warp.nii.gz" optional: true ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format inverse_warp: - - meta: type: map @@ -136,7 +136,7 @@ output: pattern: "*__backward1_warp.nii.gz" optional: true ontologies: - - edam: http://edamontology.org/format_4001 # NIFTI format + - edam: http://edamontology.org/format_4001 # NIFTI format inverse_affine: - - meta: type: map From 71a52a9f89ad6a08279058e5be31fbd24fc102a7 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 24 Sep 2025 03:42:24 +0000 Subject: [PATCH 21/37] fix lint --- .../nf-neuro/registration/anattodwi/meta.yml | 20 +++++------ modules/nf-neuro/registration/ants/meta.yml | 16 ++++----- .../registration/antsapplytransforms/meta.yml | 30 +++++++--------- .../nf-neuro/registration/easyreg/meta.yml | 16 ++++----- .../registration/synthregistration/meta.yml | 36 +++++++++---------- 5 files changed, 57 insertions(+), 61 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index c6df1ae4..2da50302 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -64,10 +64,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*_warped.{nii,nii.gz}": + - "*_warped.nii.gz": type: file description: Anatomical image warped to DWI space - pattern: "*_warped.{nii,nii.gz}" + pattern: "*_warped.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format affine: @@ -122,12 +122,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii,nii.gz,mat}": + - "*__forward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp images in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. - pattern: "*__forward*.{nii,nii.gz,mat}" + pattern: "*__forward*.{nii.gz,mat}" ontologies: [] inverse_image_transform: - - meta: @@ -135,12 +135,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii,nii.gz,mat}": + - "*__backward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp images in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__backward*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii.gz,mat}" ontologies: [] tractogram_transform: - - meta: @@ -148,12 +148,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii,nii.gz,mat}": + - "*__backward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__backward*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii.gz,mat}" ontologies: [] inverse_tractogram_transform: - - meta: @@ -161,12 +161,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii,nii.gz,mat}": + - "*__forward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. - pattern: "*__forward*.{nii,nii.gz,mat}" + pattern: "*__forward*.{nii.gz,mat}" ontologies: [] mqc: - - meta: diff --git a/modules/nf-neuro/registration/ants/meta.yml b/modules/nf-neuro/registration/ants/meta.yml index 30bbcd1e..3e56cf2c 100644 --- a/modules/nf-neuro/registration/ants/meta.yml +++ b/modules/nf-neuro/registration/ants/meta.yml @@ -213,12 +213,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii,nii.gz,mat}": + - "*__forward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. - pattern: "*__forward*.{nii,nii.gz,mat}" + pattern: "*__forward*.{nii.gz,mat}" ontologies: [] inverse_image_transform: - - meta: @@ -226,12 +226,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii,nii.gz,mat}": + - "*__backward*.{nii.gz,mat}": type: list description: | Tuple, Inverse transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__backward*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii.gz,mat}" ontologies: [] tractogram_transform: - - meta: @@ -239,12 +239,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii,nii.gz,mat}": + - "*__backward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__backward*.{nii,nii.gz,mat}" + pattern: "*__backward*.{nii.gz,mat}" ontologies: [] inverse_tractogram_transform: - - meta: @@ -252,12 +252,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii,nii.gz,mat}": + - "*__forward*.{nii.gz,mat}": type: list description: | Tuple, Inverse transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__forward*.{nii,nii.gz,mat}" + pattern: "*__forward*.{nii.gz,mat}" ontologies: [] mqc: - - meta: diff --git a/modules/nf-neuro/registration/antsapplytransforms/meta.yml b/modules/nf-neuro/registration/antsapplytransforms/meta.yml index c1ea3760..7a218a73 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/meta.yml +++ b/modules/nf-neuro/registration/antsapplytransforms/meta.yml @@ -88,29 +88,25 @@ input: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - image: - type: file - description: Input image to register + - images: + type: list + description: Input images to transform onto reference. pattern: "*.{nii.nii.gz}" - ontologies: [] + mandatory: true + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format] - reference: type: file - description: Reference image for registration + description: Reference image for transformation. pattern: "*.{nii.nii.gz}" - ontologies: [] - - warp: - type: file - description: Warp transformation file to warp image or trk. - pattern: "*.{nii,nii.gz}" + mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - affine: - type: file - description: Affine or rigig transformation file to warp image or trk (*mat). - If a rigid or affine transformation needs to be inverted before being applied, - use antsApplyTransforms with the -o Linear[inversedTransform,1], as this - module does not handles it. - pattern: "*.mat" + - transformations: + type: list + description: Transformation files (in the correct order). + pattern: "*.{nii.gz,mat}" + mandatory: true ontologies: [] output: warped_image: diff --git a/modules/nf-neuro/registration/easyreg/meta.yml b/modules/nf-neuro/registration/easyreg/meta.yml index 15cda984..b7a9e93d 100644 --- a/modules/nf-neuro/registration/easyreg/meta.yml +++ b/modules/nf-neuro/registration/easyreg/meta.yml @@ -107,33 +107,33 @@ output: pattern: "*_backward0_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - fixed_segmentation_warped: + segmentation_warped: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_warped_segmentation_reference.nii.gz": + - "*_warped_segmentation.nii.gz": type: file description: | - SynthSeg v2 (non-robust) segmentation + parcellation on the reference image. + SynthSeg v2 (non-robust) segmentation + parcellation on the warped image. Will produce image only if not passed as input. - pattern: "*_warped_segmentation_reference.nii.gz" + pattern: "*_warped_segmentation.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format optional: true - segmentation_warped: + fixed_segmentation_warped: - - meta: type: map description: | Groovy Map containing sample information e.g. `[ id:'sample1', single_end:false ]` - - "*_warped_segmentation.nii.gz": + - "*_warped_reference_segmentation.nii.gz": type: file description: | - SynthSeg v2 (non-robust) segmentation + parcellation on the warped image. + SynthSeg v2 (non-robust) segmentation + parcellation on the reference image. Will produce image only if not passed as input. - pattern: "*_warped_segmentation.nii.gz" + pattern: "*_warped_reference_segmentation.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format optional: true diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthregistration/meta.yml index 4ecc512e..94254f90 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthregistration/meta.yml @@ -93,10 +93,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*_warped.{nii,nii.gz}": + - "*__warped.nii.gz": type: file description: Warped image - pattern: "*_warped.{nii,nii.gz}" + pattern: "*__warped.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format affine: @@ -105,10 +105,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward1_affine.lta": + - "*__forward{0,1,_standalone}_affine.lta": type: file description: Affine transformation matrix file. - pattern: "*__forward1_affine.lta" + pattern: "*__forward{0,1,_standalone}_affine.lta" optional: true ontologies: [] warp: @@ -117,10 +117,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward0_warp.nii.gz": + - "*__forward0_deform.nii.gz": type: file description: Deformation field file. - pattern: "*__forward0_warp.nii.gz" + pattern: "*__forward0_deform.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format @@ -130,10 +130,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward1_warp.nii.gz": + - "*__backward1_deform.nii.gz": type: file description: Inverse deformation field file. - pattern: "*__backward1_warp.nii.gz" + pattern: "*__backward1_deform.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format @@ -143,10 +143,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward0_affine.lta": + - "*__backward{0,_standalone}_affine.lta": type: file description: Inverse affine transformation matrix file. - pattern: "*__backward0_affine.lta" + pattern: "*__backward{0,_standalone}_affine.lta" optional: true ontologies: [] image_transform: @@ -155,12 +155,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii,nii.gz,mat,lta}": + - "*__forward[!_]*.{lta,nii.gz}": type: list description: | Tuple, Transformation files to warp images in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. - pattern: "*__forward*.{nii,nii.gz,mat,lta}" + pattern: "*__forward[!_]*.{lta,nii.gz}" ontologies: [] inverse_image_transform: - - meta: @@ -168,12 +168,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii,nii.gz,mat,lta}": + - "*__backward[!_]*.{lta,nii.gz}": type: list description: | Tuple, Transformation files to warp images in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__backward*.{nii,nii.gz,mat,lta}" + pattern: "*__backward[!_]*.{lta,nii.gz}" ontologies: [] tractogram_transform: - - meta: @@ -181,12 +181,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii,nii.gz,mat,lta}": + - "*__backward[!_]*.{lta,nii.gz}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. - pattern: "*__backward*.{nii,nii.gz,mat,lta}" + pattern: "*__backward[!_]*.{lta,nii.gz}" ontologies: [] inverse_tractogram_transform: - - meta: @@ -194,12 +194,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii,nii.gz,mat,lta}": + - "*__forward[!_]*.{lta,nii.gz}": type: list description: | Tuple, Transformation files to warp tractograms in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. - pattern: "*__forward*.{nii,nii.gz,mat,lta}" + pattern: "*__forward[!_]*.{lta,nii.gz}" ontologies: [] versions: - versions.yml: From b3e03a100d251ab49565997bc8c2305c884e8593 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 24 Sep 2025 04:10:15 +0000 Subject: [PATCH 22/37] fix tests --- subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index 1f6e6bac..d3bbe14f 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -48,7 +48,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, "timestamp": "2025-10-17T17:38:41.717732229" } From 691aea5ae8277f26aea268961d02232326ed57a8 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 8 Oct 2025 14:33:51 +0000 Subject: [PATCH 23/37] update tests and meta. --- .../nf-neuro/registration/anattodwi/main.nf | 21 ++-- .../nf-neuro/registration/anattodwi/meta.yml | 1 + .../anattodwi/tests/main.nf.test.snap | 79 ++++++++++-- modules/nf-neuro/registration/ants/main.nf | 32 ++--- modules/nf-neuro/registration/ants/meta.yml | 7 +- .../registration/ants/tests/main.nf.test.snap | 4 +- .../registration/antsapplytransforms/main.nf | 114 ++++++------------ .../registration/antsapplytransforms/meta.yml | 23 ++-- .../tests/main.nf.test.snap | 6 +- modules/nf-neuro/registration/convert/main.nf | 10 +- .../convert/tests/main.nf.test.snap | 38 +++--- .../nf-neuro/registration/easyreg/meta.yml | 6 +- .../registration/synthregistration/main.nf | 113 ++++++++--------- .../nf-neuro/registration/tractogram/main.nf | 59 ++++----- .../nf-neuro/registration/tractogram/meta.yml | 6 +- .../tractogram/tests/main.nf.test.snap | 36 +++--- 16 files changed, 295 insertions(+), 260 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index 0c1cd345..4765af88 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -65,8 +65,7 @@ process REGISTRATION_ANATTODWI { -t [${prefix}__forward1_affine.mat,1] ### ** QC ** ### - if $run_qc; - then + if $run_qc; then # Extract dimensions. dim=\$(mrinfo ${prefix}__\${moving_id}_warped.nii.gz -size) read sagittal_dim coronal_dim axial_dim <<< "\${dim}" @@ -84,8 +83,7 @@ process REGISTRATION_ANATTODWI { fixed_id=\${fixed_id#${meta.id}__*} # Iterate over images. - for image in \${moving_id}_warped \${fixed_id}; - do + for image in \${moving_id}_warped \${fixed_id}; do mrconvert *\${image}.nii.gz *\${image}_viz.nii.gz -stride -1,2,3 scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_coronal.png \ --slices \$coronal_mid --axis coronal \$viz_params @@ -94,8 +92,7 @@ process REGISTRATION_ANATTODWI { scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_axial.png \ --slices \$axial_mid --axis axial \$viz_params - if [ \$image != \${fixed_id} ]; - then + if [ \$image != \${fixed_id} ]; then title="Warped \${moving_id^^}" else title="Reference \${fixed_id^^}" @@ -130,13 +127,14 @@ process REGISTRATION_ANATTODWI { stub: def prefix = task.ext.prefix ?: "${meta.id}" + def run_qc = task.ext.run_qc as Boolean || false """ set +e function handle_code () { - local code=\$? - ignore=( 1 ) - [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code + local code=\$? + ignore=( 1 ) + [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code } trap 'handle_code' ERR @@ -152,7 +150,10 @@ process REGISTRATION_ANATTODWI { touch ${prefix}__forward0_warp.nii.gz touch ${prefix}__backward1_warp.nii.gz touch ${prefix}__backward0_affine.mat - touch ${prefix}__registration_anattodwi_mqc.gif + + if $run_qc; then + touch ${prefix}__registration_anattodwi_mqc.gif + fi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index 2da50302..2230f228 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -180,6 +180,7 @@ output: .gif file containing quality control image for the registration process. For use in MultiQC report. pattern: "*_registration_anattodwi_mqc.gif" + optional: true ontologies: [] versions: - versions.yml: diff --git a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap index 24cc1077..90440bb6 100644 --- a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap @@ -8,7 +8,7 @@ "id": "test", "single_end": false }, - "test__output0GenericAffine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + "test__T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" ] ], "1": [ @@ -17,11 +17,11 @@ "id": "test", "single_end": false }, - "test__output1Warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" + "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" ] ], "10": [ - "versions.yml:md5,f7d4a628967ea923c4ce688c43ad7f5f" + "versions.yml:md5,4d59aa7132ca8851c32f00b29da08d34" ], "2": [ [ @@ -29,7 +29,7 @@ "id": "test", "single_end": false }, - "test__output1InverseWarp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" ] ], "3": [ @@ -38,7 +38,7 @@ "id": "test", "single_end": false }, - "test__t1_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" + "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" ] ], "4": [ @@ -47,7 +47,7 @@ "id": "test", "single_end": false }, - "test_registration_anattodwi_mqc.gif:md5,687252d31b0109f99a174b4e3960e4e6" + "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" ] ], "5": [ @@ -59,7 +59,61 @@ "id": "test", "single_end": false }, - "test__output0GenericAffine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + ] + ], + "anat_warped": [ + [ + { + "id": "test", + "single_end": false + }, + "test__T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" + ] + ], + "image_transform": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", + "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + ] + ] + ], + "inverse_affine": [ + [ + { + "id": "test", + "single_end": false + }, + "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" + ] + ], + "inverse_image_transform": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + ] + ] + ], + "inverse_tractogram_transform": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", + "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + ] ] ], "inverse_warp": [ @@ -68,7 +122,7 @@ "id": "test", "single_end": false }, - "test__output1InverseWarp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" ] ], "mqc": [ @@ -77,7 +131,7 @@ "id": "test", "single_end": false }, - "test_registration_anattodwi_mqc.gif:md5,687252d31b0109f99a174b4e3960e4e6" + "test_registration_anattodwi_mqc.gif:md5,9cbc1ce8755821996dae18080cf0a23c" ] ], "tractogram_transform": [ @@ -86,7 +140,10 @@ "id": "test", "single_end": false }, - "test__t1_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" + [ + "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + ] ] ], "versions": [ @@ -98,7 +155,7 @@ "id": "test", "single_end": false }, - "test__output1Warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" + "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" ] ] } diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index d72389a3..5676650b 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -58,13 +58,11 @@ process REGISTRATION_ANTS { mv outputWarped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz - if [ $transform != "bo" ] && [ $transform != "so" ]; - then + if [ $transform != "bo" ] && [ $transform != "so" ]; then mv output0GenericAffine.mat ${prefix}__forward1_affine.mat fi - if [ $transform != "t" ] && [ $transform != "r" ] && [ $transform != "a" ]; - then + if [ $transform != "t" ] && [ $transform != "r" ] && [ $transform != "a" ]; then mv output1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz mv output1Warp.nii.gz ${prefix}__forward0_warp.nii.gz fi @@ -74,8 +72,7 @@ process REGISTRATION_ANTS { -t [${prefix}__forward1_affine.mat,1] ### ** QC ** ### - if $run_qc; - then + if $run_qc; then mv $fixed_image fixed_image.nii.gz extract_dim=\$(mrinfo fixed_image.nii.gz -size) read sagittal_dim coronal_dim axial_dim <<< "\${extract_dim}" @@ -92,8 +89,7 @@ process REGISTRATION_ANTS { # Set viz params. viz_params="--display_slice_number --display_lr --size 256 256" # Iterate over images. - for image in fixed_image warped; - do + for image in fixed_image warped; do mrconvert *\${image}.nii.gz *\${image}_viz.nii.gz -stride -1,2,3 scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_coronal.png \ --slices \$coronal_dim --axis coronal \$viz_params @@ -101,23 +97,27 @@ process REGISTRATION_ANTS { --slices \$sagittal_dim --axis sagittal \$viz_params scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_axial.png \ --slices \$axial_dim --axis axial \$viz_params - if [ \$image != fixed_image ]; - then + + if [ \$image != fixed_image ]; then title="Warped \${moving_id^^}" else title="Reference \${fixed_id^^}" fi + convert +append \${image}_coronal*.png \${image}_axial*.png \ \${image}_sagittal*.png \${image}_mosaic.png convert -annotate +20+230 "\${title}" -fill white -pointsize 30 \ \${image}_mosaic.png \${image}_mosaic.png + # Clean up. rm \${image}_coronal*.png \${image}_sagittal*.png \${image}_axial*.png done + # Create GIF. convert -delay 10 -loop 0 -morph 10 \ warped_mosaic.png fixed_image_mosaic.png warped_mosaic.png \ ${prefix}_${suffix_qc}_registration_ants_mqc.gif + # Clean up. rm *_mosaic.png fi @@ -134,13 +134,14 @@ process REGISTRATION_ANTS { stub: def prefix = task.ext.prefix ?: "${meta.id}" def suffix_qc = task.ext.suffix_qc ?: "" + def run_qc = task.ext.run_qc as Boolean || false """ set +e function handle_code () { - local code=\$? - ignore=( 1 ) - [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code + local code=\$? + ignore=( 1 ) + [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code } trap 'handle_code' ERR @@ -154,7 +155,10 @@ process REGISTRATION_ANTS { touch ${prefix}__forward0_warp.nii.gz touch ${prefix}__backward1_warp.nii.gz touch ${prefix}__backward0_affine.mat - touch ${prefix}_${suffix_qc}_registration_ants_mqc.gif + + if $run_qc; then + touch ${prefix}_${suffix_qc}_registration_ants_mqc.gif + fi cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-neuro/registration/ants/meta.yml b/modules/nf-neuro/registration/ants/meta.yml index 3e56cf2c..2f07250c 100644 --- a/modules/nf-neuro/registration/ants/meta.yml +++ b/modules/nf-neuro/registration/ants/meta.yml @@ -79,7 +79,7 @@ args: description: Algorithmic initialization by geometric center, intensities, or origin. default: "" choices: - - geometric_center + - geometric center - intensities - origin - dimension: @@ -171,6 +171,7 @@ output: type: file description: Affine transformation from moving to fixed pattern: "*__forward1_affine.mat" + optional: true ontologies: [] warp: - - meta: @@ -182,6 +183,7 @@ output: type: file description: Nifti volume containing warp field from moving to fixed pattern: "*__forward0_warp.nii.gz" + optional: true ontologies: - edam: http://edamontology.org/format_3989 # GZIP format inverse_warp: @@ -194,6 +196,7 @@ output: type: file description: Nifti volume containing warp field from fixed to moving pattern: "*__backward1_warp.nii.gz" + optional: true ontologies: - edam: http://edamontology.org/format_3989 # GZIP format inverse_affine: @@ -206,6 +209,7 @@ output: type: file description: Affine transformation from fixed to moving pattern: "*__backward0_affine.mat" + optional: true ontologies: [] image_transform: - - meta: @@ -270,6 +274,7 @@ output: description: .gif file containing quality control image for the registration process. Made for use in MultiQC report. pattern: "*_registration_ants_mqc.gif" + optional: true ontologies: [] versions: - versions.yml: diff --git a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap index 05335044..39b2b284 100644 --- a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap @@ -235,10 +235,10 @@ ] ], "2": [ - + ], "3": [ - + ], "4": [ [ diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index cbad21e7..906fd88d 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -21,10 +21,10 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { def suffix_qc = task.ext.suffix_qc ?: "" def output_dtype = "-u ${task.ext.output_dtype ?: "default"}" - def dimensionality = "-d ${task.ext.dimensionality ?: 3}" - def image_type = "-e ${task.ext.image_type ?: 0}" - def interpolation = "-n ${task.ext.interpolation ?: "Linear"}" - def default_val = "-f ${task.ext.default_val ?: 3}" + def dimensionality = "-d ${task.ext.dimensionality ?: 3}" + def image_type = "-e ${task.ext.image_type ?: 0}" + def interpolation = "-n ${task.ext.interpolation ?: "Linear"}" + def default_val = "-f ${task.ext.default_val ?: 3}" def run_qc = task.ext.run_qc as Boolean || false """ @@ -32,49 +32,23 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { export OMP_NUM_THREADS=1 export OPENBLAS_NUM_THREADS=1 - for image in $images; - do - - ext=\${image#*.} - bname=\$(basename \${image} .\${ext}) - - antsApplyTransforms $dimensionality \ - -i \$image \ - -r $reference \ - -o ${prefix}__\${bname}${suffix}.nii.gz \ - $interpolation \ - ${transformations.collect{ t -> "-t $t" }.join(" ")} \ - $output_dtype \ - $image_type \ - $default_val - - ### ** QC ** ### - if $run_qc; - then - - ln -sf $reference reference.nii.gz - extract_dim=\$(mrinfo ${prefix}__\${bname}${suffix}.nii.gz -size) - read sagittal_dim coronal_dim axial_dim <<< "\${extract_dim}" - - # Get the middle slice - coronal_dim=\$((\$coronal_dim / 2)) - axial_dim=\$((\$axial_dim / 2)) - sagittal_dim=\$((\$sagittal_dim / 2)) - - # Set viz params. - viz_params="--display_slice_number --display_lr --size 256 256" - # Iterate over images. - for image in reference \${bname}${suffix}; - do - scil_viz_volume_screenshot.py *\${image}.nii.gz \${image}_coronal.png \ - --slices \$coronal_dim --axis coronal \$viz_params - scil_viz_volume_screenshot.py *\${image}.nii.gz \${image}_sagittal.png \ - --slices \$sagittal_dim --axis sagittal \$viz_params - scil_viz_volume_screenshot.py *\${image}.nii.gz \${image}_axial.png \ - --slices \$axial_dim --axis axial \$viz_params - if [ \$image != reference ]; - then - mv $reference reference.nii.gz + for image in $images; do + ext=\${image#*.} + bname=\$(basename \${image} .\${ext}) + + antsApplyTransforms $dimensionality \ + -i \$image \ + -r $reference \ + -o ${prefix}__\${bname}${suffix}.nii.gz \ + $interpolation \ + ${transformations.collect{ t -> "-t $t" }.join(" ")} \ + $output_dtype \ + $image_type \ + $default_val + + ### ** QC ** ### + if $run_qc; then + ln -sf $reference reference.nii.gz extract_dim=\$(mrinfo ${prefix}__\${bname}${suffix}.nii.gz -size) read sagittal_dim coronal_dim axial_dim <<< "\${extract_dim}" @@ -85,22 +59,23 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { # Set viz params. viz_params="--display_slice_number --display_lr --size 256 256" + # Iterate over images. - for image in reference \${bname}${suffix}; - do - mrconvert *\${image}.nii.gz *\${image}_viz.nii.gz -stride -1,2,3 + for image in reference \${bname}${suffix}; do + mrconvert *\${image}.nii.gz *\${image}_viz.nii.gz -stride -1,2,3 -force scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_coronal.png \ --slices \$coronal_dim --axis coronal \$viz_params scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_sagittal.png \ --slices \$sagittal_dim --axis sagittal \$viz_params scil_viz_volume_screenshot *\${image}_viz.nii.gz \${image}_axial.png \ --slices \$axial_dim --axis axial \$viz_params - if [ \$image != reference ]; - then + + if [ \$image != reference ]; then title="Transformed" else title="Reference" fi + convert +append \${image}_coronal*.png \${image}_axial*.png \ \${image}_sagittal*.png \${image}_mosaic.png convert -annotate +20+230 "\${title}" -fill white -pointsize 30 \ @@ -108,29 +83,15 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { # Clean up. rm \${image}_coronal*.png \${image}_sagittal*.png \${image}_axial*.png done + # Create GIF. convert -delay 10 -loop 0 -morph 10 \ \${bname}${suffix}_mosaic.png reference_mosaic.png \${bname}${suffix}_mosaic.png \ ${prefix}_\${bname}${suffix_qc}_registration_antsapplytransforms_mqc.gif + # Clean up. rm *_mosaic.png fi - convert +append \${image}_coronal*.png \${image}_axial*.png \ - \${image}_sagittal*.png \${image}_mosaic.png - convert -annotate +20+230 "\${title}" -fill white -pointsize 30 \ - \${image}_mosaic.png \${image}_mosaic.png - # Clean up. - rm \${image}_coronal*.png \${image}_sagittal*.png \${image}_axial*.png - done - # Create GIF. - convert -delay 10 -loop 0 -morph 10 \ - \${bname}${suffix}_mosaic.png reference_mosaic.png \${bname}${suffix}_mosaic.png \ - ${prefix}_\${bname}${suffix_qc}_registration_antsapplytransforms_mqc.gif - # Clean up. - rm *_mosaic.png - - fi - done cat <<-END_VERSIONS > versions.yml @@ -144,14 +105,16 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { stub: def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = task.ext.first_suffix ? "${task.ext.first_suffix}__warped" : "__warped" + def suffix = "${task.ext.first_suffix ?: ""}__warped" + def suffix_qc = task.ext.suffix_qc ?: "" + def run_qc = task.ext.run_qc as Boolean || false """ set +e function handle_code () { - local code=\$? - ignore=( 1 ) - [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code + local code=\$? + ignore=( 1 ) + [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code } trap 'handle_code' ERR @@ -159,12 +122,15 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { convert -h scil_viz_volume_screenshot -h - for image in $images; - do \ + for image in $images; do ext=\${image#*.} bname=\$(basename \${image} .\${ext}) touch ${prefix}__\${bname}${suffix}.nii.gz + + if $run_qc; then + touch ${prefix}_\${bname}${suffix_qc}_registration_antsapplytransforms_mqc.gif + fi done cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-neuro/registration/antsapplytransforms/meta.yml b/modules/nf-neuro/registration/antsapplytransforms/meta.yml index 7a218a73..7c09ce1c 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/meta.yml +++ b/modules/nf-neuro/registration/antsapplytransforms/meta.yml @@ -35,14 +35,22 @@ args: e.g. `2` for 2D images, `3` for 3D images. - image_type: type: integer - description: Type of the input image. + description: | + Type of the input image : + - 0: scalar + - 1: vector + - 2: tensor + - 3: time series + - 4: multichannel + - 5: five-dimensional + default: 0 choices: - - 0 (scalar) - - 1 (vector) - - 2 (tensor) - - 3 (time series) - - 4 (multichannel) - - 5 (five-dimensional) + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 - interpolation: type: string description: | @@ -132,6 +140,7 @@ output: .gif file containing quality control image for the registration process. Made for use in MultiQC report. pattern: "*_registration_antsapplytransforms_mqc.gif" + optional: true ontologies: [] versions: - versions.yml: diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap index 9f28397d..6c8f99aa 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap @@ -8,7 +8,7 @@ "id": "test", "single_end": false }, - "test__b0b0__warped.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" + "test__b0b0__warped.nii.gz:md5,54f953b796f87bc0765d401ab32e6450" ] ], "1": [ @@ -41,7 +41,7 @@ "id": "test", "single_end": false }, - "test__b0b0__warped.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" + "test__b0b0__warped.nii.gz:md5,54f953b796f87bc0765d401ab32e6450" ] ] } @@ -64,4 +64,4 @@ }, "timestamp": "2025-10-09T20:09:58.870177157" } -} +} \ No newline at end of file diff --git a/modules/nf-neuro/registration/convert/main.nf b/modules/nf-neuro/registration/convert/main.nf index a48e064a..29e96d16 100644 --- a/modules/nf-neuro/registration/convert/main.nf +++ b/modules/nf-neuro/registration/convert/main.nf @@ -74,7 +74,7 @@ process REGISTRATION_CONVERT { cat <<-END_VERSIONS > versions.yml "${task.process}": - Freesurfer: \$(mri_convert -version | grep "freesurfer" | sed -E 's/.* ([0-9.]+).*/\\1/') + freesurfer: \$(mri_convert -version | grep "freesurfer" | sed -E 's/.* ([0-9.]+).*/\\1/') END_VERSIONS """ @@ -96,9 +96,9 @@ process REGISTRATION_CONVERT { """ set +e function handle_code () { - local code=\$? - ignore=( 1 ) - [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code + local code=\$? + ignore=( 1 ) + [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code } trap 'handle_code' ERR @@ -109,7 +109,7 @@ process REGISTRATION_CONVERT { cat <<-END_VERSIONS > versions.yml "${task.process}": - Freesurfer: \$(mri_convert -version | grep "freesurfer" | sed -E 's/.* ([0-9.]+).*/\\1/') + freesurfer: \$(mri_convert -version | grep "freesurfer" | sed -E 's/.* ([0-9.]+).*/\\1/') END_VERSIONS """ } diff --git a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap index 79d15fd5..4d4b8c8e 100644 --- a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap @@ -2,27 +2,27 @@ "registration - convert - stub-run": { "content": [ [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.2" + "nextflow": "25.04.7" }, - "timestamp": "2025-05-30T21:45:21.615899949" + "timestamp": "2025-10-02T20:44:37.839613055" }, "registration - convert - affine - to lta (needs source)": { "content": [ "test__out_affine.lta", [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, - "timestamp": "2025-07-25T15:15:22.167873891" + "timestamp": "2025-10-02T20:44:27.597924954" }, "registration - convert - affine - lta to fsl": { "content": [ @@ -36,7 +36,7 @@ ] ], "1": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ], "transformation": [ [ @@ -47,15 +47,15 @@ ] ], "versions": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, - "timestamp": "2025-07-25T15:15:03.099213703" + "timestamp": "2025-10-02T20:44:05.956240243" }, "registration - convert - mixed - to itk": { "content": [ @@ -69,7 +69,7 @@ ] ], "1": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ], "transformation": [ [ @@ -80,15 +80,15 @@ ] ], "versions": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, - "timestamp": "2025-07-25T15:15:12.599002015" + "timestamp": "2025-10-02T20:44:17.27523449" }, "registration - convert - deformation - ras to itk (lps)": { "content": [ @@ -102,7 +102,7 @@ ] ], "1": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ], "transformation": [ [ @@ -113,14 +113,14 @@ ] ], "versions": [ - "versions.yml:md5,9912ec095965c1ff571f77b447c18f92" + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, - "timestamp": "2025-07-25T14:54:35.309900291" + "timestamp": "2025-10-02T20:43:52.34178625" } -} +} \ No newline at end of file diff --git a/modules/nf-neuro/registration/easyreg/meta.yml b/modules/nf-neuro/registration/easyreg/meta.yml index b7a9e93d..9e5c89ca 100644 --- a/modules/nf-neuro/registration/easyreg/meta.yml +++ b/modules/nf-neuro/registration/easyreg/meta.yml @@ -93,6 +93,7 @@ output: type: file description: Forward deformation field, composed of all registration stages (affine+deformation). pattern: "*_forward0_warp.nii.gz" + optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format inverse_warp: @@ -105,6 +106,7 @@ output: type: file description: Backward deformation field, composed of all registration stages (inv-deformation+inv-affine). pattern: "*_backward0_warp.nii.gz" + optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format segmentation_warped: @@ -119,9 +121,9 @@ output: SynthSeg v2 (non-robust) segmentation + parcellation on the warped image. Will produce image only if not passed as input. pattern: "*_warped_segmentation.nii.gz" + optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - optional: true fixed_segmentation_warped: - - meta: type: map @@ -134,9 +136,9 @@ output: SynthSeg v2 (non-robust) segmentation + parcellation on the reference image. Will produce image only if not passed as input. pattern: "*_warped_reference_segmentation.nii.gz" + optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - optional: true versions: - versions.yml: type: file diff --git a/modules/nf-neuro/registration/synthregistration/main.nf b/modules/nf-neuro/registration/synthregistration/main.nf index d6600196..dbf80725 100644 --- a/modules/nf-neuro/registration/synthregistration/main.nf +++ b/modules/nf-neuro/registration/synthregistration/main.nf @@ -29,7 +29,7 @@ process REGISTRATION_SYNTHREGISTRATION { def prefix = task.ext.prefix ?: "${meta.id}" def models = task.ext.models ?: ["affine", "deform"] - def weights = (task.ext.weight ?: [null] * models.size()).collect{ it ? "-w $it" : "none" }.join(" ") + def weights = (task.ext.weights ?: [null] * models.size()).collect{ it ? "-w $it" : "none" }.join(" ") def use_gpu = task.ext.use_gpu ? "-g" : "" def regularization = "-r ${task.ext.regularization ?: 0.5}" def steps = "-n ${task.ext.steps ?: 7 }" @@ -59,68 +59,59 @@ process REGISTRATION_SYNTHREGISTRATION { j=${models.size()} initializer="" init_assoc="" - for model in ${models.join(" ")} - do - echo "Processing model: \$model" - # Post-incrementation ensure no error on last index = 0 - ((j--)) - - weight="" - if [ "\${weights[i + skip]}" != "none" ] - then - weight="-w \${weights[i + skip]}" - - if [ "\$model" = "joint" ] - then - # Pre-incrementation ensure no error on first index = 0 - ((++skip)) - if [ "\${weights[i + skip]}" = "none" ] - then - echo "Joint deformations need 2 weights, only 1 given" - exit 1 - else - weight="\$weight -w \${weights[i + skip]}" + for model in ${models.join(" ")}; do + echo "Processing model: \$model" + # Post-incrementation ensure no error on last index = 0 + ((j--)) + + weight="" + if [ "\${weights[i + skip]}" != "none" ]; then + weight="-w \${weights[i + skip]}" + + if [ "\$model" = "joint" ]; then + # Pre-incrementation ensure no error on first index = 0 + ((++skip)) + if [ "\${weights[i + skip]}" = "none" ]; then + echo "Joint deformations need 2 weights, only 1 given" + exit 1 + else + weight="\$weight -w \${weights[i + skip]}" + fi fi fi - fi - - args="" - if [ \$model = "joint" ] || [ \$model = "deform" ] - then - args="$regularization $steps" - else - args="$update_header" - fi - - if [ \$initializer ] - then - args="\$args -i \$initializer" - fi - - mri_synthmorph register \$moving fixed.nii.gz -v -m \$model \$weight \$args \ - -t ${prefix}__forward\${j}_\$model.\${extension[\$model]} \ - -T ${prefix}__backward\${i}_\$model.\${extension[\$model]} \ - -o warped.nii.gz -j $task.cpus $extent $use_gpu - - if [ \$initializer ] - then - # rm \$initializer \$init_assoc - # Retag initializer file to standalone using sed - # - replace the number after forward/backward to standalone - mv \$initializer \$(echo "\$initializer" | sed -r 's/(_forward|_backward)[[:digit:]]+/\\1_standalone/') - mv \$init_assoc \$(echo "\$init_assoc" | sed -r 's/(_forward|_backward)[[:digit:]]+/\\1_standalone/') - fi - - if [ \${extension[\$model]} = "lta" ] - then - initializer=${prefix}__forward\${j}_\$model.\${extension[\$model]} - init_assoc=${prefix}__backward\${i}_\$model.\${extension[\$model]} - else - moving=warped.nii.gz - fi - - # Pre-incrementation ensure no error on first index = 0 - ((++i)) + + args="" + if [ \$model = "joint" ] || [ \$model = "deform" ]; then + args="$regularization $steps" + else + args="$update_header" + fi + + if [ \$initializer ]; then + args="\$args -i \$initializer" + fi + + mri_synthmorph register \$moving fixed.nii.gz -v -m \$model \$weight \$args \ + -t ${prefix}__forward\${j}_\$model.\${extension[\$model]} \ + -T ${prefix}__backward\${i}_\$model.\${extension[\$model]} \ + -o warped.nii.gz -j $task.cpus $extent $use_gpu + + if [ \$initializer ]; then + # Retag initializer file to standalone using sed + # - replace the number after forward/backward to standalone + mv \$initializer \$(echo "\$initializer" | sed -r 's/(_forward|_backward)[[:digit:]]+/\\1_standalone/') + mv \$init_assoc \$(echo "\$init_assoc" | sed -r 's/(_forward|_backward)[[:digit:]]+/\\1_standalone/') + fi + + if [ \${extension[\$model]} = "lta" ]; then + initializer=${prefix}__forward\${j}_\$model.\${extension[\$model]} + init_assoc=${prefix}__backward\${i}_\$model.\${extension[\$model]} + else + moving=warped.nii.gz + fi + + # Pre-incrementation ensure no error on first index = 0 + ((++i)) done diff --git a/modules/nf-neuro/registration/tractogram/main.nf b/modules/nf-neuro/registration/tractogram/main.nf index 4aa61c19..6358c728 100644 --- a/modules/nf-neuro/registration/tractogram/main.nf +++ b/modules/nf-neuro/registration/tractogram/main.nf @@ -2,10 +2,10 @@ process REGISTRATION_TRACTOGRAM { tag "$meta.id" label 'process_single' - container "scilus/scilpy:2.2.0_cpu" + container "scilus/scilus:2.2.0" input: - tuple val(meta), path(anat), path(affine), path(tractogram), path(ref), path(deformation) + tuple val(meta), path(anat), path(affine), path(tractogram), path(reference), path(deformation) output: tuple val(meta), path("*__*.{trk,tck}"), emit: tractogram @@ -17,7 +17,7 @@ process REGISTRATION_TRACTOGRAM { script: def prefix = task.ext.prefix ?: "${meta.id}" def suffix = task.ext.suffix ? "_${task.ext.suffix}" : "" - def reference = "$ref" ? "--reference $ref" : "" + reference = "$reference" ? "--reference $reference" : "" def in_deformation = "$deformation" ? "--in_deformation $deformation" : "" def inverse = task.ext.inverse ? "--inverse" : "" @@ -38,35 +38,35 @@ process REGISTRATION_TRACTOGRAM { || echo "TXT affine transform file conversion failed, using original file." fi - for tractogram in ${tractogram}; - do \ + for tractogram in ${tractogram}; do ext=\${tractogram#*.} bname=\$(basename \${tractogram} .\${ext} | sed 's/${prefix}_\\+//') - - scil_tractogram_apply_transform.py \$tractogram $anat \$affine \ - ${prefix}__\${bname}${suffix}.\${ext} \ - $in_deformation \ - $inverse \ - $reverse_operation \ - $reference \ - --keep_invalid -f - - if [[ "$invalid_management" == "keep" ]]; then - echo "Skip invalid streamline detection: ${prefix}__\${bname}${suffix}.\${ext}" - continue - fi - - scil_tractogram_remove_invalid tmp.trk ${prefix}__\${bname}${suffix}.\${ext}\ - $cut_invalid\ - $remove_single_point\ - $remove_overlapping_points\ - $threshold\ - $no_empty\ - -f + name=${prefix}__\${bname}${suffix}.\${ext} + + scil_tractogram_apply_transform \$tractogram $anat \$affine \$name \ + $in_deformation \ + $inverse \ + $reverse_operation \ + $reference \ + --keep_invalid -f + + if [[ "$invalid_management" == "keep" ]]; then + echo "Skip invalid streamline detection: \$name" + continue + fi + + scil_tractogram_remove_invalid \$name \$name \ + $cut_invalid\ + $remove_single_point\ + $remove_overlapping_points\ + $threshold\ + $no_empty\ + -f done cat <<-END_VERSIONS > versions.yml "${task.process}": + ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*v([0-9.a-zA-Z-]+).*/\\1/') scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ @@ -78,15 +78,16 @@ process REGISTRATION_TRACTOGRAM { scil_tractogram_apply_transform -h scil_tractogram_remove_invalid -h - for tractogram in ${tractogram}; - do \ + for tractogram in ${tractogram}; do ext=\${tractogram#*.} bname=\$(basename \${tractogram} .\${ext} | sed 's/${prefix}_\\+//') - + name=${prefix}__\${bname}${suffix}.\${ext} + touch \$name done cat <<-END_VERSIONS > versions.yml "${task.process}": + ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*v([0-9.a-zA-Z-]+).*/\\1/') scilpy: \$(uv pip -q -n list | grep scilpy | tr -s ' ' | cut -d' ' -f2) END_VERSIONS """ diff --git a/modules/nf-neuro/registration/tractogram/meta.yml b/modules/nf-neuro/registration/tractogram/meta.yml index 6530330f..886efe6c 100644 --- a/modules/nf-neuro/registration/tractogram/meta.yml +++ b/modules/nf-neuro/registration/tractogram/meta.yml @@ -7,6 +7,10 @@ keywords: - Bundles - Tractogram tools: + - ANTs: + description: perform registration using transform as input + homepage: https://antsx.github.io/ANTsRCore/reference/antsApplyTransforms.html + identifier: "" - scilpy: description: The Sherbrooke Connectivity Imaging Lab (SCIL) Python dMRI processing toolbox. @@ -79,7 +83,7 @@ input: pattern: "*.{trk,tck}" mandatory: true ontologies: [] - - ref: + - reference: type: file description: Reference anatomy for tck/vtk/fib/dpy file support (.nii or .nii.gz) (optional) diff --git a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap index e8088aac..4a3c029e 100644 --- a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap @@ -12,7 +12,7 @@ ] ], "1": [ - "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" + "versions.yml:md5,452295f58ea9ab6aa25264de21b111c1" ], "tractogram": [ [ @@ -24,15 +24,15 @@ ] ], "versions": [ - "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" + "versions.yml:md5,452295f58ea9ab6aa25264de21b111c1" ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, - "timestamp": "2025-07-30T17:00:29.348451708" + "timestamp": "2025-10-02T20:58:49.616623032" }, "registration - tractogram_bundles": { "content": [ @@ -55,12 +55,9 @@ ] ], "1": [ - "versions.yml:md5,504210d056544efae377411b749443e5" - ], - "versions": [ - "versions.yml:md5,504210d056544efae377411b749443e5" + "versions.yml:md5,452295f58ea9ab6aa25264de21b111c1" ], - "warped_tractogram": [ + "tractogram": [ [ { "id": "test", @@ -78,7 +75,7 @@ ] ], "versions": [ - "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" + "versions.yml:md5,452295f58ea9ab6aa25264de21b111c1" ] } ], @@ -86,19 +83,19 @@ "nf-test": "0.9.0", "nextflow": "25.04.7" }, - "timestamp": "2025-09-22T22:17:00.981071105" + "timestamp": "2025-10-02T20:57:42.535433219" }, "registration - tractogram - stub-run": { "content": [ [ - "versions.yml:md5,504210d056544efae377411b749443e5" + "versions.yml:md5,452295f58ea9ab6aa25264de21b111c1" ] ], "meta": { "nf-test": "0.9.0", "nextflow": "25.04.7" }, - "timestamp": "2025-09-22T22:17:25.469054766" + "timestamp": "2025-10-02T20:59:23.756300025" }, "registration - tractogram - custom suffix": { "content": [ @@ -113,12 +110,9 @@ ] ], "1": [ - "versions.yml:md5,504210d056544efae377411b749443e5" + "versions.yml:md5,452295f58ea9ab6aa25264de21b111c1" ], - "versions": [ - "versions.yml:md5,504210d056544efae377411b749443e5" - ], - "warped_tractogram": [ + "tractogram": [ [ { "id": "test", @@ -128,7 +122,7 @@ ] ], "versions": [ - "versions.yml:md5,616950ab6895e0c55937a4ca94a64fea" + "versions.yml:md5,452295f58ea9ab6aa25264de21b111c1" ] } ], @@ -136,6 +130,6 @@ "nf-test": "0.9.0", "nextflow": "25.04.7" }, - "timestamp": "2025-09-22T22:17:13.547090754" + "timestamp": "2025-10-02T20:58:16.81646804" } -} +} \ No newline at end of file From efc3a23543cfee69b591a2c012dde2b10603a06c Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Fri, 10 Oct 2025 16:45:02 +0000 Subject: [PATCH 24/37] update subworkflows tests --- .../bundle_seg/tests/main.nf.test.snap | 25 +++- .../tests/main.nf.test.snap | 110 +++++++++++++++++- .../registration/tests/main.nf.test.snap | 12 +- .../tractoflow/tests/main.nf.test.snap | 1 + 4 files changed, 139 insertions(+), 9 deletions(-) diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index d3bbe14f..d4dfc81f 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -50,6 +50,29 @@ "nf-test": "0.9.0", "nextflow": "25.04.7" }, - "timestamp": "2025-10-17T17:38:41.717732229" + "timestamp": "2025-10-08T14:45:55.930099672" + }, + "rbx - download atlas - ants registration": { + "content": [ + { + "bundles": [ + [ + { + "id": "test" + }, + "test__AF_L_cleaned.trk" + ] + ], + "versions": [ + "versions.yml:md5,386ca841f44a73e4f5cf04171ce7f503", + "versions.yml:md5,afaf6c2953accc507d8777303eea8718" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "25.04.7" + }, + "timestamp": "2025-10-08T14:42:39.410389277" } } \ No newline at end of file diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap index 60dca327..09c38865 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap @@ -42,6 +42,20 @@ "ch_t2w_tpl": [ "template__image_bet.nii.gz" ], + "mqc": [ + [ + { + "id": "test" + }, + "test_IFGWM_labels_map_registration_antsapplytransforms_mqc.gif" + ], + [ + { + "id": "test" + }, + "test_IFGWM_registration_antsapplytransforms_mqc.gif" + ] + ], "versions": [ "versions.yml:md5,08c023826481c9130c3914096cda7f63", "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", @@ -103,6 +117,18 @@ "template__image_bet.nii.gz" ], "mqc": [ + [ + { + "id": "test" + }, + "test_IFGWM_labels_map_registration_antsapplytransforms_mqc.gif" + ], + [ + { + "id": "test" + }, + "test_IFGWM_registration_antsapplytransforms_mqc.gif" + ], [ { "id": "test" @@ -125,6 +151,86 @@ "nf-test": "0.9.0", "nextflow": "25.04.7" }, - "timestamp": "2025-10-17T17:39:09.650176125" + "timestamp": "2025-10-08T14:52:05.229017105" + }, + "Template MNI152NLin2009cAsym - local templates": { + "content": [ + { + "ch_registered_anat": [ + [ + { + "id": "test" + }, + "test__t1_warped.nii.gz" + ] + ], + "ch_registered_labels_files": [ + [ + { + "id": "test" + }, + "test__IFGWM_labels_map__warped.nii.gz" + ] + ], + "ch_registered_nifti_files": [ + [ + { + "id": "test" + }, + "test__IFGWM__warped.nii.gz" + ] + ], + "ch_registered_trk_files": [ + [ + { + "id": "test" + }, + "test__IFGWM.trk", + "test__IFGWM_color.trk", + "test__IFGWM_uni.trk" + ] + ], + "ch_t1w_tpl": [ + "template__image_bet.nii.gz" + ], + "ch_t2w_tpl": [ + "template__image_bet.nii.gz" + ], + "mqc": [ + [ + { + "id": "test" + }, + "test_IFGWM_labels_map_registration_antsapplytransforms_mqc.gif" + ], + [ + { + "id": "test" + }, + "test_IFGWM_registration_antsapplytransforms_mqc.gif" + ], + [ + { + "id": "test" + }, + "test__registration_ants_mqc.gif" + ] + ], + "versions": [ + "versions.yml:md5,08c023826481c9130c3914096cda7f63", + "versions.yml:md5,4e02408f236932635d1e7585d80d16a1", + "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", + "versions.yml:md5,53e0a593f56efd67061357b22888233f", + "versions.yml:md5,82fa7e33467013d6fb309385e7a70aba", + "versions.yml:md5,e5d4ec0205b4e948c5e5c3e4579ce5d0", + "versions.yml:md5,ea689c85377dd23d74af147457113bf6" + ] + } + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "25.04.7" + }, + "timestamp": "2025-10-08T14:49:39.690526638" } -} +} \ No newline at end of file diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 4b072c58..08b4cc35 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -63,16 +63,16 @@ ] ], "versions": [ - "versions.yml:md5,5f2030eca02186c4f9b3e76425f94bf1", + "versions.yml:md5,300199ef2ea6dd6438553c3ec2615e58", "versions.yml:md5,f0fa799dd0d27d1974ea409d9c9e5da7" ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, - "timestamp": "2025-07-30T02:55:56.619117796" + "timestamp": "2025-10-08T15:14:48.304234548" }, "registration - easyreg": { "content": [ @@ -248,7 +248,7 @@ ] ], "versions": [ - "versions.yml:md5,7b059759af9e9bd4711e94db65e61095" + "versions.yml:md5,5f3f8c831b55885ffcc7bd976939dbad" ], "warp": [ [ @@ -261,10 +261,10 @@ } ], "meta": { - "nf-test": "0.9.2", + "nf-test": "0.9.0", "nextflow": "25.04.7" }, - "timestamp": "2025-09-20T13:03:27.206157" + "timestamp": "2025-10-08T15:13:44.415238887" }, "registration - ANTs - Anat to DWI": { "content": [ diff --git a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap index 75db8890..0153666e 100644 --- a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap @@ -376,6 +376,7 @@ ], "versions": [ "versions.yml:md5,0db65009e955d16a3cf997ed4401166d", + "versions.yml:md5,1019ce5b5db942aa4e239be81640fe1a", "versions.yml:md5,21aeeda82df6de4b5bdd1c6bb9930eb0", "versions.yml:md5,46756f8a550da8585f854b45afd1036d", "versions.yml:md5,5011203328febedfa9c5af5684bcc20c", From c18142d4ce012e5e79a6e54817c0ace83755150d Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 15 Oct 2025 17:47:00 +0000 Subject: [PATCH 25/37] uniformize naming, fix convert -h in stubs (bad), scope trap to prevent actual error gobbling in registration stubs --- .../nf-neuro/registration/anattodwi/main.nf | 36 ++--- .../nf-neuro/registration/anattodwi/meta.yml | 40 +++--- .../anattodwi/tests/main.nf.test.snap | 55 +++++--- modules/nf-neuro/registration/ants/main.nf | 26 ++-- modules/nf-neuro/registration/ants/meta.yml | 38 ++--- .../registration/ants/tests/main.nf.test.snap | 2 +- .../registration/antsapplytransforms/main.nf | 10 +- modules/nf-neuro/registration/easyreg/main.nf | 4 +- .../nf-neuro/registration/easyreg/meta.yml | 4 +- .../registration/easyreg/tests/main.nf.test | 4 +- .../registration/synthregistration/main.nf | 16 +-- .../registration/synthregistration/meta.yml | 40 +++--- .../synthregistration/tests/main.nf.test.snap | 42 +++--- .../nf-neuro/registration/tractogram/main.nf | 4 +- .../nf-neuro/registration/tractogram/meta.yml | 2 +- .../tests/main.nf.test.snap | 2 +- subworkflows/nf-neuro/bundle_seg/main.nf | 2 +- .../nf-neuro/output_template_space/main.nf | 10 +- .../preproc_dwi/tests/main.nf.test.snap | 2 +- subworkflows/nf-neuro/registration/main.nf | 133 +++++++++--------- subworkflows/nf-neuro/registration/meta.yml | 65 +++++---- .../registration/tests/main.nf.test.snap | 50 +++---- subworkflows/nf-neuro/tractoflow/main.nf | 10 +- 23 files changed, 301 insertions(+), 296 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index 4765af88..3daa2440 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -9,14 +9,14 @@ process REGISTRATION_ANATTODWI { output: tuple val(meta), path("*_warped.nii.gz") , emit: anat_warped - tuple val(meta), path("*__forward1_affine.mat") , emit: affine - tuple val(meta), path("*__forward0_warp.nii.gz") , emit: warp - tuple val(meta), path("*__backward1_warp.nii.gz") , emit: inverse_warp - tuple val(meta), path("*__backward0_affine.mat") , emit: inverse_affine - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform + tuple val(meta), path("*__forward1_affine.mat") , emit: forward_affine + tuple val(meta), path("*__forward0_warp.nii.gz") , emit: forward_warp + tuple val(meta), path("*__backward1_warp.nii.gz") , emit: backward_warp + tuple val(meta), path("*__backward0_affine.mat") , emit: backward_affine + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: forward_image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: backward_image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: forward_tractogram_transform + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: backward_tractogram_transform tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions @@ -34,7 +34,7 @@ process REGISTRATION_ANATTODWI { export ANTS_RANDOM_SEED=1234 antsRegistration --dimensionality 3 --float 0\ - --output [trans,warped.nii.gz]\ + --output [forward,warped.nii.gz]\ --interpolation Linear --use-histogram-matching 0\ --winsorize-image-intensities [0.005,0.995]\ --initial-moving-transform [$fixed_reference,$moving_anat,1]\ @@ -56,9 +56,9 @@ process REGISTRATION_ANATTODWI { moving_id=\${moving_id#${meta.id}__*} mv warped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz - mv trans0GenericAffine.mat ${prefix}__forward1_affine.mat - mv trans1Warp.nii.gz ${prefix}__forward0_warp.nii.gz - mv trans1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz + mv forward0GenericAffine.mat ${prefix}__forward1_affine.mat + mv forward1Warp.nii.gz ${prefix}__forward0_warp.nii.gz + mv forward1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz antsApplyTransforms -d 3 -i $moving_anat -r $fixed_reference \ -o Linear[${prefix}__backward0_affine.mat] \ @@ -130,17 +130,11 @@ process REGISTRATION_ANATTODWI { def run_qc = task.ext.run_qc as Boolean || false """ - set +e - function handle_code () { - local code=\$? - ignore=( 1 ) - [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code - } - trap 'handle_code' ERR - antsRegistration -h + antsApplyTransforms -h + mrconvert -h scil_viz_volume_screenshot -h - convert -h + convert -help . moving_id=\$(basename $moving_anat .nii.gz) moving_id=\${moving_id#${meta.id}__*} diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index 2230f228..9ff1c342 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -70,7 +70,7 @@ output: pattern: "*_warped.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - affine: + forward_affine: - - meta: type: map description: | @@ -78,10 +78,10 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__forward1_affine.mat": type: file - description: Affine transformation matrix file. + description: Affine transformation matrix to fixed space. pattern: "*__forward1_affine.mat" ontologies: [] - warp: + forward_warp: - - meta: type: map description: | @@ -89,11 +89,11 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__forward0_warp.nii.gz": type: file - description: Deformation field file. + description: Deformation field to fixed space. pattern: "*__forward0_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - inverse_warp: + backward_warp: - - meta: type: map description: | @@ -101,11 +101,11 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__backward1_warp.nii.gz": type: file - description: Inverse deformation field file. + description: Deformation field to moving space. pattern: "*__backward1_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - inverse_affine: + backward_affine: - - meta: type: map description: | @@ -113,10 +113,10 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__backward0_affine.mat": type: file - description: Inverse affine transformation matrix file. + description: Affine transformation matrix to moving space. pattern: "*__backward0_affine.mat" ontologies: [] - image_transform: + forward_image_transform: - - meta: type: map description: | @@ -125,11 +125,11 @@ output: - "*__forward*.{nii.gz,mat}": type: list description: | - Tuple, Transformation files to warp images in the correct order - for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. + Tuple, Transformation files to warp images in fixed space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_warp, forward_affine ] ]. pattern: "*__forward*.{nii.gz,mat}" ontologies: [] - inverse_image_transform: + backward_image_transform: - - meta: type: map description: | @@ -138,11 +138,11 @@ output: - "*__backward*.{nii.gz,mat}": type: list description: | - Tuple, Transformation files to warp images in the correct order for - REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. + Tuple, transformation files to warp images in moving space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. pattern: "*__backward*.{nii.gz,mat}" ontologies: [] - tractogram_transform: + forward_tractogram_transform: - - meta: type: map description: | @@ -151,11 +151,11 @@ output: - "*__backward*.{nii.gz,mat}": type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + Tuple, transformation files to warp tractograms into fixed space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. pattern: "*__backward*.{nii.gz,mat}" ontologies: [] - inverse_tractogram_transform: + backward_tractogram_transform: - - meta: type: map description: | @@ -164,8 +164,8 @@ output: - "*__forward*.{nii.gz,mat}": type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + Tuple, transformation files to warp tractograms into moving space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_affine, forward_warp ] ]. pattern: "*__forward*.{nii.gz,mat}" ontologies: [] mqc: diff --git a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap index 90440bb6..d90cfd42 100644 --- a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap @@ -53,25 +53,37 @@ "5": [ "versions.yml:md5,f49f4ab58360830a5cdb39d7530b45b1" ], - "affine": [ + "anat_warped": [ [ { "id": "test", "single_end": false }, - "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + "test__T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" ] ], - "anat_warped": [ + "backward_affine": [ [ { "id": "test", "single_end": false }, - "test__T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" + "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" + ] + ], + "backward_image_transform": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + ] ] ], - "image_transform": [ + "backward_tractogram_transform": [ [ { "id": "test", @@ -83,28 +95,25 @@ ] ] ], - "inverse_affine": [ + "backward_warp": [ [ { "id": "test", "single_end": false }, - "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" + "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" ] ], - "inverse_image_transform": [ + "forward_affine": [ [ { "id": "test", "single_end": false }, - [ - "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", - "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" - ] + "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" ] ], - "inverse_tractogram_transform": [ + "forward_image_transform": [ [ { "id": "test", @@ -116,34 +125,34 @@ ] ] ], - "inverse_warp": [ + "forward_tractogram_transform": [ [ { "id": "test", "single_end": false }, - "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + [ + "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + ] ] ], - "mqc": [ + "forward_warp": [ [ { "id": "test", "single_end": false }, - "test_registration_anattodwi_mqc.gif:md5,9cbc1ce8755821996dae18080cf0a23c" + "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" ] ], - "tractogram_transform": [ + "mqc": [ [ { "id": "test", "single_end": false }, - [ - "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", - "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" - ] + "test_registration_anattodwi_mqc.gif:md5,9cbc1ce8755821996dae18080cf0a23c" ] ], "versions": [ @@ -174,7 +183,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-09T20:08:45.279539751" } diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index 5676650b..57a7a37c 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -10,14 +10,14 @@ process REGISTRATION_ANTS { output: tuple val(meta), path("*_warped.nii.gz") , emit: image_warped - tuple val(meta), path("*__forward1_affine.mat") , emit: affine, optional: true - tuple val(meta), path("*__forward0_warp.nii.gz") , emit: warp, optional: true - tuple val(meta), path("*__backward1_warp.nii.gz") , emit: inverse_warp, optional: true - tuple val(meta), path("*__backward0_affine.mat") , emit: inverse_affine, optional: true - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: tractogram_transform - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: inverse_tractogram_transform + tuple val(meta), path("*__forward1_affine.mat") , emit: forward_affine, optional: true + tuple val(meta), path("*__forward0_warp.nii.gz") , emit: forward_warp, optional: true + tuple val(meta), path("*__backward1_warp.nii.gz") , emit: backward_warp, optional: true + tuple val(meta), path("*__backward0_affine.mat") , emit: backward_affine, optional: true + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: forward_image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: backward_image_transform + tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: forward_tractogram_transform + tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: backward_tractogram_transform tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions @@ -143,11 +143,15 @@ process REGISTRATION_ANTS { ignore=( 1 ) [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code } - trap 'handle_code' ERR - antsRegistrationSyNQuick.sh -h + # Local trap to ignore awaited non-zero exit codes + { + trap 'handle_code' ERR + antsRegistrationSyNQuick.sh -h + } + antsApplyTransforms -h - convert -h + convert -help . scil_viz_volume_screenshot -h touch ${prefix}__t1_warped.nii.gz diff --git a/modules/nf-neuro/registration/ants/meta.yml b/modules/nf-neuro/registration/ants/meta.yml index 2f07250c..e5b677f5 100644 --- a/modules/nf-neuro/registration/ants/meta.yml +++ b/modules/nf-neuro/registration/ants/meta.yml @@ -9,9 +9,9 @@ description: | Main features: (1) Supports multiple transformation types (see `transform` argument). (2) Supports initial transformations (see `initial_transform` argument) via a closure, e.g. `{ [$fixedimage,$movingimage,0] }`. - (3) Automatic creation of inverse transformations matrices. - (4) Curated combined output transformations for REGISTRATION_ANTSAPPLYTRANSFORMS and - REGISTRATION_TRANSFORMTRACTOGRAM processes : `image_transform`, `tractogram_transform`, and their inverse. + (3) Automatic creation of backward (inverse) transformations matrices. + (4) Curated combined output transformations for REGISTRATION_ANTSAPPLYTRANSFORMS and REGISTRATION_TRANSFORMTRACTOGRAM + processes : `forward_image_transform`, `forward_tractogram_transform`, and their `backward` versions. (5) Quality control (QC) image generation for MultiQC reports. keywords: - nifti @@ -161,7 +161,7 @@ output: pattern: "*_warped.nii.gz" ontologies: - edam: http://edamontology.org/format_3989 # GZIP format - affine: + forward_affine: - - meta: type: map description: | @@ -173,7 +173,7 @@ output: pattern: "*__forward1_affine.mat" optional: true ontologies: [] - warp: + forward_warp: - - meta: type: map description: | @@ -186,7 +186,7 @@ output: optional: true ontologies: - edam: http://edamontology.org/format_3989 # GZIP format - inverse_warp: + backward_warp: - - meta: type: map description: | @@ -199,7 +199,7 @@ output: optional: true ontologies: - edam: http://edamontology.org/format_3989 # GZIP format - inverse_affine: + backward_affine: - - meta: type: map description: | @@ -211,7 +211,7 @@ output: pattern: "*__backward0_affine.mat" optional: true ontologies: [] - image_transform: + forward_image_transform: - - meta: type: map description: | @@ -220,11 +220,11 @@ output: - "*__forward*.{nii.gz,mat}": type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + Tuple, Transformation files to warp images in fixed space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_warp, forward_affine ] ]. pattern: "*__forward*.{nii.gz,mat}" ontologies: [] - inverse_image_transform: + backward_image_transform: - - meta: type: map description: | @@ -233,11 +233,11 @@ output: - "*__backward*.{nii.gz,mat}": type: list description: | - Tuple, Inverse transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + Tuple, transformation files to warp images in moving space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. pattern: "*__backward*.{nii.gz,mat}" ontologies: [] - tractogram_transform: + forward_tractogram_transform: - - meta: type: map description: | @@ -246,11 +246,11 @@ output: - "*__backward*.{nii.gz,mat}": type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + Tuple, transformation files to warp tractograms into fixed space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. pattern: "*__backward*.{nii.gz,mat}" ontologies: [] - inverse_tractogram_transform: + backward_tractogram_transform: - - meta: type: map description: | @@ -259,8 +259,8 @@ output: - "*__forward*.{nii.gz,mat}": type: list description: | - Tuple, Inverse transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + Tuple, transformation files to warp tractograms into moving space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_affine, forward_warp ] ]. pattern: "*__forward*.{nii.gz,mat}" ontologies: [] mqc: diff --git a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap index 39b2b284..4bb9572b 100644 --- a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap @@ -322,7 +322,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-09T20:09:40.567822165" } diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index 906fd88d..0083ee33 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -110,17 +110,9 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { def run_qc = task.ext.run_qc as Boolean || false """ - set +e - function handle_code () { - local code=\$? - ignore=( 1 ) - [[ " \${ignore[@]} " =~ " \$code " ]] || exit \$code - } - trap 'handle_code' ERR - antsApplyTransforms -h - convert -h scil_viz_volume_screenshot -h + convert -help . for image in $images; do ext=\${image#*.} diff --git a/modules/nf-neuro/registration/easyreg/main.nf b/modules/nf-neuro/registration/easyreg/main.nf index e6ee6a5d..4ab2bae9 100644 --- a/modules/nf-neuro/registration/easyreg/main.nf +++ b/modules/nf-neuro/registration/easyreg/main.nf @@ -12,8 +12,8 @@ process REGISTRATION_EASYREG { output: tuple val(meta), path("*_warped.nii.gz") , emit: image_warped tuple val(meta), path("*_warped_reference.nii.gz") , emit: fixed_warped - tuple val(meta), path("*_forward0_warp.nii.gz") , emit: warp, optional: true - tuple val(meta), path("*_backward0_warp.nii.gz") , emit: inverse_warp, optional: true + tuple val(meta), path("*_forward0_warp.nii.gz") , emit: forward_warp, optional: true + tuple val(meta), path("*_backward0_warp.nii.gz") , emit: backward_warp, optional: true tuple val(meta), path("*_warped_segmentation.nii.gz") , emit: segmentation_warped, optional: true tuple val(meta), path("*_warped_reference_segmentation.nii.gz") , emit: fixed_segmentation_warped, optional: true path "versions.yml" , emit: versions diff --git a/modules/nf-neuro/registration/easyreg/meta.yml b/modules/nf-neuro/registration/easyreg/meta.yml index 9e5c89ca..45af4f3a 100644 --- a/modules/nf-neuro/registration/easyreg/meta.yml +++ b/modules/nf-neuro/registration/easyreg/meta.yml @@ -83,7 +83,7 @@ output: pattern: "*_warped_reference.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - warp: + forward_warp: - - meta: type: map description: | @@ -96,7 +96,7 @@ output: optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - inverse_warp: + backward_warp: - - meta: type: map description: | diff --git a/modules/nf-neuro/registration/easyreg/tests/main.nf.test b/modules/nf-neuro/registration/easyreg/tests/main.nf.test index 4855a21d..17b9834c 100644 --- a/modules/nf-neuro/registration/easyreg/tests/main.nf.test +++ b/modules/nf-neuro/registration/easyreg/tests/main.nf.test @@ -61,8 +61,8 @@ nextflow_process { file(process.out.segmentation_warped.get(0).get(1)).name, niftiMD5SUM(process.out.fixed_warped.get(0).get(1), 6), niftiMD5SUM(process.out.image_warped.get(0).get(1), 6), - niftiMD5SUM(process.out.warp.get(0).get(1), 6), - niftiMD5SUM(process.out.inverse_warp.get(0).get(1), 6), + niftiMD5SUM(process.out.forward_warp.get(0).get(1), 6), + niftiMD5SUM(process.out.backward_warp.get(0).get(1), 6), process.out.versions ).match() } ) diff --git a/modules/nf-neuro/registration/synthregistration/main.nf b/modules/nf-neuro/registration/synthregistration/main.nf index dbf80725..1272b054 100644 --- a/modules/nf-neuro/registration/synthregistration/main.nf +++ b/modules/nf-neuro/registration/synthregistration/main.nf @@ -12,14 +12,14 @@ process REGISTRATION_SYNTHREGISTRATION { output: tuple val(meta), path("*__warped.nii.gz") , emit: image_warped - tuple val(meta), path("*__forward{0,1,_standalone}_affine.lta") , emit: affine, optional: true - tuple val(meta), path("*__forward0_deform.nii.gz") , emit: warp, optional: true - tuple val(meta), path("*__backward1_deform.nii.gz") , emit: inverse_warp, optional: true - tuple val(meta), path("*__backward{0,_standalone}_affine.lta") , emit: inverse_affine, optional: true - tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: image_transform - tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: inverse_image_transform - tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: tractogram_transform - tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: inverse_tractogram_transform + tuple val(meta), path("*__forward{0,1,_standalone}_affine.lta") , emit: forward_affine, optional: true + tuple val(meta), path("*__forward0_deform.nii.gz") , emit: forward_warp, optional: true + tuple val(meta), path("*__backward1_deform.nii.gz") , emit: backward_warp, optional: true + tuple val(meta), path("*__backward{0,_standalone}_affine.lta") , emit: backward_affine, optional: true + tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: forward_image_transform + tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: backward_image_transform + tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: forward_tractogram_transform + tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: backward_tractogram_transform path "versions.yml" , emit: versions when: diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthregistration/meta.yml index 94254f90..f162757f 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthregistration/meta.yml @@ -99,7 +99,7 @@ output: pattern: "*__warped.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - affine: + forward_affine: - - meta: type: map description: | @@ -107,11 +107,11 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__forward{0,1,_standalone}_affine.lta": type: file - description: Affine transformation matrix file. + description: Affine transformation matrix to fixed space. pattern: "*__forward{0,1,_standalone}_affine.lta" optional: true ontologies: [] - warp: + forward_warp: - - meta: type: map description: | @@ -119,12 +119,12 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__forward0_deform.nii.gz": type: file - description: Deformation field file. + description: Deformation field to fixed space. pattern: "*__forward0_deform.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - inverse_warp: + backward_warp: - - meta: type: map description: | @@ -132,12 +132,12 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__backward1_deform.nii.gz": type: file - description: Inverse deformation field file. + description: Deformation field to moving space. pattern: "*__backward1_deform.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - inverse_affine: + backward_affine: - - meta: type: map description: | @@ -145,11 +145,11 @@ output: e.g. `[ id:'test', single_end:false ]` - "*__backward{0,_standalone}_affine.lta": type: file - description: Inverse affine transformation matrix file. + description: Affine transformation matrix to moving space. pattern: "*__backward{0,_standalone}_affine.lta" optional: true ontologies: [] - image_transform: + forward_image_transform: - - meta: type: map description: | @@ -158,11 +158,11 @@ output: - "*__forward[!_]*.{lta,nii.gz}": type: list description: | - Tuple, Transformation files to warp images in the correct order - for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. + Tuple, transformation files to warp images to fixed space, in the correct order + for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ forward_warp, forward_affine ] ]. pattern: "*__forward[!_]*.{lta,nii.gz}" ontologies: [] - inverse_image_transform: + backward_image_transform: - - meta: type: map description: | @@ -171,11 +171,11 @@ output: - "*__backward[!_]*.{lta,nii.gz}": type: list description: | - Tuple, Transformation files to warp images in the correct order for - REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. + Tuple, transformation files to warp images to moving space, in the correct order for + REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ backward_affine, backward_warp ] ]. pattern: "*__backward[!_]*.{lta,nii.gz}" ontologies: [] - tractogram_transform: + forward_tractogram_transform: - - meta: type: map description: | @@ -184,11 +184,11 @@ output: - "*__backward[!_]*.{lta,nii.gz}": type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + Tuple, transformation files to warp tractograms to fixed space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. pattern: "*__backward[!_]*.{lta,nii.gz}" ontologies: [] - inverse_tractogram_transform: + backward_tractogram_transform: - - meta: type: map description: | @@ -197,8 +197,8 @@ output: - "*__forward[!_]*.{lta,nii.gz}": type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + Tuple, transformation files to warp tractograms to moving space, in the correct order + for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_warp, forward_affine ] ]. pattern: "*__forward[!_]*.{lta,nii.gz}" ontologies: [] versions: diff --git a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap index 0cd594c3..1c229588 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap @@ -2,52 +2,52 @@ "registration - synthregistration": { "content": [ { - "affine": [ + "backward_affine": [ [ { "id": "test", "single_end": false }, - "test__forward_standalone_affine.lta" + "test__backward_standalone_affine.lta" ] ], - "image_transform": [ + "backward_image_transform": [ [ { "id": "test", "single_end": false }, - "test__forward0_deform.nii.gz" + "test__backward1_deform.nii.gz" ] ], - "image_warped": [ + "backward_tractogram_transform": [ [ { "id": "test", "single_end": false }, - "test__warped.nii.gz" + "test__forward0_deform.nii.gz" ] ], - "inverse_affine": [ + "backward_warp": [ [ { "id": "test", "single_end": false }, - "test__backward_standalone_affine.lta" + "test__backward1_deform.nii.gz" ] ], - "inverse_image_transform": [ + "forward_affine": [ [ { "id": "test", "single_end": false }, - "test__backward1_deform.nii.gz" + "test__forward_standalone_affine.lta" ] ], - "inverse_tractogram_transform": [ + "forward_image_transform": [ [ { "id": "test", @@ -56,7 +56,7 @@ "test__forward0_deform.nii.gz" ] ], - "inverse_warp": [ + "forward_tractogram_transform": [ [ { "id": "test", @@ -65,34 +65,34 @@ "test__backward1_deform.nii.gz" ] ], - "tractogram_transform": [ + "forward_warp": [ [ { "id": "test", "single_end": false }, - "test__backward1_deform.nii.gz" + "test__forward0_deform.nii.gz" ] ], - "versions": [ - "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" - ], - "warp": [ + "image_warped": [ [ { "id": "test", "single_end": false }, - "test__forward0_deform.nii.gz" + "test__warped.nii.gz" ] + ], + "versions": [ + "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.7" }, - "timestamp": "2025-07-28T15:53:09.741422131" + "timestamp": "2025-10-14T21:29:05.976082158" }, "registration - synthregistration - stub-run": { "content": [ diff --git a/modules/nf-neuro/registration/tractogram/main.nf b/modules/nf-neuro/registration/tractogram/main.nf index 6358c728..34141237 100644 --- a/modules/nf-neuro/registration/tractogram/main.nf +++ b/modules/nf-neuro/registration/tractogram/main.nf @@ -8,8 +8,8 @@ process REGISTRATION_TRACTOGRAM { tuple val(meta), path(anat), path(affine), path(tractogram), path(reference), path(deformation) output: - tuple val(meta), path("*__*.{trk,tck}"), emit: tractogram - path "versions.yml" , emit: versions + tuple val(meta), path("*__*.{trk,tck}") , emit: tractogram + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when diff --git a/modules/nf-neuro/registration/tractogram/meta.yml b/modules/nf-neuro/registration/tractogram/meta.yml index 886efe6c..528df0fd 100644 --- a/modules/nf-neuro/registration/tractogram/meta.yml +++ b/modules/nf-neuro/registration/tractogram/meta.yml @@ -20,7 +20,7 @@ args: - inverse: type: boolean description: | - If true, the inverse affine transform will be applied to the tractogram. + If true, the affine transform will be inverted before being applied to the tractogram. default: false - reverse_operation: type: boolean diff --git a/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test.snap b/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test.snap index 6d011b38..b86d206d 100644 --- a/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/anatomical_segmentation/tests/main.nf.test.snap @@ -264,4 +264,4 @@ }, "timestamp": "2025-09-30T16:36:44.805357" } -} +} \ No newline at end of file diff --git a/subworkflows/nf-neuro/bundle_seg/main.nf b/subworkflows/nf-neuro/bundle_seg/main.nf index ef6128cd..a15af23b 100644 --- a/subworkflows/nf-neuro/bundle_seg/main.nf +++ b/subworkflows/nf-neuro/bundle_seg/main.nf @@ -96,7 +96,7 @@ workflow BUNDLE_SEG { // ** Perform bundle recognition and segmentation ** // ch_recognize_bundle = ch_tractogram - .join(REGISTRATION.out.affine) + .join(REGISTRATION.out.forward_affine) .combine(ch_atlas_config) .combine(ch_atlas_average) diff --git a/subworkflows/nf-neuro/output_template_space/main.nf b/subworkflows/nf-neuro/output_template_space/main.nf index 81b1f6c1..24dd7dc4 100644 --- a/subworkflows/nf-neuro/output_template_space/main.nf +++ b/subworkflows/nf-neuro/output_template_space/main.nf @@ -164,7 +164,7 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** Need to unpack the files and apply the transformation to each one ** // ch_files_to_transform = ch_nifti_files .join(REGISTRATION.out.image_warped) - .join(REGISTRATION.out.image_transform) + .join(REGISTRATION.out.forward_image_transform) WARPIMAGES ( ch_files_to_transform ) ch_versions = ch_versions.mix(WARPIMAGES.out.versions) @@ -173,7 +173,7 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** Same process for the masks ** // ch_masks_to_transform = ch_mask_files .join(REGISTRATION.out.image_warped) - .join(REGISTRATION.out.image_transform) + .join(REGISTRATION.out.forward_image_transform) WARPMASK ( ch_masks_to_transform ) ch_versions = ch_versions.mix(WARPMASK.out.versions) ch_mqc = ch_mqc.mix(WARPMASK.out.mqc) @@ -181,7 +181,7 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** Same process for the labels ** // ch_labels_to_transform = ch_labels_files .join(REGISTRATION.out.image_warped) - .join(REGISTRATION.out.image_transform) + .join(REGISTRATION.out.forward_image_transform) WARPLABELS ( ch_labels_to_transform ) ch_versions = ch_versions.mix(WARPLABELS.out.versions) ch_mqc = ch_mqc.mix(WARPLABELS.out.mqc) @@ -189,8 +189,8 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** Apply the transformation to the tractograms ** // ch_tractograms_to_transform = ch_trk_files .join(REGISTRATION.out.image_warped) - .join(REGISTRATION.out.inverse_affine) - .join(REGISTRATION.out.inverse_warp, remainder: true) + .join(REGISTRATION.out.backward_affine) + .join(REGISTRATION.out.backward_warp, remainder: true) .map{ meta, trk, image, affine, warp -> [meta, image, affine, trk, [], warp ?: []] } diff --git a/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap b/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap index aebab1b2..6d938a75 100644 --- a/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/preproc_dwi/tests/main.nf.test.snap @@ -324,4 +324,4 @@ }, "timestamp": "2025-10-22T13:36:58.836905415" } -} +} \ No newline at end of file diff --git a/subworkflows/nf-neuro/registration/main.nf b/subworkflows/nf-neuro/registration/main.nf index e7643d57..46c350b5 100644 --- a/subworkflows/nf-neuro/registration/main.nf +++ b/subworkflows/nf-neuro/registration/main.nf @@ -48,14 +48,14 @@ workflow REGISTRATION { // ** Set compulsory outputs ** // out_image_warped = REGISTRATION_EASYREG.out.image_warped - out_affine = Channel.empty() - out_warp = REGISTRATION_EASYREG.out.warp - out_inverse_affine = Channel.empty() - out_inverse_warp = REGISTRATION_EASYREG.out.inverse_warp - out_image_transform = REGISTRATION_EASYREG.out.warp - out_inverse_image_transform = REGISTRATION_EASYREG.out.inverse_warp - out_tractogram_transform = REGISTRATION_EASYREG.out.inverse_warp - out_inverse_tractogram_transform = REGISTRATION_EASYREG.out.warp + out_forward_affine = Channel.empty() + out_forward_warp = REGISTRATION_EASYREG.out.forward_warp + out_backward_affine = Channel.empty() + out_backward_warp = REGISTRATION_EASYREG.out.backward_warp + out_forward_image_transform = REGISTRATION_EASYREG.out.forward_warp + out_backward_image_transform = REGISTRATION_EASYREG.out.backward_warp + out_forward_tractogram_transform = REGISTRATION_EASYREG.out.backward_warp + out_backward_tractogram_transform = REGISTRATION_EASYREG.out.forward_warp // ** Set optional outputs. ** // // If segmentations are not provided as inputs, @@ -74,30 +74,30 @@ workflow REGISTRATION { // Tag all synthmorph transforms per type, and index if in a chain. This info will be // used after conversion to sort out the transforms from the conversion module. - ch_convert_affine = REGISTRATION_SYNTHREGISTRATION.out.affine - .map{ meta, affine -> [meta, [tag: "affine"], affine] } - ch_convert_warp = REGISTRATION_SYNTHREGISTRATION.out.warp - .map{ meta, warp -> [meta, [tag: "warp"], warp] } - ch_convert_inverse_affine = REGISTRATION_SYNTHREGISTRATION.out.inverse_affine - .map{ meta, inverse_affine -> [meta, [tag: "inverse_affine"], inverse_affine] } - ch_convert_inverse_warp = REGISTRATION_SYNTHREGISTRATION.out.inverse_warp - .map{ meta, inverse_warp -> [meta, [tag: "inverse_warp"], inverse_warp] } - ch_convert_image_transform = REGISTRATION_SYNTHREGISTRATION.out.image_transform - .map{ meta, transforms -> [meta, [tag: "image_transform"], 0.. [meta, [tag: "forward_affine"], forward_affine] } + ch_convert_forward_warp = REGISTRATION_SYNTHREGISTRATION.out.forward_warp + .map{ meta, forward_warp -> [meta, [tag: "forward_warp"], forward_warp] } + ch_convert_backward_affine = REGISTRATION_SYNTHREGISTRATION.out.backward_affine + .map{ meta, backward_affine -> [meta, [tag: "backward_affine"], backward_affine] } + ch_convert_backward_warp = REGISTRATION_SYNTHREGISTRATION.out.backward_warp + .map{ meta, backward_warp -> [meta, [tag: "backward_warp"], backward_warp] } + ch_convert_forward_image_transform = REGISTRATION_SYNTHREGISTRATION.out.forward_image_transform + .map{ meta, transforms -> [meta, [tag: "forward_image_transform"], 0.. [meta, tag + [idx: idx], transform]} - ch_convert_inverse_image_transform = REGISTRATION_SYNTHREGISTRATION.out.inverse_image_transform - .map{ meta, transforms -> [meta, [tag: "inverse_image_transform"], 0.. [meta, [tag: "backward_image_transform"], 0.. [meta, tag + [idx: idx], transform]} // Mix all transforms into a single channel for conversion - ch_convert = ch_convert_affine - .mix(ch_convert_warp) - .mix(ch_convert_inverse_affine) - .mix(ch_convert_inverse_warp) - .mix(ch_convert_image_transform) - .mix(ch_convert_inverse_image_transform) + ch_convert = ch_convert_forward_affine + .mix(ch_convert_forward_warp) + .mix(ch_convert_backward_affine) + .mix(ch_convert_backward_warp) + .mix(ch_convert_forward_image_transform) + .mix(ch_convert_backward_image_transform) .combine(ch_fixed_image, by: 0) .combine(ch_moving_image, by: 0) .map{ meta, tag, transform, fixed, moving -> @@ -118,35 +118,34 @@ workflow REGISTRATION { // Un-mix conversion outputs using the tags. Save indexes for output sorting ch_conversion_outputs = REGISTRATION_CONVERT.out.transformation .branch{ meta, transform -> - affine: meta.tag == "affine" + forward_affine: meta.tag == "forward_affine" return [meta.cache, transform] - warp: meta.tag == "warp" + forward_warp: meta.tag == "forward_warp" return [meta.cache, transform] - inverse_affine: meta.tag == "inverse_affine" + backward_affine: meta.tag == "backward_affine" return [meta.cache, transform] - inverse_warp: meta.tag == "inverse_warp" + backward_warp: meta.tag == "backward_warp" return [meta.cache, transform] - image_transform: meta.tag == "image_transform" + forward_image_transform: meta.tag == "forward_image_transform" return [meta.cache, [idx: meta.idx, trans: transform]] - inverse_image_transform: meta.tag == "inverse_image_transform" + backward_image_transform: meta.tag == "backward_image_transform" return [meta.cache, [idx: meta.idx, trans: transform]] } - // ** Set compulsory outputs ** // out_image_warped = REGISTRATION_SYNTHREGISTRATION.out.image_warped - out_affine = ch_conversion_outputs.affine - out_warp = ch_conversion_outputs.warp - out_inverse_affine = ch_conversion_outputs.inverse_affine - out_inverse_warp = ch_conversion_outputs.inverse_warp - out_image_transform = ch_conversion_outputs.image_transform + out_forward_affine = ch_conversion_outputs.forward_affine + out_forward_warp = ch_conversion_outputs.forward_warp + out_backward_affine = ch_conversion_outputs.backward_affine + out_backward_warp = ch_conversion_outputs.backward_warp + out_forward_image_transform = ch_conversion_outputs.forward_image_transform .groupTuple() .map{ meta, trans -> [meta, trans.sort{ t1, t2 -> t1.idx <=> t2.idx }.collect{ it.trans }] } - out_inverse_image_transform = ch_conversion_outputs.inverse_image_transform + out_backward_image_transform = ch_conversion_outputs.backward_image_transform .groupTuple() .map{ meta, trans -> [meta, trans.sort{ t1, t2 -> t1.idx <=> t2.idx }.collect{ it.trans }] } - out_tractogram_transform = out_inverse_image_transform - out_inverse_tractogram_transform = out_image_transform + out_forward_tractogram_transform = out_backward_image_transform + out_backward_tractogram_transform = out_forward_image_transform // ** and optional outputs. ** // out_ref_warped = Channel.empty() out_segmentation = Channel.empty() @@ -178,14 +177,14 @@ workflow REGISTRATION { // ** Set compulsory outputs ** // out_image_warped = REGISTRATION_ANATTODWI.out.anat_warped - out_affine = REGISTRATION_ANATTODWI.out.affine - out_warp = REGISTRATION_ANATTODWI.out.warp - out_inverse_affine = REGISTRATION_ANATTODWI.out.inverse_affine - out_inverse_warp = REGISTRATION_ANATTODWI.out.inverse_warp - out_image_transform = REGISTRATION_ANATTODWI.out.image_transform - out_inverse_image_transform = REGISTRATION_ANATTODWI.out.inverse_image_transform - out_tractogram_transform = REGISTRATION_ANATTODWI.out.tractogram_transform - out_inverse_tractogram_transform = REGISTRATION_ANATTODWI.out.inverse_tractogram_transform + out_forward_affine = REGISTRATION_ANATTODWI.out.forward_affine + out_forward_warp = REGISTRATION_ANATTODWI.out.forward_warp + out_backward_affine = REGISTRATION_ANATTODWI.out.backward_affine + out_backward_warp = REGISTRATION_ANATTODWI.out.backward_warp + out_forward_image_transform = REGISTRATION_ANATTODWI.out.forward_image_transform + out_backward_image_transform = REGISTRATION_ANATTODWI.out.backward_image_transform + out_forward_tractogram_transform = REGISTRATION_ANATTODWI.out.forward_tractogram_transform + out_backward_tractogram_transform = REGISTRATION_ANATTODWI.out.backward_tractogram_transform // ** Registration using ANTS SYN SCRIPTS ** // // Registration using antsRegistrationSyN.sh or antsRegistrationSyNQuick.sh, has @@ -204,14 +203,14 @@ workflow REGISTRATION { // ** Set compulsory outputs ** // out_image_warped = out_image_warped.mix(REGISTRATION_ANTS.out.image_warped) - out_affine = out_affine.mix(REGISTRATION_ANTS.out.affine) - out_warp = out_warp.mix(REGISTRATION_ANTS.out.warp) - out_inverse_affine = out_inverse_affine.mix(REGISTRATION_ANTS.out.inverse_affine) - out_inverse_warp = out_inverse_warp.mix(REGISTRATION_ANTS.out.inverse_warp) - out_image_transform = out_image_transform.mix(REGISTRATION_ANTS.out.image_transform) - out_inverse_image_transform = out_inverse_image_transform.mix(REGISTRATION_ANTS.out.inverse_image_transform) - out_tractogram_transform = out_tractogram_transform.mix(REGISTRATION_ANTS.out.tractogram_transform) - out_inverse_tractogram_transform = out_inverse_tractogram_transform.mix(REGISTRATION_ANTS.out.inverse_tractogram_transform) + out_forward_affine = out_forward_affine.mix(REGISTRATION_ANTS.out.forward_affine) + out_forward_warp = out_forward_warp.mix(REGISTRATION_ANTS.out.forward_warp) + out_backward_affine = out_backward_affine.mix(REGISTRATION_ANTS.out.backward_affine) + out_backward_warp = out_backward_warp.mix(REGISTRATION_ANTS.out.backward_warp) + out_forward_image_transform = out_forward_image_transform.mix(REGISTRATION_ANTS.out.forward_image_transform) + out_backward_image_transform = out_backward_image_transform.mix(REGISTRATION_ANTS.out.backward_image_transform) + out_forward_tractogram_transform = out_forward_tractogram_transform.mix(REGISTRATION_ANTS.out.forward_tractogram_transform) + out_backward_tractogram_transform = out_backward_tractogram_transform.mix(REGISTRATION_ANTS.out.backward_tractogram_transform) // **and optional outputs **// out_ref_warped = Channel.empty() @@ -220,20 +219,20 @@ workflow REGISTRATION { } emit: image_warped = out_image_warped // channel: [ val(meta), image ] - ref_warped = out_ref_warped // channel: [ val(meta), ref ] + reference_warped = out_ref_warped // channel: [ val(meta), ref ] // Individual transforms - affine = out_affine // channel: [ val(meta), ] - warp = out_warp // channel: [ val(meta), ] - inverse_warp = out_inverse_warp // channel: [ val(meta), ] - inverse_affine = out_inverse_affine // channel: [ val(meta), ] + forward_affine = out_forward_affine // channel: [ val(meta), ] + forward_warp = out_forward_warp // channel: [ val(meta), ] + backward_warp = out_backward_warp // channel: [ val(meta), ] + backward_affine = out_backward_affine // channel: [ val(meta), ] // Combined transforms - image_transform = out_image_transform // channel: [ val(meta), [ , ] ] - inverse_image_transform = out_inverse_image_transform // channel: [ val(meta), [ , ] ] - tractogram_transform = out_tractogram_transform // channel: [ val(meta), [ , ] ] - inverse_tractogram_transform = out_inverse_tractogram_transform // channel: [ val(meta), [ , ] ] + forward_image_transform = out_forward_image_transform // channel: [ val(meta), [ , ] ] + backward_image_transform = out_backward_image_transform // channel: [ val(meta), [ , ] ] + forward_tractogram_transform = out_forward_tractogram_transform // channel: [ val(meta), [ , ] ] + backward_tractogram_transform = out_backward_tractogram_transform // channel: [ val(meta), [ , ] ] // Segmentations segmentation = out_segmentation // channel: [ val(meta), segmentation ] - ref_segmentation = out_ref_segmentation // channel: [ val(meta), ref-segmentation ] + reference_segmentation = out_ref_segmentation // channel: [ val(meta), ref-segmentation ] mqc = ch_mqc // channel: [ *mqc.*, ... ] versions = ch_versions // channel: [ versions.yml ] diff --git a/subworkflows/nf-neuro/registration/meta.yml b/subworkflows/nf-neuro/registration/meta.yml index 8de10b50..ac52882e 100644 --- a/subworkflows/nf-neuro/registration/meta.yml +++ b/subworkflows/nf-neuro/registration/meta.yml @@ -4,8 +4,11 @@ description: | It requires as input at least a moving (ch_image) and a reference (ch_ref) image to properly perform registration. - Output transformations curated for use with the REGISTRATION_ANTSAPPLYTRANSFORMS subworkflows - are available under the names image_transform and tractogram_transform, and their inverses. + Output transformations curated for images for use with the REGISTRATION_ANTSAPPLYTRANSFORMS module + are available under the names `forward_image_transform` and `backward_image_transform`. The same lists + are also available for tractograms (`forward_tractogram_transform` and `backward_tractogram_transform`). + However, to use the REGISTRATION_TRACTOGRAM module, you have to use the `backward_affine` and `backward_warp` + channels provided by this subworkflow. Registration suites: - EasyReg (ML): params.run_easyreg = true @@ -96,64 +99,68 @@ output: Channel containing images warped in fixed space. Structure: [ val(meta), path(image) ] pattern: "*.{nii,nii.gz}" - - ref_warped: + - reference_warped: type: file description: | ONLY PROVIDED BY REGISTRATION_EASYREG. Channel containing the reference image warped in moving space. Structure: [ val(meta), path(image) ] pattern: "*.{nii,nii.gz}" optional: true - - affine: + - forward_affine: type: file description: | - Channel containing the affine forward transformation matrix file. - Structure: [ val(meta), path(affine) ] + Channel containing the affine transformation matrix to fixed space. + Structure: [ val(meta), path(forward_affine) ] pattern: "*__forward*.{lta,mat}" optional: true - - warp: + - forward_warp: type: file description: | - Channel containing the forward deformation field file. - Structure: [ val(meta), path(warp) ] + Channel containing the deformation field to fixed space. + Structure: [ val(meta), path(forward_warp) ] pattern: "*__forward*.{nii,nii.gz}" optional: true - - inverse_warp: + - backward_warp: type: file description: | - Channel containing the inverse deformation field file. - Structure: [ val(meta), path(inverse_warp) ] + Channel containing the deformation field to moving space. + Structure: [ val(meta), path(backward_warp) ] pattern: "*__backward*.{nii,nii.gz}" optional: true - - inverse_affine: + - backward_affine: type: file description: | - Channel containing the inverse affine transformation matrix file. - Structure: [ val(meta), path(inverse_affine) ] + Channel containing the affine transformation matrix to moving space. + Structure: [ val(meta), path(backward_affine) ] pattern: "*__backward*.{lta,mat}" optional: true - - image_transform: + - forward_image_transform: type: list description: | - Tuple, Transformation files to warp images in the correct order - for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ warp, affine ] ]. + Channel containing the transformation tuples to warp images to fixed space, + in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS. + Structure: [ val(meta), [ path(forward_warp), path(forward_affine) ] ]. pattern: "*__forward*.{nii,nii.gz,mat,lta}" - - inverse_image_transform: + - backward_image_transform: type: list description: | - Tuple, Transformation files to warp images in the correct order for - REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ inverse_affine, inverse_warp ] ]. + Channel containing the transformation tuples to warp images to moving space, + in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS. + Structure: [ val(meta), [ path(backward_affine), path(backward_warp) ] ]. pattern: "*__backward*.{nii,nii.gz,mat,lta}" - - tractogram_transform: + - forward_tractogram_transform: type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ inverse_affine, inverse_warp ] ]. + Channel containing the transformation tuples to warp tractograms to fixed space, + in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM. + Structure: [ val(meta), [ path(backward_warp), path(backward_affine) ] ]. pattern: "*__backward*.{nii,nii.gz,mat,lta}" - - inverse_tractogram_transform: + - backward_tractogram_transform: type: list description: | - Tuple, Transformation files to warp tractograms in the correct order - for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ warp, affine ] ]. + Channel containing the transformation tuples to warp tractograms to moving space, + in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM. + Structure: [ val(meta), [ path(forward_warp), path(forward_affine) ] ]. pattern: "*__forward*.{nii,nii.gz,mat,lta}" - segmentation: type: file @@ -163,12 +170,12 @@ output: Structure: [ val(meta), path(segmentation) ] pattern: "*.{nii,nii.gz}" optional: true - - ref_segmentation: + - reference_segmentation: type: file description: | ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) segmentation + parcellation in fixed space (reference in Easyreg naming convention). - Structure: [ val(meta), path(ref_segmentation) ] + Structure: [ val(meta), path(reference_segmentation) ] pattern: "*.{nii,nii.gz}" optional: true - mqc: diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 08b4cc35..07f770aa 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -171,49 +171,49 @@ "registration - ANTs - SyNQuick": { "content": [ { - "affine": [ + "backward_affine": [ [ { "id": "test" }, - "test__forward1_affine.mat" + "test__backward0_affine.mat" ] ], - "image_transform": [ + "backward_image_transform": [ [ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" + "test__backward0_affine.mat", + "test__backward1_warp.nii.gz" ] ], - "image_warped": [ + "backward_tractogram_transform": [ [ { "id": "test" }, - "test__t1_warped.nii.gz" + "test__forward0_warp.nii.gz", + "test__forward1_affine.mat" ] ], - "inverse_affine": [ + "backward_warp": [ [ { "id": "test" }, - "test__backward0_affine.mat" + "test__backward1_warp.nii.gz" ] ], - "inverse_image_transform": [ + "forward_affine": [ [ { "id": "test" }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" + "test__forward1_affine.mat" ] ], - "inverse_tractogram_transform": [ + "forward_image_transform": [ [ { "id": "test" @@ -222,41 +222,41 @@ "test__forward1_affine.mat" ] ], - "inverse_warp": [ + "forward_tractogram_transform": [ [ { "id": "test" }, + "test__backward0_affine.mat", "test__backward1_warp.nii.gz" ] ], - "mqc": [ + "forward_warp": [ [ { "id": "test" }, - "test__registration_ants_mqc.gif" + "test__forward0_warp.nii.gz" ] ], - "tractogram_transform": [ + "image_warped": [ [ { "id": "test" }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" + "test__t1_warped.nii.gz" ] ], - "versions": [ - "versions.yml:md5,5f3f8c831b55885ffcc7bd976939dbad" - ], - "warp": [ + "mqc": [ [ { "id": "test" }, - "test__forward0_warp.nii.gz" + "test__registration_ants_mqc.gif" ] + ], + "versions": [ + "versions.yml:md5,5f3f8c831b55885ffcc7bd976939dbad" ] } ], @@ -264,7 +264,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.7" }, - "timestamp": "2025-10-08T15:13:44.415238887" + "timestamp": "2025-10-14T22:14:12.754132943" }, "registration - ANTs - Anat to DWI": { "content": [ diff --git a/subworkflows/nf-neuro/tractoflow/main.nf b/subworkflows/nf-neuro/tractoflow/main.nf index b19e3ca8..89575439 100644 --- a/subworkflows/nf-neuro/tractoflow/main.nf +++ b/subworkflows/nf-neuro/tractoflow/main.nf @@ -111,7 +111,7 @@ workflow TRACTOFLOW { TRANSFORM_WMPARC( ch_wmparc .join(PREPROC_DWI.out.b0) - .join(T1_REGISTRATION.out.image_transform) + .join(T1_REGISTRATION.out.forward_image_transform) ) ch_versions = ch_versions.mix(TRANSFORM_WMPARC.out.versions.first()) @@ -121,7 +121,7 @@ workflow TRACTOFLOW { TRANSFORM_APARC_ASEG( ch_aparc_aseg .join(PREPROC_DWI.out.b0) - .join(T1_REGISTRATION.out.image_transform) + .join(T1_REGISTRATION.out.forward_image_transform) ) ch_versions = ch_versions.mix(TRANSFORM_APARC_ASEG.out.versions.first()) @@ -130,7 +130,7 @@ workflow TRACTOFLOW { TRANSFORM_LESION_MASK( ch_lesion_mask .join(PREPROC_DWI.out.b0) - .join(T1_REGISTRATION.out.image_transform) + .join(T1_REGISTRATION.out.forward_image_transform) ) ch_versions = ch_versions.mix(TRANSFORM_LESION_MASK.out.versions.first()) @@ -270,8 +270,8 @@ workflow TRACTOFLOW { wmparc = TRANSFORM_WMPARC.out.warped_image // REGISTRATION - anatomical_to_diffusion = T1_REGISTRATION.out.image_transform - diffusion_to_anatomical = T1_REGISTRATION.out.inverse_image_transform + anatomical_to_diffusion = T1_REGISTRATION.out.forward_image_transform + diffusion_to_anatomical = T1_REGISTRATION.out.backward_image_transform // IN ANATOMICAL SPACE t1_native = PREPROC_T1.out.t1_final From 554a00e802f80e790923356757a22380e678cacd Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 15 Oct 2025 17:48:28 +0000 Subject: [PATCH 26/37] update devcontainer to scilus 2.2.0 --- poetry.lock | 156 ++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6a321926..4d0c5986 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1017,85 +1017,85 @@ files = [ [[package]] name = "numpy" -version = "2.3.4" +version = "2.3.3" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.11" files = [ - {file = "numpy-2.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e78aecd2800b32e8347ce49316d3eaf04aed849cd5b38e0af39f829a4e59f5eb"}, - {file = "numpy-2.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7fd09cc5d65bda1e79432859c40978010622112e9194e581e3415a3eccc7f43f"}, - {file = "numpy-2.3.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1b219560ae2c1de48ead517d085bc2d05b9433f8e49d0955c82e8cd37bd7bf36"}, - {file = "numpy-2.3.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:bafa7d87d4c99752d07815ed7a2c0964f8ab311eb8168f41b910bd01d15b6032"}, - {file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36dc13af226aeab72b7abad501d370d606326a0029b9f435eacb3b8c94b8a8b7"}, - {file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7b2f9a18b5ff9824a6af80de4f37f4ec3c2aab05ef08f51c77a093f5b89adda"}, - {file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9984bd645a8db6ca15d850ff996856d8762c51a2239225288f08f9050ca240a0"}, - {file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:64c5825affc76942973a70acf438a8ab618dbd692b84cd5ec40a0a0509edc09a"}, - {file = "numpy-2.3.4-cp311-cp311-win32.whl", hash = "sha256:ed759bf7a70342f7817d88376eb7142fab9fef8320d6019ef87fae05a99874e1"}, - {file = "numpy-2.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:faba246fb30ea2a526c2e9645f61612341de1a83fb1e0c5edf4ddda5a9c10996"}, - {file = "numpy-2.3.4-cp311-cp311-win_arm64.whl", hash = "sha256:4c01835e718bcebe80394fd0ac66c07cbb90147ebbdad3dcecd3f25de2ae7e2c"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef1b5a3e808bc40827b5fa2c8196151a4c5abe110e1726949d7abddfe5c7ae11"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c2f91f496a87235c6aaf6d3f3d89b17dba64996abadccb289f48456cff931ca9"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f77e5b3d3da652b474cc80a14084927a5e86a5eccf54ca8ca5cbd697bf7f2667"}, - {file = "numpy-2.3.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ab1c5f5ee40d6e01cbe96de5863e39b215a4d24e7d007cad56c7184fdf4aeef"}, - {file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77b84453f3adcb994ddbd0d1c5d11db2d6bda1a2b7fd5ac5bd4649d6f5dc682e"}, - {file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4121c5beb58a7f9e6dfdee612cb24f4df5cd4db6e8261d7f4d7450a997a65d6a"}, - {file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65611ecbb00ac9846efe04db15cbe6186f562f6bb7e5e05f077e53a599225d16"}, - {file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dabc42f9c6577bcc13001b8810d300fe814b4cfbe8a92c873f269484594f9786"}, - {file = "numpy-2.3.4-cp312-cp312-win32.whl", hash = "sha256:a49d797192a8d950ca59ee2d0337a4d804f713bb5c3c50e8db26d49666e351dc"}, - {file = "numpy-2.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:985f1e46358f06c2a09921e8921e2c98168ed4ae12ccd6e5e87a4f1857923f32"}, - {file = "numpy-2.3.4-cp312-cp312-win_arm64.whl", hash = "sha256:4635239814149e06e2cb9db3dd584b2fa64316c96f10656983b8026a82e6e4db"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c090d4860032b857d94144d1a9976b8e36709e40386db289aaf6672de2a81966"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a13fc473b6db0be619e45f11f9e81260f7302f8d180c49a22b6e6120022596b3"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:3634093d0b428e6c32c3a69b78e554f0cd20ee420dcad5a9f3b2a63762ce4197"}, - {file = "numpy-2.3.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:043885b4f7e6e232d7df4f51ffdef8c36320ee9d5f227b380ea636722c7ed12e"}, - {file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ee6a571d1e4f0ea6d5f22d6e5fbd6ed1dc2b18542848e1e7301bd190500c9d7"}, - {file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc8a63918b04b8571789688b2780ab2b4a33ab44bfe8ccea36d3eba51228c953"}, - {file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40cc556d5abbc54aabe2b1ae287042d7bdb80c08edede19f0c0afb36ae586f37"}, - {file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ecb63014bb7f4ce653f8be7f1df8cbc6093a5a2811211770f6606cc92b5a78fd"}, - {file = "numpy-2.3.4-cp313-cp313-win32.whl", hash = "sha256:e8370eb6925bb8c1c4264fec52b0384b44f675f191df91cbe0140ec9f0955646"}, - {file = "numpy-2.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:56209416e81a7893036eea03abcb91c130643eb14233b2515c90dcac963fe99d"}, - {file = "numpy-2.3.4-cp313-cp313-win_arm64.whl", hash = "sha256:a700a4031bc0fd6936e78a752eefb79092cecad2599ea9c8039c548bc097f9bc"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:86966db35c4040fdca64f0816a1c1dd8dbd027d90fca5a57e00e1ca4cd41b879"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:838f045478638b26c375ee96ea89464d38428c69170360b23a1a50fa4baa3562"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d7315ed1dab0286adca467377c8381cd748f3dc92235f22a7dfc42745644a96a"}, - {file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:84f01a4d18b2cc4ade1814a08e5f3c907b079c847051d720fad15ce37aa930b6"}, - {file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:817e719a868f0dacde4abdfc5c1910b301877970195db9ab6a5e2c4bd5b121f7"}, - {file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85e071da78d92a214212cacea81c6da557cab307f2c34b5f85b628e94803f9c0"}, - {file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2ec646892819370cf3558f518797f16597b4e4669894a2ba712caccc9da53f1f"}, - {file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:035796aaaddfe2f9664b9a9372f089cfc88bd795a67bd1bfe15e6e770934cf64"}, - {file = "numpy-2.3.4-cp313-cp313t-win32.whl", hash = "sha256:fea80f4f4cf83b54c3a051f2f727870ee51e22f0248d3114b8e755d160b38cfb"}, - {file = "numpy-2.3.4-cp313-cp313t-win_amd64.whl", hash = "sha256:15eea9f306b98e0be91eb344a94c0e630689ef302e10c2ce5f7e11905c704f9c"}, - {file = "numpy-2.3.4-cp313-cp313t-win_arm64.whl", hash = "sha256:b6c231c9c2fadbae4011ca5e7e83e12dc4a5072f1a1d85a0a7b3ed754d145a40"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:81c3e6d8c97295a7360d367f9f8553973651b76907988bb6066376bc2252f24e"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7c26b0b2bf58009ed1f38a641f3db4be8d960a417ca96d14e5b06df1506d41ff"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:62b2198c438058a20b6704351b35a1d7db881812d8512d67a69c9de1f18ca05f"}, - {file = "numpy-2.3.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:9d729d60f8d53a7361707f4b68a9663c968882dd4f09e0d58c044c8bf5faee7b"}, - {file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd0c630cf256b0a7fd9d0a11c9413b42fef5101219ce6ed5a09624f5a65392c7"}, - {file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5e081bc082825f8b139f9e9fe42942cb4054524598aaeb177ff476cc76d09d2"}, - {file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15fb27364ed84114438fff8aaf998c9e19adbeba08c0b75409f8c452a8692c52"}, - {file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:85d9fb2d8cd998c84d13a79a09cc0c1091648e848e4e6249b0ccd7f6b487fa26"}, - {file = "numpy-2.3.4-cp314-cp314-win32.whl", hash = "sha256:e73d63fd04e3a9d6bc187f5455d81abfad05660b212c8804bf3b407e984cd2bc"}, - {file = "numpy-2.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:3da3491cee49cf16157e70f607c03a217ea6647b1cea4819c4f48e53d49139b9"}, - {file = "numpy-2.3.4-cp314-cp314-win_arm64.whl", hash = "sha256:6d9cd732068e8288dbe2717177320723ccec4fb064123f0caf9bbd90ab5be868"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:22758999b256b595cf0b1d102b133bb61866ba5ceecf15f759623b64c020c9ec"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9cb177bc55b010b19798dc5497d540dea67fd13a8d9e882b2dae71de0cf09eb3"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0f2bcc76f1e05e5ab58893407c63d90b2029908fa41f9f1cc51eecce936c3365"}, - {file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dc20bde86802df2ed8397a08d793da0ad7a5fd4ea3ac85d757bf5dd4ad7c252"}, - {file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e199c087e2aa71c8f9ce1cb7a8e10677dc12457e7cc1be4798632da37c3e86e"}, - {file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85597b2d25ddf655495e2363fe044b0ae999b75bc4d630dc0d886484b03a5eb0"}, - {file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04a69abe45b49c5955923cf2c407843d1c85013b424ae8a560bba16c92fe44a0"}, - {file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e1708fac43ef8b419c975926ce1eaf793b0c13b7356cfab6ab0dc34c0a02ac0f"}, - {file = "numpy-2.3.4-cp314-cp314t-win32.whl", hash = "sha256:863e3b5f4d9915aaf1b8ec79ae560ad21f0b8d5e3adc31e73126491bb86dee1d"}, - {file = "numpy-2.3.4-cp314-cp314t-win_amd64.whl", hash = "sha256:962064de37b9aef801d33bc579690f8bfe6c5e70e29b61783f60bcba838a14d6"}, - {file = "numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6e274603039f924c0fe5cb73438fa9246699c78a6df1bd3decef9ae592ae1c05"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d149aee5c72176d9ddbc6803aef9c0f6d2ceeea7626574fc68518da5476fa346"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:6d34ed9db9e6395bb6cd33286035f73a59b058169733a9db9f85e650b88df37e"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:fdebe771ca06bb8d6abce84e51dca9f7921fe6ad34a0c914541b063e9a68928b"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e92defe6c08211eb77902253b14fe5b480ebc5112bc741fd5e9cd0608f847"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13b9062e4f5c7ee5c7e5be96f29ba71bc5a37fed3d1d77c37390ae00724d296d"}, - {file = "numpy-2.3.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:81b3a59793523e552c4a96109dde028aa4448ae06ccac5a76ff6532a85558a7f"}, - {file = "numpy-2.3.4.tar.gz", hash = "sha256:a7d018bfedb375a8d979ac758b120ba846a7fe764911a64465fd87b8729f4a6a"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ffc4f5caba7dfcbe944ed674b7eef683c7e94874046454bb79ed7ee0236f59d"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7e946c7170858a0295f79a60214424caac2ffdb0063d4d79cb681f9aa0aa569"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:cd4260f64bc794c3390a63bf0728220dd1a68170c169088a1e0dfa2fde1be12f"}, + {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f0ddb4b96a87b6728df9362135e764eac3cfa674499943ebc44ce96c478ab125"}, + {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:afd07d377f478344ec6ca2b8d4ca08ae8bd44706763d1efb56397de606393f48"}, + {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc92a5dedcc53857249ca51ef29f5e5f2f8c513e22cfb90faeb20343b8c6f7a6"}, + {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7af05ed4dc19f308e1d9fc759f36f21921eb7bbfc82843eeec6b2a2863a0aefa"}, + {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:433bf137e338677cebdd5beac0199ac84712ad9d630b74eceeb759eaa45ddf30"}, + {file = "numpy-2.3.3-cp311-cp311-win32.whl", hash = "sha256:eb63d443d7b4ffd1e873f8155260d7f58e7e4b095961b01c91062935c2491e57"}, + {file = "numpy-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:ec9d249840f6a565f58d8f913bccac2444235025bbb13e9a4681783572ee3caa"}, + {file = "numpy-2.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:74c2a948d02f88c11a3c075d9733f1ae67d97c6bdb97f2bb542f980458b257e7"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe"}, + {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b"}, + {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8"}, + {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20"}, + {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea"}, + {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7"}, + {file = "numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf"}, + {file = "numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb"}, + {file = "numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6"}, + {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7"}, + {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c"}, + {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93"}, + {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae"}, + {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86"}, + {file = "numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8"}, + {file = "numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf"}, + {file = "numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b"}, + {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19"}, + {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30"}, + {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e"}, + {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3"}, + {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea"}, + {file = "numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd"}, + {file = "numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d"}, + {file = "numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7"}, + {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a"}, + {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe"}, + {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421"}, + {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021"}, + {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf"}, + {file = "numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0"}, + {file = "numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8"}, + {file = "numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d"}, + {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a"}, + {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54"}, + {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e"}, + {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097"}, + {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970"}, + {file = "numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5"}, + {file = "numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f"}, + {file = "numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1e02c7159791cd481e1e6d5ddd766b62a4d5acf8df4d4d1afe35ee9c5c33a41e"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:dca2d0fc80b3893ae72197b39f69d55a3cd8b17ea1b50aa4c62de82419936150"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:99683cbe0658f8271b333a1b1b4bb3173750ad59c0c61f5bbdc5b318918fffe3"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d9d537a39cc9de668e5cd0e25affb17aec17b577c6b3ae8a3d866b479fbe88d0"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8596ba2f8af5f93b01d97563832686d20206d303024777f6dfc2e7c7c3f1850e"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1ec5615b05369925bd1125f27df33f3b6c8bc10d788d5999ecd8769a1fa04db"}, + {file = "numpy-2.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2e267c7da5bf7309670523896df97f93f6e469fb931161f483cd6882b3b1a5dc"}, + {file = "numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029"}, ] [[package]] @@ -1543,13 +1543,13 @@ files = [ [[package]] name = "pydantic" -version = "2.12.3" +version = "2.12.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" files = [ - {file = "pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf"}, - {file = "pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74"}, + {file = "pydantic-2.12.2-py3-none-any.whl", hash = "sha256:25ff718ee909acd82f1ff9b1a4acfd781bb23ab3739adaa7144f19a6a4e231ae"}, + {file = "pydantic-2.12.2.tar.gz", hash = "sha256:7b8fa15b831a4bbde9d5b84028641ac3080a4ca2cbd4a621a661687e741624fd"}, ] [package.dependencies] From c2c7e3cfc1027b5c5cad5564740e897e70af8717 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 15 Oct 2025 18:54:03 +0000 Subject: [PATCH 27/37] add entrypoint to ensure pipx dependencies loading --- .devcontainer/devops/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/devops/Dockerfile b/.devcontainer/devops/Dockerfile index 1ac4a3ec..31a62f14 100755 --- a/.devcontainer/devops/Dockerfile +++ b/.devcontainer/devops/Dockerfile @@ -67,3 +67,5 @@ RUN pipx ensurepath && \ # Export history for saving between container sessions RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/home/$USERNAME/commandhistory/.bash_history" \ && echo "$SNIPPET" >> "/home/$USERNAME/.bashrc" + +ENTRYPOINT ["/bin/sh", "-lc", "pipx ensurepath && exec \"$@\""] From 1d1631ac90c6cc21e6cc7d0c658ba4f761115e76 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 15 Oct 2025 18:59:16 +0000 Subject: [PATCH 28/37] resnap registration subworkflow --- .../nf-neuro/registration/anattodwi/main.nf | 5 +- .../nf-neuro/registration/anattodwi/meta.yml | 7 +- modules/nf-neuro/registration/ants/main.nf | 5 +- .../registration/antsapplytransforms/main.nf | 2 +- .../registration/tests/main.nf.test.snap | 131 ++++++++++++------ 5 files changed, 97 insertions(+), 53 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index 3daa2440..aa2be510 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -60,9 +60,8 @@ process REGISTRATION_ANATTODWI { mv forward1Warp.nii.gz ${prefix}__forward0_warp.nii.gz mv forward1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz - antsApplyTransforms -d 3 -i $moving_anat -r $fixed_reference \ - -o Linear[${prefix}__backward0_affine.mat] \ - -t [${prefix}__forward1_affine.mat,1] + antsApplyTransforms -d 3 -t [${prefix}__forward1_affine.mat,1] \ + -o Linear[${prefix}__backward0_affine.mat] ### ** QC ** ### if $run_qc; then diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index 9ff1c342..a6cf1d93 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -1,6 +1,11 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json name: registration_anattodwi -description: Anatomical image registration on a diffusion image. +description: | + Registration computing transformations moving images from anatomical space into diffusion space. The `moving_anat` image + represents the anatomical space, moving to diffusion space, onto its `fixed_reference` and its `metric` representations. + + Configuration, direction and order of the registration follows the [tractoflow](https://doi.org/10.1016/j.neuroimage.2020.116889) + publication. keywords: - nifti - registration diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index 57a7a37c..9c456944 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -67,9 +67,8 @@ process REGISTRATION_ANTS { mv output1Warp.nii.gz ${prefix}__forward0_warp.nii.gz fi - antsApplyTransforms -d 3 -i $fixed_image -r $moving_image \ - -o Linear[${prefix}__backward0_affine.mat] \ - -t [${prefix}__forward1_affine.mat,1] + antsApplyTransforms -d 3 -t [${prefix}__forward1_affine.mat,1] \ + -o Linear[${prefix}__backward0_affine.mat] ### ** QC ** ### if $run_qc; then diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index 0083ee33..49ba1737 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -24,7 +24,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { def dimensionality = "-d ${task.ext.dimensionality ?: 3}" def image_type = "-e ${task.ext.image_type ?: 0}" def interpolation = "-n ${task.ext.interpolation ?: "Linear"}" - def default_val = "-f ${task.ext.default_val ?: 3}" + def default_val = "-f ${task.ext.default_val ?: 0}" def run_qc = task.ext.run_qc as Boolean || false """ diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 07f770aa..00149319 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -2,7 +2,7 @@ "registration - Synthmorph": { "content": [ { - "affine": [ + "backward_affine": [ [ { "id": "test" @@ -10,24 +10,25 @@ "test__out_affine.txt" ] ], - "image_transform": [ + "backward_image_transform": [ [ { "id": "test" }, - "test__out_warp.nii.gz", - "test__out_affine.txt" + "test__out_affine.txt", + "test__out_warp.nii.gz" ] ], - "image_warped": [ + "backward_tractogram_transform": [ [ { "id": "test" }, - "test__warped.nii.gz" + "test__out_warp.nii.gz", + "test__out_affine.txt" ] ], - "inverse_affine": [ + "forward_affine": [ [ { "id": "test" @@ -35,31 +36,30 @@ "test__out_affine.txt" ] ], - "inverse_image_transform": [ + "forward_image_transform": [ [ { "id": "test" }, - "test__out_affine.txt", - "test__out_warp.nii.gz" + "test__out_warp.nii.gz", + "test__out_affine.txt" ] ], - "inverse_tractogram_transform": [ + "forward_tractogram_transform": [ [ { "id": "test" }, - "test__out_warp.nii.gz", - "test__out_affine.txt" + "test__out_affine.txt", + "test__out_warp.nii.gz" ] ], - "tractogram_transform": [ + "image_warped": [ [ { "id": "test" }, - "test__out_affine.txt", - "test__out_warp.nii.gz" + "test__warped.nii.gz" ] ], "versions": [ @@ -70,30 +70,30 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-08T15:14:48.304234548" + "timestamp": "2025-10-15T18:56:29.572768378" }, "registration - easyreg": { "content": [ { - "image_transform": [ + "backward_image_transform": [ [ { "id": "test" }, - "test_forward0_warp.nii.gz" + "test_backward0_warp.nii.gz" ] ], - "image_warped": [ + "backward_tractogram_transform": [ [ { "id": "test" }, - "test_warped.nii.gz" + "test_forward0_warp.nii.gz" ] ], - "inverse_image_transform": [ + "backward_warp": [ [ { "id": "test" @@ -101,7 +101,7 @@ "test_backward0_warp.nii.gz" ] ], - "inverse_tractogram_transform": [ + "forward_image_transform": [ [ { "id": "test" @@ -109,7 +109,7 @@ "test_forward0_warp.nii.gz" ] ], - "inverse_warp": [ + "forward_tractogram_transform": [ [ { "id": "test" @@ -117,56 +117,56 @@ "test_backward0_warp.nii.gz" ] ], - "ref_segmentation": [ + "forward_warp": [ [ { "id": "test" }, - "test_warped_reference_segmentation.nii.gz" + "test_forward0_warp.nii.gz" ] ], - "ref_warped": [ + "image_warped": [ [ { "id": "test" }, - "test_warped_reference.nii.gz" + "test_warped.nii.gz" ] ], - "segmentation": [ + "reference_segmentation": [ [ { "id": "test" }, - "test_warped_segmentation.nii.gz" + "test_warped_reference_segmentation.nii.gz" ] ], - "tractogram_transform": [ + "reference_warped": [ [ { "id": "test" }, - "test_backward0_warp.nii.gz" + "test_warped_reference.nii.gz" ] ], - "versions": [ - "versions.yml:md5,3f38c911476c605480c02e484fcf6e9f" - ], - "warp": [ + "segmentation": [ [ { "id": "test" }, - "test_forward0_warp.nii.gz" + "test_warped_segmentation.nii.gz" ] + ], + "versions": [ + "versions.yml:md5,3f38c911476c605480c02e484fcf6e9f" ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.8" }, - "timestamp": "2025-07-30T02:06:11.777613914" + "timestamp": "2025-10-15T18:55:55.830874285" }, "registration - ANTs - SyNQuick": { "content": [ @@ -392,7 +392,7 @@ "test__backward0_affine.mat" ] ], - "inverse_image_transform": [ + "backward_image_transform": [ [ { "id": "test" @@ -401,7 +401,7 @@ "test__backward1_warp.nii.gz" ] ], - "inverse_tractogram_transform": [ + "backward_tractogram_transform": [ [ { "id": "test" @@ -410,7 +410,7 @@ "test__forward1_affine.mat" ] ], - "inverse_warp": [ + "backward_warp": [ [ { "id": "test" @@ -418,7 +418,24 @@ "test__backward1_warp.nii.gz" ] ], - "tractogram_transform": [ + "forward_affine": [ + [ + { + "id": "test" + }, + "test__forward1_affine.mat" + ] + ], + "forward_image_transform": [ + [ + { + "id": "test" + }, + "test__forward0_warp.nii.gz", + "test__forward1_affine.mat" + ] + ], + "forward_tractogram_transform": [ [ { "id": "test" @@ -427,6 +444,30 @@ "test__backward1_warp.nii.gz" ] ], + "forward_warp": [ + [ + { + "id": "test" + }, + "test__forward0_warp.nii.gz" + ] + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test__T1w_warped.nii.gz" + ] + ], + "mqc": [ + [ + { + "id": "test" + }, + "test__registration_anattodwi_mqc.gif" + ] + ], "versions": [ "versions.yml:md5,42f2dcb95a2cf29b157dbaebf162d2dd" ] @@ -434,7 +475,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-17T17:41:57.285829729" } From ae8a860e590d6f1ff69ea15a6c975c4293ebfd7e Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 15 Oct 2025 21:05:16 +0000 Subject: [PATCH 29/37] remove workdir collection --- .github/workflows/test_component.yml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/.github/workflows/test_component.yml b/.github/workflows/test_component.yml index 02f591ab..05c640b6 100644 --- a/.github/workflows/test_component.yml +++ b/.github/workflows/test_component.yml @@ -197,27 +197,6 @@ jobs: retention-days: 1 compression-level: 9 - - name: Collect test working directories - if: failure() - run: | - mkdir -p tests_workdir - for t in ${{ env.NXF_WORKDIR }}/.nf-test/tests/**/work/**/.command.log - do - tag=$(sed -n '3p' $(dirname $t)/.command.run | cut -d' ' -f3 | tr -d "'") - cp -R $(dirname $t) tests_workdir/$tag - done - - - name: Upload test working directories - if: failure() - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 - with: - name: tests-workdir-${{ steps.test-run-identifier.outputs.uid }} - path: tests_workdir/ - overwrite: true - retention-days: 1 - compression-level: 9 - include-hidden-files: true - - name: Clean up if: always() run: | From 70ec5c35fbe3d0615c87497b02f7f289b24e4819 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 16 Oct 2025 17:01:07 +0000 Subject: [PATCH 30/37] naming conventions and resnap --- modules/nf-neuro/bundle/recognize/main.nf | 6 +- .../bundle/recognize/tests/main.nf.test.snap | 40 ++++----- .../nf-neuro/registration/anattodwi/main.nf | 48 +++++------ .../nf-neuro/registration/anattodwi/meta.yml | 32 ++++---- .../anattodwi/tests/main.nf.test.snap | 38 ++++----- modules/nf-neuro/registration/ants/main.nf | 42 +++++----- modules/nf-neuro/registration/ants/meta.yml | 32 ++++---- .../registration/antsapplytransforms/main.nf | 14 ++-- .../registration/antsapplytransforms/meta.yml | 6 +- .../antsapplytransforms/tests/main.nf.test | 6 +- .../tests/main.nf.test.snap | 22 ++--- .../antsapplytransforms/tests/nextflow.config | 4 +- modules/nf-neuro/registration/convert/main.nf | 4 +- .../convert/tests/main.nf.test.snap | 30 +++---- modules/nf-neuro/registration/easyreg/main.nf | 4 +- .../easyreg/tests/main.nf.test.snap | 8 +- .../registration/synthregistration/main.nf | 40 ++++----- .../registration/synthregistration/meta.yml | 36 ++++---- .../synthregistration/tests/main.nf.test.snap | 22 ++--- .../nf-neuro/registration/tractogram/main.nf | 8 +- .../nf-neuro/registration/tractogram/meta.yml | 4 +- .../tractogram/tests/main.nf.test.snap | 48 +++++------ .../bundle_seg/tests/main.nf.test.snap | 12 +-- .../tests/main.nf.test.snap | 46 +++++------ .../registration/tests/main.nf.test.snap | 82 +++++++++---------- .../tractoflow/tests/main.nf.test.snap | 12 +-- 26 files changed, 321 insertions(+), 325 deletions(-) diff --git a/modules/nf-neuro/bundle/recognize/main.nf b/modules/nf-neuro/bundle/recognize/main.nf index 9b0de3b1..41506e06 100644 --- a/modules/nf-neuro/bundle/recognize/main.nf +++ b/modules/nf-neuro/bundle/recognize/main.nf @@ -34,8 +34,8 @@ process BUNDLE_RECOGNIZE { -v DEBUG $minimal_vote_ratio $seed $rbx_processes for bundle_file in recobundles/*.trk; do - bname=\$(basename \${bundle_file} .trk) - out_cleaned=${prefix}__\${bname}_cleaned.trk + bname=\$(basename \${bundle_file} .trk | sed 's/${prefix}_\\+//') + out_cleaned=${prefix}_\${bname}_cleaned.trk scil_bundle_reject_outliers \${bundle_file} "\${out_cleaned}" ${outlier_alpha} done @@ -52,7 +52,7 @@ process BUNDLE_RECOGNIZE { scil_bundle_reject_outliers -h # dummy output for single bundle - touch ${prefix}__AF_L_cleaned.trk + touch ${prefix}_AF_L_cleaned.trk cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap b/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap index 757f5948..ebae8040 100644 --- a/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap +++ b/modules/nf-neuro/bundle/recognize/tests/main.nf.test.snap @@ -8,11 +8,11 @@ "id": "test", "single_end": false }, - "test__bundle_1_cleaned.trk", - "test__bundle_2_cleaned.trk", - "test__bundle_3_cleaned.trk", - "test__bundle_4_cleaned.trk", - "test__bundle_5_cleaned.trk" + "test_bundle_1_cleaned.trk", + "test_bundle_2_cleaned.trk", + "test_bundle_3_cleaned.trk", + "test_bundle_4_cleaned.trk", + "test_bundle_5_cleaned.trk" ] ], "versions": [ @@ -21,10 +21,10 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.0", + "nextflow": "25.04.8" }, - "timestamp": "2025-07-28T16:02:34.519025132" + "timestamp": "2025-10-16T16:21:06.178446125" }, "bundle - recognize - stub-run": { "content": [ @@ -35,7 +35,7 @@ "id": "test", "single_end": false }, - "test__AF_L_cleaned.trk" + "test_AF_L_cleaned.trk" ] ], "versions": [ @@ -45,9 +45,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-09-17T17:40:14.633526447" + "timestamp": "2025-10-16T16:21:40.42494296" }, "bundle - recognize - base": { "content": [ @@ -58,11 +58,11 @@ "id": "test", "single_end": false }, - "test__bundle_1_cleaned.trk", - "test__bundle_2_cleaned.trk", - "test__bundle_3_cleaned.trk", - "test__bundle_4_cleaned.trk", - "test__bundle_5_cleaned.trk" + "test_bundle_1_cleaned.trk", + "test_bundle_2_cleaned.trk", + "test_bundle_3_cleaned.trk", + "test_bundle_4_cleaned.trk", + "test_bundle_5_cleaned.trk" ] ], "versions": [ @@ -71,9 +71,9 @@ } ], "meta": { - "nf-test": "0.9.2", - "nextflow": "25.04.7" + "nf-test": "0.9.0", + "nextflow": "25.04.8" }, - "timestamp": "2025-07-28T16:01:58.07707728" + "timestamp": "2025-10-16T16:20:14.719020953" } -} +} \ No newline at end of file diff --git a/modules/nf-neuro/registration/anattodwi/main.nf b/modules/nf-neuro/registration/anattodwi/main.nf index aa2be510..1520de47 100644 --- a/modules/nf-neuro/registration/anattodwi/main.nf +++ b/modules/nf-neuro/registration/anattodwi/main.nf @@ -9,14 +9,14 @@ process REGISTRATION_ANATTODWI { output: tuple val(meta), path("*_warped.nii.gz") , emit: anat_warped - tuple val(meta), path("*__forward1_affine.mat") , emit: forward_affine - tuple val(meta), path("*__forward0_warp.nii.gz") , emit: forward_warp - tuple val(meta), path("*__backward1_warp.nii.gz") , emit: backward_warp - tuple val(meta), path("*__backward0_affine.mat") , emit: backward_affine - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: forward_image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: backward_image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: forward_tractogram_transform - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: backward_tractogram_transform + tuple val(meta), path("*_forward1_affine.mat") , emit: forward_affine + tuple val(meta), path("*_forward0_warp.nii.gz") , emit: forward_warp + tuple val(meta), path("*_backward1_warp.nii.gz") , emit: backward_warp + tuple val(meta), path("*_backward0_affine.mat") , emit: backward_affine + tuple val(meta), path("*_forward*.{nii.gz,mat}", arity: '1..2') , emit: forward_image_transform + tuple val(meta), path("*_backward*.{nii.gz,mat}", arity: '1..2') , emit: backward_image_transform + tuple val(meta), path("*_backward*.{nii.gz,mat}", arity: '1..2') , emit: forward_tractogram_transform + tuple val(meta), path("*_forward*.{nii.gz,mat}", arity: '1..2') , emit: backward_tractogram_transform tuple val(meta), path("*_registration_anattodwi_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions @@ -53,20 +53,20 @@ process REGISTRATION_ANATTODWI { --smoothing-sigmas 3x2x1 moving_id=\$(basename $moving_anat .nii.gz) - moving_id=\${moving_id#${meta.id}__*} + moving_id=\${moving_id#${meta.id}_*} - mv warped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz - mv forward0GenericAffine.mat ${prefix}__forward1_affine.mat - mv forward1Warp.nii.gz ${prefix}__forward0_warp.nii.gz - mv forward1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz + mv warped.nii.gz ${prefix}_\${moving_id}_warped.nii.gz + mv forward0GenericAffine.mat ${prefix}_forward1_affine.mat + mv forward1Warp.nii.gz ${prefix}_forward0_warp.nii.gz + mv forward1InverseWarp.nii.gz ${prefix}_backward1_warp.nii.gz - antsApplyTransforms -d 3 -t [${prefix}__forward1_affine.mat,1] \ - -o Linear[${prefix}__backward0_affine.mat] + antsApplyTransforms -d 3 -t [${prefix}_forward1_affine.mat,1] \ + -o Linear[${prefix}_backward0_affine.mat] ### ** QC ** ### if $run_qc; then # Extract dimensions. - dim=\$(mrinfo ${prefix}__\${moving_id}_warped.nii.gz -size) + dim=\$(mrinfo ${prefix}_\${moving_id}_warped.nii.gz -size) read sagittal_dim coronal_dim axial_dim <<< "\${dim}" # Get middle slices. @@ -79,7 +79,7 @@ process REGISTRATION_ANATTODWI { # Get fixed ID, moving ID already computed fixed_id=\$(basename $fixed_reference .nii.gz) - fixed_id=\${fixed_id#${meta.id}__*} + fixed_id=\${fixed_id#${meta.id}_*} # Iterate over images. for image in \${moving_id}_warped \${fixed_id}; do @@ -136,16 +136,16 @@ process REGISTRATION_ANATTODWI { convert -help . moving_id=\$(basename $moving_anat .nii.gz) - moving_id=\${moving_id#${meta.id}__*} + moving_id=\${moving_id#${meta.id}_*} - touch ${prefix}__\${moving_id}_warped.nii.gz - touch ${prefix}__forward1_affine.mat - touch ${prefix}__forward0_warp.nii.gz - touch ${prefix}__backward1_warp.nii.gz - touch ${prefix}__backward0_affine.mat + touch ${prefix}_\${moving_id}_warped.nii.gz + touch ${prefix}_forward1_affine.mat + touch ${prefix}_forward0_warp.nii.gz + touch ${prefix}_backward1_warp.nii.gz + touch ${prefix}_backward0_affine.mat if $run_qc; then - touch ${prefix}__registration_anattodwi_mqc.gif + touch ${prefix}_registration_anattodwi_mqc.gif fi cat <<-END_VERSIONS > versions.yml diff --git a/modules/nf-neuro/registration/anattodwi/meta.yml b/modules/nf-neuro/registration/anattodwi/meta.yml index a6cf1d93..0f269050 100644 --- a/modules/nf-neuro/registration/anattodwi/meta.yml +++ b/modules/nf-neuro/registration/anattodwi/meta.yml @@ -81,10 +81,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward1_affine.mat": + - "*_forward1_affine.mat": type: file description: Affine transformation matrix to fixed space. - pattern: "*__forward1_affine.mat" + pattern: "*_forward1_affine.mat" ontologies: [] forward_warp: - - meta: @@ -92,10 +92,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward0_warp.nii.gz": + - "*_forward0_warp.nii.gz": type: file description: Deformation field to fixed space. - pattern: "*__forward0_warp.nii.gz" + pattern: "*_forward0_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format backward_warp: @@ -104,10 +104,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward1_warp.nii.gz": + - "*_backward1_warp.nii.gz": type: file description: Deformation field to moving space. - pattern: "*__backward1_warp.nii.gz" + pattern: "*_backward1_warp.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format backward_affine: @@ -116,10 +116,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward0_affine.mat": + - "*_backward0_affine.mat": type: file description: Affine transformation matrix to moving space. - pattern: "*__backward0_affine.mat" + pattern: "*_backward0_affine.mat" ontologies: [] forward_image_transform: - - meta: @@ -127,12 +127,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii.gz,mat}": + - "*_forward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp images in fixed space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_warp, forward_affine ] ]. - pattern: "*__forward*.{nii.gz,mat}" + pattern: "*_forward*.{nii.gz,mat}" ontologies: [] backward_image_transform: - - meta: @@ -140,12 +140,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii.gz,mat}": + - "*_backward*.{nii.gz,mat}": type: list description: | Tuple, transformation files to warp images in moving space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. - pattern: "*__backward*.{nii.gz,mat}" + pattern: "*_backward*.{nii.gz,mat}" ontologies: [] forward_tractogram_transform: - - meta: @@ -153,12 +153,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii.gz,mat}": + - "*_backward*.{nii.gz,mat}": type: list description: | Tuple, transformation files to warp tractograms into fixed space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. - pattern: "*__backward*.{nii.gz,mat}" + pattern: "*_backward*.{nii.gz,mat}" ontologies: [] backward_tractogram_transform: - - meta: @@ -166,12 +166,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii.gz,mat}": + - "*_forward*.{nii.gz,mat}": type: list description: | Tuple, transformation files to warp tractograms into moving space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_affine, forward_warp ] ]. - pattern: "*__forward*.{nii.gz,mat}" + pattern: "*_forward*.{nii.gz,mat}" ontologies: [] mqc: - - meta: diff --git a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap index d90cfd42..f9705138 100644 --- a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap @@ -8,7 +8,7 @@ "id": "test", "single_end": false }, - "test__T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" + "test_T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" ] ], "1": [ @@ -17,7 +17,7 @@ "id": "test", "single_end": false }, - "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + "test_forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" ] ], "10": [ @@ -29,7 +29,7 @@ "id": "test", "single_end": false }, - "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" + "test_forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" ] ], "3": [ @@ -38,7 +38,7 @@ "id": "test", "single_end": false }, - "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + "test_backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" ] ], "4": [ @@ -47,7 +47,7 @@ "id": "test", "single_end": false }, - "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" + "test_backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" ] ], "5": [ @@ -59,7 +59,7 @@ "id": "test", "single_end": false }, - "test__T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" + "test_T1w_warped.nii.gz:md5,39c30c6251cba224989bc74a31540121" ] ], "backward_affine": [ @@ -68,7 +68,7 @@ "id": "test", "single_end": false }, - "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" + "test_backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b" ] ], "backward_image_transform": [ @@ -78,8 +78,8 @@ "single_end": false }, [ - "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", - "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + "test_backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test_backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" ] ] ], @@ -90,8 +90,8 @@ "single_end": false }, [ - "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", - "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + "test_forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", + "test_forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" ] ] ], @@ -101,7 +101,7 @@ "id": "test", "single_end": false }, - "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + "test_backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" ] ], "forward_affine": [ @@ -110,7 +110,7 @@ "id": "test", "single_end": false }, - "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + "test_forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" ] ], "forward_image_transform": [ @@ -120,8 +120,8 @@ "single_end": false }, [ - "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", - "test__forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + "test_forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", + "test_forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" ] ] ], @@ -132,8 +132,8 @@ "single_end": false }, [ - "test__backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", - "test__backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + "test_backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test_backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" ] ] ], @@ -143,7 +143,7 @@ "id": "test", "single_end": false }, - "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" + "test_forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" ] ], "mqc": [ @@ -171,7 +171,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-09T20:08:38.758050028" }, diff --git a/modules/nf-neuro/registration/ants/main.nf b/modules/nf-neuro/registration/ants/main.nf index 9c456944..6ca63ac1 100644 --- a/modules/nf-neuro/registration/ants/main.nf +++ b/modules/nf-neuro/registration/ants/main.nf @@ -10,14 +10,14 @@ process REGISTRATION_ANTS { output: tuple val(meta), path("*_warped.nii.gz") , emit: image_warped - tuple val(meta), path("*__forward1_affine.mat") , emit: forward_affine, optional: true - tuple val(meta), path("*__forward0_warp.nii.gz") , emit: forward_warp, optional: true - tuple val(meta), path("*__backward1_warp.nii.gz") , emit: backward_warp, optional: true - tuple val(meta), path("*__backward0_affine.mat") , emit: backward_affine, optional: true - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: forward_image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: backward_image_transform - tuple val(meta), path("*__backward*.{nii.gz,mat}", arity: '1..2') , emit: forward_tractogram_transform - tuple val(meta), path("*__forward*.{nii.gz,mat}", arity: '1..2') , emit: backward_tractogram_transform + tuple val(meta), path("*_forward1_affine.mat") , emit: forward_affine, optional: true + tuple val(meta), path("*_forward0_warp.nii.gz") , emit: forward_warp, optional: true + tuple val(meta), path("*_backward1_warp.nii.gz") , emit: backward_warp, optional: true + tuple val(meta), path("*_backward0_affine.mat") , emit: backward_affine, optional: true + tuple val(meta), path("*_forward*.{nii.gz,mat}", arity: '1..2') , emit: forward_image_transform + tuple val(meta), path("*_backward*.{nii.gz,mat}", arity: '1..2') , emit: backward_image_transform + tuple val(meta), path("*_backward*.{nii.gz,mat}", arity: '1..2') , emit: forward_tractogram_transform + tuple val(meta), path("*_forward*.{nii.gz,mat}", arity: '1..2') , emit: backward_tractogram_transform tuple val(meta), path("*_registration_ants_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions @@ -54,21 +54,21 @@ process REGISTRATION_ANTS { $ants $dimension -f $fixed_image -m $moving_image -o output -t $transform $args $seed moving_id=\$(basename $moving_image .nii.gz) - moving_id=\${moving_id#${meta.id}__*} + moving_id=\${moving_id#${meta.id}_*} - mv outputWarped.nii.gz ${prefix}__\${moving_id}_warped.nii.gz + mv outputWarped.nii.gz ${prefix}_\${moving_id}_warped.nii.gz if [ $transform != "bo" ] && [ $transform != "so" ]; then - mv output0GenericAffine.mat ${prefix}__forward1_affine.mat + mv output0GenericAffine.mat ${prefix}_forward1_affine.mat fi if [ $transform != "t" ] && [ $transform != "r" ] && [ $transform != "a" ]; then - mv output1InverseWarp.nii.gz ${prefix}__backward1_warp.nii.gz - mv output1Warp.nii.gz ${prefix}__forward0_warp.nii.gz + mv output1InverseWarp.nii.gz ${prefix}_backward1_warp.nii.gz + mv output1Warp.nii.gz ${prefix}_forward0_warp.nii.gz fi - antsApplyTransforms -d 3 -t [${prefix}__forward1_affine.mat,1] \ - -o Linear[${prefix}__backward0_affine.mat] + antsApplyTransforms -d 3 -t [${prefix}_forward1_affine.mat,1] \ + -o Linear[${prefix}_backward0_affine.mat] ### ** QC ** ### if $run_qc; then @@ -83,7 +83,7 @@ process REGISTRATION_ANTS { # Get fixed ID, moving ID already computed fixed_id=\$(basename $fixed_image .nii.gz) - fixed_id=\${fixed_id#${meta.id}__*} + fixed_id=\${fixed_id#${meta.id}_*} # Set viz params. viz_params="--display_slice_number --display_lr --size 256 256" @@ -153,11 +153,11 @@ process REGISTRATION_ANTS { convert -help . scil_viz_volume_screenshot -h - touch ${prefix}__t1_warped.nii.gz - touch ${prefix}__forward1_affine.mat - touch ${prefix}__forward0_warp.nii.gz - touch ${prefix}__backward1_warp.nii.gz - touch ${prefix}__backward0_affine.mat + touch ${prefix}_t1_warped.nii.gz + touch ${prefix}_forward1_affine.mat + touch ${prefix}_forward0_warp.nii.gz + touch ${prefix}_backward1_warp.nii.gz + touch ${prefix}_backward0_affine.mat if $run_qc; then touch ${prefix}_${suffix_qc}_registration_ants_mqc.gif diff --git a/modules/nf-neuro/registration/ants/meta.yml b/modules/nf-neuro/registration/ants/meta.yml index e5b677f5..9ff787d9 100644 --- a/modules/nf-neuro/registration/ants/meta.yml +++ b/modules/nf-neuro/registration/ants/meta.yml @@ -167,10 +167,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward1_affine.mat": + - "*_forward1_affine.mat": type: file description: Affine transformation from moving to fixed - pattern: "*__forward1_affine.mat" + pattern: "*_forward1_affine.mat" optional: true ontologies: [] forward_warp: @@ -179,10 +179,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward0_warp.nii.gz": + - "*_forward0_warp.nii.gz": type: file description: Nifti volume containing warp field from moving to fixed - pattern: "*__forward0_warp.nii.gz" + pattern: "*_forward0_warp.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_3989 # GZIP format @@ -192,10 +192,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward1_warp.nii.gz": + - "*_backward1_warp.nii.gz": type: file description: Nifti volume containing warp field from fixed to moving - pattern: "*__backward1_warp.nii.gz" + pattern: "*_backward1_warp.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_3989 # GZIP format @@ -205,10 +205,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward0_affine.mat": + - "*_backward0_affine.mat": type: file description: Affine transformation from fixed to moving - pattern: "*__backward0_affine.mat" + pattern: "*_backward0_affine.mat" optional: true ontologies: [] forward_image_transform: @@ -217,12 +217,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii.gz,mat}": + - "*_forward*.{nii.gz,mat}": type: list description: | Tuple, Transformation files to warp images in fixed space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_warp, forward_affine ] ]. - pattern: "*__forward*.{nii.gz,mat}" + pattern: "*_forward*.{nii.gz,mat}" ontologies: [] backward_image_transform: - - meta: @@ -230,12 +230,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii.gz,mat}": + - "*_backward*.{nii.gz,mat}": type: list description: | Tuple, transformation files to warp images in moving space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. - pattern: "*__backward*.{nii.gz,mat}" + pattern: "*_backward*.{nii.gz,mat}" ontologies: [] forward_tractogram_transform: - - meta: @@ -243,12 +243,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward*.{nii.gz,mat}": + - "*_backward*.{nii.gz,mat}": type: list description: | Tuple, transformation files to warp tractograms into fixed space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. - pattern: "*__backward*.{nii.gz,mat}" + pattern: "*_backward*.{nii.gz,mat}" ontologies: [] backward_tractogram_transform: - - meta: @@ -256,12 +256,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward*.{nii.gz,mat}": + - "*_forward*.{nii.gz,mat}": type: list description: | Tuple, transformation files to warp tractograms into moving space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_affine, forward_warp ] ]. - pattern: "*__forward*.{nii.gz,mat}" + pattern: "*_forward*.{nii.gz,mat}" ontologies: [] mqc: - - meta: diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index 49ba1737..bee63757 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -8,7 +8,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { tuple val(meta), path(images, arity: '1..*'), path(reference), path(transformations, arity: '1..*') output: - tuple val(meta), path("*__warped.nii.gz") , emit: warped_image + tuple val(meta), path("*_warped.nii.gz") , emit: warped_image tuple val(meta), path("*_registration_antsapplytransforms_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions @@ -17,8 +17,8 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { script: def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = "${task.ext.first_suffix ?: ""}__warped" - def suffix_qc = task.ext.suffix_qc ?: "" + def suffix = "_${[task.ext.first_suffix, "warped"].findAll().join("_")}" + def suffix_qc = task.ext.suffix_qc ? "_${task.ext.suffix_qc}" : "" def output_dtype = "-u ${task.ext.output_dtype ?: "default"}" def dimensionality = "-d ${task.ext.dimensionality ?: 3}" @@ -39,7 +39,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { antsApplyTransforms $dimensionality \ -i \$image \ -r $reference \ - -o ${prefix}__\${bname}${suffix}.nii.gz \ + -o ${prefix}_\${bname}${suffix}.nii.gz \ $interpolation \ ${transformations.collect{ t -> "-t $t" }.join(" ")} \ $output_dtype \ @@ -49,7 +49,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { ### ** QC ** ### if $run_qc; then ln -sf $reference reference.nii.gz - extract_dim=\$(mrinfo ${prefix}__\${bname}${suffix}.nii.gz -size) + extract_dim=\$(mrinfo ${prefix}_\${bname}${suffix}.nii.gz -size) read sagittal_dim coronal_dim axial_dim <<< "\${extract_dim}" # Get the middle slice @@ -105,7 +105,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { stub: def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = "${task.ext.first_suffix ?: ""}__warped" + def suffix = "${task.ext.first_suffix ?: ""}_warped" def suffix_qc = task.ext.suffix_qc ?: "" def run_qc = task.ext.run_qc as Boolean || false @@ -118,7 +118,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { ext=\${image#*.} bname=\$(basename \${image} .\${ext}) - touch ${prefix}__\${bname}${suffix}.nii.gz + touch ${prefix}_\${bname}${suffix}.nii.gz if $run_qc; then touch ${prefix}_\${bname}${suffix_qc}_registration_antsapplytransforms_mqc.gif diff --git a/modules/nf-neuro/registration/antsapplytransforms/meta.yml b/modules/nf-neuro/registration/antsapplytransforms/meta.yml index 7c09ce1c..e4790161 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/meta.yml +++ b/modules/nf-neuro/registration/antsapplytransforms/meta.yml @@ -123,10 +123,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__warped.nii.gz": + - "*_warped.nii.gz": type: file - description: Warped image. - pattern: "*__warped.{nii.nii.gz}" + description: Warped image(s). + pattern: "*_warped.{nii.nii.gz}" ontologies: [] mqc: - - meta: diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test index 23256d77..569e2dfb 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test @@ -53,7 +53,7 @@ nextflow_process { """ input[0] = LOAD_DATA.out.test_data_directory .map{ test_data_directory -> [ - [ id:'test', single_end:false ], // meta map + [ id:'test' ], // meta map file("\${test_data_directory}/b0.nii.gz"), file("\${test_data_directory}/mni_masked_2x2x2.nii.gz"), [ @@ -78,7 +78,7 @@ nextflow_process { """ input[0] = LOAD_DATA.out.test_data_directory .map{ test_data_directory -> [ - [ id:'test', single_end:false ], // meta map + [ id:'test' ], // meta map [ file("\${test_data_directory}/b0.nii.gz"), file("\${test_data_directory}/b0.nii.gz").copyTo( @@ -110,7 +110,7 @@ nextflow_process { """ input[0] = LOAD_DATA.out.test_data_directory .map{ test_data_directory -> [ - [ id:'test', single_end:false ], // meta map + [ id:'test' ], // meta map file("\${test_data_directory}/b0.nii.gz"), file("\${test_data_directory}/mni_masked_2x2x2.nii.gz"), [ diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap index 6c8f99aa..5f0b6df2 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap @@ -5,19 +5,17 @@ "0": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "test__b0b0__warped.nii.gz:md5,54f953b796f87bc0765d401ab32e6450" + "test_b0_to_template_warped.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" ] ], "1": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "test_b0b0_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2" + "test_b0_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2" ] ], "2": [ @@ -26,10 +24,9 @@ "mqc": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "test_b0b0_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2" + "test_b0_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2" ] ], "versions": [ @@ -38,17 +35,16 @@ "warped_image": [ [ { - "id": "test", - "single_end": false + "id": "test" }, - "test__b0b0__warped.nii.gz:md5,54f953b796f87bc0765d401ab32e6450" + "test_b0_to_template_warped.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" ] ] } ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-09T20:09:53.057544388" }, diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config b/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config index 1aac9a64..e7494ca3 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config @@ -1,12 +1,12 @@ process { withName: "REGISTRATION_ANTSAPPLYTRANSFORMS" { ext.interpolation = "Linear" - ext.first_suffix = "b0" + ext.first_suffix = "to_template" ext.dimensionality = 3 ext.image_type = 0 ext.output_dtype = "float" ext.default_val = 0 ext.run_qc = true - ext.suffix_qc = "b0_to_template" + ext.suffix_qc = "to_template" } } diff --git a/modules/nf-neuro/registration/convert/main.nf b/modules/nf-neuro/registration/convert/main.nf index 29e96d16..b57054e2 100644 --- a/modules/nf-neuro/registration/convert/main.nf +++ b/modules/nf-neuro/registration/convert/main.nf @@ -33,7 +33,7 @@ process REGISTRATION_CONVERT { } def out_extension = transform_types[transform_type][output_type] - def output_name = "${prefix}__out_${transform_type}.${out_extension}" + def output_name = "${prefix}_out_${transform_type}.${out_extension}" def command = transform_type == "affine" ? "lta_convert" : "mri_warp_convert" if ( transform_type == "affine" ) { @@ -92,7 +92,7 @@ process REGISTRATION_CONVERT { } def out_extension = transform_types[transform_type][output_type] - def output_name = "${prefix}__out_${transform_type}.${out_extension}" + def output_name = "${prefix}_out_${transform_type}.${out_extension}" """ set +e function handle_code () { diff --git a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap index 4d4b8c8e..ad5184d8 100644 --- a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap @@ -13,16 +13,16 @@ }, "registration - convert - affine - to lta (needs source)": { "content": [ - "test__out_affine.lta", + "test_out_affine.lta", [ "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-02T20:44:27.597924954" + "timestamp": "2025-10-16T15:03:48.505663297" }, "registration - convert - affine - lta to fsl": { "content": [ @@ -32,7 +32,7 @@ { "id": "test" }, - "test__out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" + "test_out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" ] ], "1": [ @@ -43,7 +43,7 @@ { "id": "test" }, - "test__out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" + "test_out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" ] ], "versions": [ @@ -53,9 +53,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-02T20:44:05.956240243" + "timestamp": "2025-10-16T15:03:28.499786859" }, "registration - convert - mixed - to itk": { "content": [ @@ -65,7 +65,7 @@ { "id": "test1" }, - "test1__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + "test1_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" ] ], "1": [ @@ -76,7 +76,7 @@ { "id": "test1" }, - "test1__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + "test1_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" ] ], "versions": [ @@ -86,9 +86,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-02T20:44:17.27523449" + "timestamp": "2025-10-16T15:03:38.467678996" }, "registration - convert - deformation - ras to itk (lps)": { "content": [ @@ -98,7 +98,7 @@ { "id": "test" }, - "test__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + "test_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" ] ], "1": [ @@ -109,7 +109,7 @@ { "id": "test" }, - "test__out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + "test_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" ] ], "versions": [ @@ -119,8 +119,8 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-02T20:43:52.34178625" + "timestamp": "2025-10-16T15:03:18.528152956" } } \ No newline at end of file diff --git a/modules/nf-neuro/registration/easyreg/main.nf b/modules/nf-neuro/registration/easyreg/main.nf index 4ab2bae9..1058b798 100644 --- a/modules/nf-neuro/registration/easyreg/main.nf +++ b/modules/nf-neuro/registration/easyreg/main.nf @@ -24,8 +24,8 @@ process REGISTRATION_EASYREG { script: def prefix = task.ext.prefix ?: "${meta.id}" def affine_only = task.ext.affine_only ? "--affine_only " : "" - fixed_segmentation = "--ref_seg ${fixed_segmentation ?: "${prefix}__warped_segmentation.nii.gz" }" - moving_segmentation = "--flo_seg ${moving_segmentation ?: "${prefix}__warped_reference_segmentation.nii.gz" }" + fixed_segmentation = "--ref_seg ${fixed_segmentation ?: "${prefix}_warped_segmentation.nii.gz" }" + moving_segmentation = "--flo_seg ${moving_segmentation ?: "${prefix}_warped_reference_segmentation.nii.gz" }" """ export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1 export OMP_NUM_THREADS=1 diff --git a/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap b/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap index a40373e5..d9c53e2f 100644 --- a/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/easyreg/tests/main.nf.test.snap @@ -1,8 +1,8 @@ { "registration - easyreg": { "content": [ - "test__warped_reference_segmentation.nii.gz", - "test__warped_segmentation.nii.gz", + "test_warped_reference_segmentation.nii.gz", + "test_warped_segmentation.nii.gz", "test_warped_reference.nii.gz:md5:header,c5e41f89848f91c53a9a7be44970d4b1,data,1501221fe23cd62bfdafb33367cadf4d", "test_warped.nii.gz:md5:header,ec5893cd9ea024e630c4444bd914c331,data,d75ae3fc935cd5cc70ea6797a4c70775", "test_forward0_warp.nii.gz:md5:header,0db0a80786ff39864cc17506ed1a0146,data,e4fa6c626729cbf236c34680e5c76df4", @@ -13,9 +13,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.8" }, - "timestamp": "2025-07-19T02:11:25.288399742" + "timestamp": "2025-10-16T15:11:21.026914183" }, "registration - easyreg - stub-run": { "content": [ diff --git a/modules/nf-neuro/registration/synthregistration/main.nf b/modules/nf-neuro/registration/synthregistration/main.nf index 1272b054..cb4530a0 100644 --- a/modules/nf-neuro/registration/synthregistration/main.nf +++ b/modules/nf-neuro/registration/synthregistration/main.nf @@ -11,16 +11,16 @@ process REGISTRATION_SYNTHREGISTRATION { tuple val(meta), path(fixed_image), path(moving_image) output: - tuple val(meta), path("*__warped.nii.gz") , emit: image_warped - tuple val(meta), path("*__forward{0,1,_standalone}_affine.lta") , emit: forward_affine, optional: true - tuple val(meta), path("*__forward0_deform.nii.gz") , emit: forward_warp, optional: true - tuple val(meta), path("*__backward1_deform.nii.gz") , emit: backward_warp, optional: true - tuple val(meta), path("*__backward{0,_standalone}_affine.lta") , emit: backward_affine, optional: true - tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: forward_image_transform - tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: backward_image_transform - tuple val(meta), path("*__backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: forward_tractogram_transform - tuple val(meta), path("*__forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: backward_tractogram_transform - path "versions.yml" , emit: versions + tuple val(meta), path("*_warped.nii.gz") , emit: image_warped + tuple val(meta), path("*_forward{0,1,_standalone}_affine.lta") , emit: forward_affine, optional: true + tuple val(meta), path("*_forward0_deform.nii.gz") , emit: forward_warp, optional: true + tuple val(meta), path("*_backward1_deform.nii.gz") , emit: backward_warp, optional: true + tuple val(meta), path("*_backward{0,_standalone}_affine.lta") , emit: backward_affine, optional: true + tuple val(meta), path("*_forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: forward_image_transform + tuple val(meta), path("*_backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: backward_image_transform + tuple val(meta), path("*_backward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: forward_tractogram_transform + tuple val(meta), path("*_forward[!_]*.{lta,nii.gz}", arity: '1..*') , emit: backward_tractogram_transform + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -92,8 +92,8 @@ process REGISTRATION_SYNTHREGISTRATION { fi mri_synthmorph register \$moving fixed.nii.gz -v -m \$model \$weight \$args \ - -t ${prefix}__forward\${j}_\$model.\${extension[\$model]} \ - -T ${prefix}__backward\${i}_\$model.\${extension[\$model]} \ + -t ${prefix}_forward\${j}_\$model.\${extension[\$model]} \ + -T ${prefix}_backward\${i}_\$model.\${extension[\$model]} \ -o warped.nii.gz -j $task.cpus $extent $use_gpu if [ \$initializer ]; then @@ -104,8 +104,8 @@ process REGISTRATION_SYNTHREGISTRATION { fi if [ \${extension[\$model]} = "lta" ]; then - initializer=${prefix}__forward\${j}_\$model.\${extension[\$model]} - init_assoc=${prefix}__backward\${i}_\$model.\${extension[\$model]} + initializer=${prefix}_forward\${j}_\$model.\${extension[\$model]} + init_assoc=${prefix}_backward\${i}_\$model.\${extension[\$model]} else moving=warped.nii.gz fi @@ -115,7 +115,7 @@ process REGISTRATION_SYNTHREGISTRATION { done - mv warped.nii.gz ${prefix}__warped.nii.gz + mv warped.nii.gz ${prefix}_warped.nii.gz cat <<-END_VERSIONS > versions.yml "${task.process}": @@ -129,11 +129,11 @@ process REGISTRATION_SYNTHREGISTRATION { """ mri_synthmorph -h - touch ${prefix}__warped.nii.gz - touch ${prefix}__forward1_affine.lta - touch ${prefix}__forward0_warp.nii.gz - touch ${prefix}__backward1_warp.nii.gz - touch ${prefix}__backward0_affine.lta + touch ${prefix}_warped.nii.gz + touch ${prefix}_forward1_affine.lta + touch ${prefix}_forward0_warp.nii.gz + touch ${prefix}_backward1_warp.nii.gz + touch ${prefix}_backward0_affine.lta cat <<-END_VERSIONS > versions.yml "${task.process}": diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthregistration/meta.yml index f162757f..d424a8dc 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthregistration/meta.yml @@ -93,10 +93,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__warped.nii.gz": + - "*_warped.nii.gz": type: file description: Warped image - pattern: "*__warped.nii.gz" + pattern: "*_warped.nii.gz" ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format forward_affine: @@ -105,10 +105,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward{0,1,_standalone}_affine.lta": + - "*_forward{0,1,_standalone}_affine.lta": type: file description: Affine transformation matrix to fixed space. - pattern: "*__forward{0,1,_standalone}_affine.lta" + pattern: "*_forward{0,1,_standalone}_affine.lta" optional: true ontologies: [] forward_warp: @@ -117,10 +117,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward0_deform.nii.gz": + - "*_forward0_deform.nii.gz": type: file description: Deformation field to fixed space. - pattern: "*__forward0_deform.nii.gz" + pattern: "*_forward0_deform.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format @@ -130,10 +130,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward1_deform.nii.gz": + - "*_backward1_deform.nii.gz": type: file description: Deformation field to moving space. - pattern: "*__backward1_deform.nii.gz" + pattern: "*_backward1_deform.nii.gz" optional: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format @@ -143,10 +143,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward{0,_standalone}_affine.lta": + - "*_backward{0,_standalone}_affine.lta": type: file description: Affine transformation matrix to moving space. - pattern: "*__backward{0,_standalone}_affine.lta" + pattern: "*_backward{0,_standalone}_affine.lta" optional: true ontologies: [] forward_image_transform: @@ -155,12 +155,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward[!_]*.{lta,nii.gz}": + - "*_forward[!_]*.{lta,nii.gz}": type: list description: | Tuple, transformation files to warp images to fixed space, in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ forward_warp, forward_affine ] ]. - pattern: "*__forward[!_]*.{lta,nii.gz}" + pattern: "*_forward[!_]*.{lta,nii.gz}" ontologies: [] backward_image_transform: - - meta: @@ -168,12 +168,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward[!_]*.{lta,nii.gz}": + - "*_backward[!_]*.{lta,nii.gz}": type: list description: | Tuple, transformation files to warp images to moving space, in the correct order for REGISTRATION_ANTSAPPLYTRANSFORMS : [ meta, [ backward_affine, backward_warp ] ]. - pattern: "*__backward[!_]*.{lta,nii.gz}" + pattern: "*_backward[!_]*.{lta,nii.gz}" ontologies: [] forward_tractogram_transform: - - meta: @@ -181,12 +181,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__backward[!_]*.{lta,nii.gz}": + - "*_backward[!_]*.{lta,nii.gz}": type: list description: | Tuple, transformation files to warp tractograms to fixed space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ backward_affine, backward_warp ] ]. - pattern: "*__backward[!_]*.{lta,nii.gz}" + pattern: "*_backward[!_]*.{lta,nii.gz}" ontologies: [] backward_tractogram_transform: - - meta: @@ -194,12 +194,12 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__forward[!_]*.{lta,nii.gz}": + - "*_forward[!_]*.{lta,nii.gz}": type: list description: | Tuple, transformation files to warp tractograms to moving space, in the correct order for REGISTRATION_TRANSFORMTRACTOGRAM : [ meta, [ forward_warp, forward_affine ] ]. - pattern: "*__forward[!_]*.{lta,nii.gz}" + pattern: "*_forward[!_]*.{lta,nii.gz}" ontologies: [] versions: - versions.yml: diff --git a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap index 1c229588..1c7affdc 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap @@ -8,7 +8,7 @@ "id": "test", "single_end": false }, - "test__backward_standalone_affine.lta" + "test_backward_standalone_affine.lta" ] ], "backward_image_transform": [ @@ -17,7 +17,7 @@ "id": "test", "single_end": false }, - "test__backward1_deform.nii.gz" + "test_backward1_deform.nii.gz" ] ], "backward_tractogram_transform": [ @@ -26,7 +26,7 @@ "id": "test", "single_end": false }, - "test__forward0_deform.nii.gz" + "test_forward0_deform.nii.gz" ] ], "backward_warp": [ @@ -35,7 +35,7 @@ "id": "test", "single_end": false }, - "test__backward1_deform.nii.gz" + "test_backward1_deform.nii.gz" ] ], "forward_affine": [ @@ -44,7 +44,7 @@ "id": "test", "single_end": false }, - "test__forward_standalone_affine.lta" + "test_forward_standalone_affine.lta" ] ], "forward_image_transform": [ @@ -53,7 +53,7 @@ "id": "test", "single_end": false }, - "test__forward0_deform.nii.gz" + "test_forward0_deform.nii.gz" ] ], "forward_tractogram_transform": [ @@ -62,7 +62,7 @@ "id": "test", "single_end": false }, - "test__backward1_deform.nii.gz" + "test_backward1_deform.nii.gz" ] ], "forward_warp": [ @@ -71,7 +71,7 @@ "id": "test", "single_end": false }, - "test__forward0_deform.nii.gz" + "test_forward0_deform.nii.gz" ] ], "image_warped": [ @@ -80,7 +80,7 @@ "id": "test", "single_end": false }, - "test__warped.nii.gz" + "test_warped.nii.gz" ] ], "versions": [ @@ -90,9 +90,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-14T21:29:05.976082158" + "timestamp": "2025-10-16T15:22:15.176985467" }, "registration - synthregistration - stub-run": { "content": [ diff --git a/modules/nf-neuro/registration/tractogram/main.nf b/modules/nf-neuro/registration/tractogram/main.nf index 34141237..ad80f9f8 100644 --- a/modules/nf-neuro/registration/tractogram/main.nf +++ b/modules/nf-neuro/registration/tractogram/main.nf @@ -8,8 +8,8 @@ process REGISTRATION_TRACTOGRAM { tuple val(meta), path(anat), path(affine), path(tractogram), path(reference), path(deformation) output: - tuple val(meta), path("*__*.{trk,tck}") , emit: tractogram - path "versions.yml" , emit: versions + tuple val(meta), path("*.{trk,tck}") , emit: tractogram + path "versions.yml" , emit: versions when: task.ext.when == null || task.ext.when @@ -41,7 +41,7 @@ process REGISTRATION_TRACTOGRAM { for tractogram in ${tractogram}; do ext=\${tractogram#*.} bname=\$(basename \${tractogram} .\${ext} | sed 's/${prefix}_\\+//') - name=${prefix}__\${bname}${suffix}.\${ext} + name=${prefix}_\${bname}${suffix}.\${ext} scil_tractogram_apply_transform \$tractogram $anat \$affine \$name \ $in_deformation \ @@ -81,7 +81,7 @@ process REGISTRATION_TRACTOGRAM { for tractogram in ${tractogram}; do ext=\${tractogram#*.} bname=\$(basename \${tractogram} .\${ext} | sed 's/${prefix}_\\+//') - name=${prefix}__\${bname}${suffix}.\${ext} + name=${prefix}_\${bname}${suffix}.\${ext} touch \$name done diff --git a/modules/nf-neuro/registration/tractogram/meta.yml b/modules/nf-neuro/registration/tractogram/meta.yml index 528df0fd..1c060f29 100644 --- a/modules/nf-neuro/registration/tractogram/meta.yml +++ b/modules/nf-neuro/registration/tractogram/meta.yml @@ -104,10 +104,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*__*.{trk,tck}": + - "*.{trk,tck}": type: file description: Warped tractogram(s). - pattern: "*__*.{trk,tck}" + pattern: "*.{trk,tck}" ontologies: [] versions: - versions.yml: diff --git a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap index 4a3c029e..849705c0 100644 --- a/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/tractogram/tests/main.nf.test.snap @@ -8,7 +8,7 @@ "id": "test", "single_end": false }, - "test__bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" + "test_bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" ] ], "1": [ @@ -20,7 +20,7 @@ "id": "test", "single_end": false }, - "test__bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" + "test_bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" ] ], "versions": [ @@ -30,9 +30,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-02T20:58:49.616623032" + "timestamp": "2025-10-16T15:24:45.131144667" }, "registration - tractogram_bundles": { "content": [ @@ -44,13 +44,13 @@ "single_end": false }, [ - "test__bundle_0.trk:md5,6e14cc02b66d12d5dde0a0701918385a", - "test__bundle_1.trk:md5,ef5a759144ab7e8d2f5abf30a463a152", - "test__bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9", - "test__bundle_3.trk:md5,8877161b9aebaa6b12a4d7a8f8410407", - "test__bundle_4.trk:md5,6c8658b946154896952ca89e88fcf29f", - "test__bundle_5.trk:md5,fa058f93d9bfe4bed2ff027e9acd5682", - "test__bundle_6.trk:md5,125e50561b4b0c5fd8ee23867c28bc51" + "test_bundle_0.trk:md5,6e14cc02b66d12d5dde0a0701918385a", + "test_bundle_1.trk:md5,ef5a759144ab7e8d2f5abf30a463a152", + "test_bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9", + "test_bundle_3.trk:md5,8877161b9aebaa6b12a4d7a8f8410407", + "test_bundle_4.trk:md5,6c8658b946154896952ca89e88fcf29f", + "test_bundle_5.trk:md5,fa058f93d9bfe4bed2ff027e9acd5682", + "test_bundle_6.trk:md5,125e50561b4b0c5fd8ee23867c28bc51" ] ] ], @@ -64,13 +64,13 @@ "single_end": false }, [ - "test__bundle_0.trk:md5,6e14cc02b66d12d5dde0a0701918385a", - "test__bundle_1.trk:md5,ef5a759144ab7e8d2f5abf30a463a152", - "test__bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9", - "test__bundle_3.trk:md5,8877161b9aebaa6b12a4d7a8f8410407", - "test__bundle_4.trk:md5,6c8658b946154896952ca89e88fcf29f", - "test__bundle_5.trk:md5,fa058f93d9bfe4bed2ff027e9acd5682", - "test__bundle_6.trk:md5,125e50561b4b0c5fd8ee23867c28bc51" + "test_bundle_0.trk:md5,6e14cc02b66d12d5dde0a0701918385a", + "test_bundle_1.trk:md5,ef5a759144ab7e8d2f5abf30a463a152", + "test_bundle_2.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9", + "test_bundle_3.trk:md5,8877161b9aebaa6b12a4d7a8f8410407", + "test_bundle_4.trk:md5,6c8658b946154896952ca89e88fcf29f", + "test_bundle_5.trk:md5,fa058f93d9bfe4bed2ff027e9acd5682", + "test_bundle_6.trk:md5,125e50561b4b0c5fd8ee23867c28bc51" ] ] ], @@ -81,9 +81,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-02T20:57:42.535433219" + "timestamp": "2025-10-16T15:23:46.56008019" }, "registration - tractogram - stub-run": { "content": [ @@ -106,7 +106,7 @@ "id": "test", "single_end": false }, - "test__bundle_2_mni.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" + "test_bundle_2_mni.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" ] ], "1": [ @@ -118,7 +118,7 @@ "id": "test", "single_end": false }, - "test__bundle_2_mni.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" + "test_bundle_2_mni.trk:md5,824bcbf796cbce3e1c93e39d1c98dcf9" ] ], "versions": [ @@ -128,8 +128,8 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-02T20:58:16.81646804" + "timestamp": "2025-10-16T15:24:16.677031753" } } \ No newline at end of file diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index d4dfc81f..29d31cde 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -37,7 +37,7 @@ { "id": "test" }, - "test__AF_L_cleaned.trk" + "test_AF_L_cleaned.trk" ] ], "versions": [ @@ -48,9 +48,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-08T14:45:55.930099672" + "timestamp": "2025-10-16T16:28:52.712317132" }, "rbx - download atlas - ants registration": { "content": [ @@ -60,7 +60,7 @@ { "id": "test" }, - "test__AF_L_cleaned.trk" + "test_AF_L_cleaned.trk" ] ], "versions": [ @@ -71,8 +71,8 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-08T14:42:39.410389277" + "timestamp": "2025-10-16T16:25:01.408812547" } } \ No newline at end of file diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap index 09c38865..75f90558 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap @@ -7,7 +7,7 @@ { "id": "test" }, - "test__warped.nii.gz" + "test_warped.nii.gz" ] ], "ch_registered_labels_files": [ @@ -15,7 +15,7 @@ { "id": "test" }, - "test__IFGWM_labels_map__warped.nii.gz" + "test_IFGWM_labels_map_warped.nii.gz" ] ], "ch_registered_nifti_files": [ @@ -23,7 +23,7 @@ { "id": "test" }, - "test__IFGWM__warped.nii.gz" + "test_IFGWM_warped.nii.gz" ] ], "ch_registered_trk_files": [ @@ -31,9 +31,9 @@ { "id": "test" }, - "test__IFGWM.trk", - "test__IFGWM_color.trk", - "test__IFGWM_uni.trk" + "test_IFGWM.trk", + "test_IFGWM_color.trk", + "test_IFGWM_uni.trk" ] ], "ch_t1w_tpl": [ @@ -69,7 +69,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-17T17:39:24.646305544" }, @@ -81,7 +81,7 @@ { "id": "test" }, - "test__t1_warped.nii.gz" + "test_t1_warped.nii.gz" ] ], "ch_registered_labels_files": [ @@ -89,7 +89,7 @@ { "id": "test" }, - "test__IFGWM_labels_map__warped.nii.gz" + "test_IFGWM_labels_map_warped.nii.gz" ] ], "ch_registered_nifti_files": [ @@ -97,7 +97,7 @@ { "id": "test" }, - "test__IFGWM__warped.nii.gz" + "test_IFGWM_warped.nii.gz" ] ], "ch_registered_trk_files": [ @@ -105,9 +105,9 @@ { "id": "test" }, - "test__IFGWM.trk", - "test__IFGWM_color.trk", - "test__IFGWM_uni.trk" + "test_IFGWM.trk", + "test_IFGWM_color.trk", + "test_IFGWM_uni.trk" ] ], "ch_t1w_tpl": [ @@ -149,9 +149,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-08T14:52:05.229017105" + "timestamp": "2025-10-16T15:53:24.130917882" }, "Template MNI152NLin2009cAsym - local templates": { "content": [ @@ -161,7 +161,7 @@ { "id": "test" }, - "test__t1_warped.nii.gz" + "test_t1_warped.nii.gz" ] ], "ch_registered_labels_files": [ @@ -169,7 +169,7 @@ { "id": "test" }, - "test__IFGWM_labels_map__warped.nii.gz" + "test_IFGWM_labels_map_warped.nii.gz" ] ], "ch_registered_nifti_files": [ @@ -177,7 +177,7 @@ { "id": "test" }, - "test__IFGWM__warped.nii.gz" + "test_IFGWM_warped.nii.gz" ] ], "ch_registered_trk_files": [ @@ -185,9 +185,9 @@ { "id": "test" }, - "test__IFGWM.trk", - "test__IFGWM_color.trk", - "test__IFGWM_uni.trk" + "test_IFGWM.trk", + "test_IFGWM_color.trk", + "test_IFGWM_uni.trk" ] ], "ch_t1w_tpl": [ @@ -229,8 +229,8 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-08T14:49:39.690526638" + "timestamp": "2025-10-16T15:51:15.187833232" } } \ No newline at end of file diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 00149319..c481285e 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -7,7 +7,7 @@ { "id": "test" }, - "test__out_affine.txt" + "test_out_affine.txt" ] ], "backward_image_transform": [ @@ -15,8 +15,8 @@ { "id": "test" }, - "test__out_affine.txt", - "test__out_warp.nii.gz" + "test_out_affine.txt", + "test_out_warp.nii.gz" ] ], "backward_tractogram_transform": [ @@ -24,8 +24,8 @@ { "id": "test" }, - "test__out_warp.nii.gz", - "test__out_affine.txt" + "test_out_warp.nii.gz", + "test_out_affine.txt" ] ], "forward_affine": [ @@ -33,7 +33,7 @@ { "id": "test" }, - "test__out_affine.txt" + "test_out_affine.txt" ] ], "forward_image_transform": [ @@ -41,8 +41,8 @@ { "id": "test" }, - "test__out_warp.nii.gz", - "test__out_affine.txt" + "test_out_warp.nii.gz", + "test_out_affine.txt" ] ], "forward_tractogram_transform": [ @@ -50,8 +50,8 @@ { "id": "test" }, - "test__out_affine.txt", - "test__out_warp.nii.gz" + "test_out_affine.txt", + "test_out_warp.nii.gz" ] ], "image_warped": [ @@ -59,7 +59,7 @@ { "id": "test" }, - "test__warped.nii.gz" + "test_warped.nii.gz" ] ], "versions": [ @@ -72,7 +72,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.8" }, - "timestamp": "2025-10-15T18:56:29.572768378" + "timestamp": "2025-10-16T15:28:24.402873254" }, "registration - easyreg": { "content": [ @@ -176,7 +176,7 @@ { "id": "test" }, - "test__backward0_affine.mat" + "test_backward0_affine.mat" ] ], "backward_image_transform": [ @@ -184,8 +184,8 @@ { "id": "test" }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" + "test_backward0_affine.mat", + "test_backward1_warp.nii.gz" ] ], "backward_tractogram_transform": [ @@ -193,8 +193,8 @@ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" + "test_forward0_warp.nii.gz", + "test_forward1_affine.mat" ] ], "backward_warp": [ @@ -202,7 +202,7 @@ { "id": "test" }, - "test__backward1_warp.nii.gz" + "test_backward1_warp.nii.gz" ] ], "forward_affine": [ @@ -210,7 +210,7 @@ { "id": "test" }, - "test__forward1_affine.mat" + "test_forward1_affine.mat" ] ], "forward_image_transform": [ @@ -218,8 +218,8 @@ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" + "test_forward0_warp.nii.gz", + "test_forward1_affine.mat" ] ], "forward_tractogram_transform": [ @@ -227,8 +227,8 @@ { "id": "test" }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" + "test_backward0_affine.mat", + "test_backward1_warp.nii.gz" ] ], "forward_warp": [ @@ -236,7 +236,7 @@ { "id": "test" }, - "test__forward0_warp.nii.gz" + "test_forward0_warp.nii.gz" ] ], "image_warped": [ @@ -244,7 +244,7 @@ { "id": "test" }, - "test__t1_warped.nii.gz" + "test_t1_warped.nii.gz" ] ], "mqc": [ @@ -262,9 +262,9 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, - "timestamp": "2025-10-14T22:14:12.754132943" + "timestamp": "2025-10-16T15:27:00.460253907" }, "registration - ANTs - Anat to DWI": { "content": [ @@ -389,7 +389,7 @@ { "id": "test" }, - "test__backward0_affine.mat" + "test_backward0_affine.mat" ] ], "backward_image_transform": [ @@ -397,8 +397,8 @@ { "id": "test" }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" + "test_backward0_affine.mat", + "test_backward1_warp.nii.gz" ] ], "backward_tractogram_transform": [ @@ -406,8 +406,8 @@ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" + "test_forward0_warp.nii.gz", + "test_forward1_affine.mat" ] ], "backward_warp": [ @@ -415,7 +415,7 @@ { "id": "test" }, - "test__backward1_warp.nii.gz" + "test_backward1_warp.nii.gz" ] ], "forward_affine": [ @@ -423,7 +423,7 @@ { "id": "test" }, - "test__forward1_affine.mat" + "test_forward1_affine.mat" ] ], "forward_image_transform": [ @@ -431,8 +431,8 @@ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" + "test_forward0_warp.nii.gz", + "test_forward1_affine.mat" ] ], "forward_tractogram_transform": [ @@ -440,8 +440,8 @@ { "id": "test" }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" + "test_backward0_affine.mat", + "test_backward1_warp.nii.gz" ] ], "forward_warp": [ @@ -449,7 +449,7 @@ { "id": "test" }, - "test__forward0_warp.nii.gz" + "test_forward0_warp.nii.gz" ] ], "image_warped": [ @@ -457,7 +457,7 @@ { "id": "test" }, - "test__T1w_warped.nii.gz" + "test_T1w_warped.nii.gz" ] ], "mqc": [ @@ -465,7 +465,7 @@ { "id": "test" }, - "test__registration_anattodwi_mqc.gif" + "test_registration_anattodwi_mqc.gif" ] ], "versions": [ diff --git a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap index 0153666e..cf88761e 100644 --- a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap @@ -31,8 +31,8 @@ { "id": "test" }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" + "test_forward0_warp.nii.gz", + "test_forward1_affine.mat" ] ], "csf_fodf": [ @@ -64,8 +64,8 @@ { "id": "test" }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" + "test_backward0_affine.mat", + "test_backward1_warp.nii.gz" ] ], "dti_ad": [ @@ -363,7 +363,7 @@ { "id": "test" }, - "test__test_b0_warped.nii.gz" + "test_b0_warped.nii.gz" ] ], "t1_native": [ @@ -422,7 +422,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-17T17:43:41.279576493" } From 064ea7588fca5d9ce55af2f267be7b400d75c163 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 16 Oct 2025 19:26:29 +0000 Subject: [PATCH 31/37] move synthregistration to synthmorph. Fix antsapplytransforms suffix --- .github/workflows/run_checks_suite.yml | 2 +- .../registration/antsapplytransforms/main.nf | 12 ++++++----- .../registration/antsapplytransforms/meta.yml | 12 +++++++---- .../tests/main.nf.test.snap | 6 +++--- .../antsapplytransforms/tests/nextflow.config | 2 +- .../registration/synthmorph/environment.yml | 3 +++ .../{synthregistration => synthmorph}/main.nf | 2 +- .../meta.yml | 2 +- .../tests/main.nf.test | 10 +++++----- .../tests/main.nf.test.snap | 6 +++--- .../tests/nextflow.config | 2 +- .../registration/synthmorph/tests/tags.yml | 2 ++ .../synthregistration/environment.yml | 3 --- .../synthregistration/tests/tags.yml | 2 -- .../nf-neuro/bundle_seg/tests/main.nf.test | 2 +- .../bundle_seg/tests/synthregistration.config | 2 +- .../tests/synthmorph.config | 2 +- subworkflows/nf-neuro/registration/main.nf | 20 +++++++++---------- subworkflows/nf-neuro/registration/meta.yml | 8 ++++---- .../nf-neuro/registration/tests/main.nf.test | 4 ++-- .../tests/synthregistration.config | 2 +- 21 files changed, 56 insertions(+), 50 deletions(-) create mode 100644 modules/nf-neuro/registration/synthmorph/environment.yml rename modules/nf-neuro/registration/{synthregistration => synthmorph}/main.nf (99%) rename modules/nf-neuro/registration/{synthregistration => synthmorph}/meta.yml (99%) rename modules/nf-neuro/registration/{synthregistration => synthmorph}/tests/main.nf.test (91%) rename modules/nf-neuro/registration/{synthregistration => synthmorph}/tests/main.nf.test.snap (97%) rename modules/nf-neuro/registration/{synthregistration => synthmorph}/tests/nextflow.config (84%) create mode 100644 modules/nf-neuro/registration/synthmorph/tests/tags.yml delete mode 100644 modules/nf-neuro/registration/synthregistration/environment.yml delete mode 100644 modules/nf-neuro/registration/synthregistration/tests/tags.yml diff --git a/.github/workflows/run_checks_suite.yml b/.github/workflows/run_checks_suite.yml index d1e396b3..8557d366 100644 --- a/.github/workflows/run_checks_suite.yml +++ b/.github/workflows/run_checks_suite.yml @@ -193,7 +193,7 @@ jobs: - runner: scilus-docker-large path: modules/nf-neuro/betcrop/synthbet - runner: scilus-docker-large - path: modules/nf-neuro/registration/synthregistration + path: modules/nf-neuro/registration/synthmorph exclude: - path: subworkflows/nf-neuro/load_test_data uses: ./.github/workflows/test_component.yml diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index bee63757..48851ff7 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -8,7 +8,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { tuple val(meta), path(images, arity: '1..*'), path(reference), path(transformations, arity: '1..*') output: - tuple val(meta), path("*_warped.nii.gz") , emit: warped_image + tuple val(meta), path("*.nii.gz") , emit: warped_image tuple val(meta), path("*_registration_antsapplytransforms_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions @@ -17,13 +17,13 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { script: def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = "_${[task.ext.first_suffix, "warped"].findAll().join("_")}" + def suffix = "_${task.ext.suffix ?: "warped"}" def suffix_qc = task.ext.suffix_qc ? "_${task.ext.suffix_qc}" : "" - def output_dtype = "-u ${task.ext.output_dtype ?: "default"}" def dimensionality = "-d ${task.ext.dimensionality ?: 3}" def image_type = "-e ${task.ext.image_type ?: 0}" def interpolation = "-n ${task.ext.interpolation ?: "Linear"}" + def output_dtype = "-u ${task.ext.output_dtype ?: "default"}" def default_val = "-f ${task.ext.default_val ?: 0}" def run_qc = task.ext.run_qc as Boolean || false @@ -82,6 +82,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { \${image}_mosaic.png \${image}_mosaic.png # Clean up. rm \${image}_coronal*.png \${image}_sagittal*.png \${image}_axial*.png + rm *\${image}_viz.nii.gz done # Create GIF. @@ -91,6 +92,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { # Clean up. rm *_mosaic.png + rm reference.nii.gz fi done @@ -105,8 +107,8 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { stub: def prefix = task.ext.prefix ?: "${meta.id}" - def suffix = "${task.ext.first_suffix ?: ""}_warped" - def suffix_qc = task.ext.suffix_qc ?: "" + def suffix = "_${task.ext.suffix ?: "warped"}" + def suffix_qc = task.ext.suffix_qc ? "_${task.ext.suffix_qc}" : "" def run_qc = task.ext.run_qc as Boolean || false """ diff --git a/modules/nf-neuro/registration/antsapplytransforms/meta.yml b/modules/nf-neuro/registration/antsapplytransforms/meta.yml index e4790161..89e6303a 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/meta.yml +++ b/modules/nf-neuro/registration/antsapplytransforms/meta.yml @@ -15,14 +15,14 @@ args: type: string description: | Prefix to add to the output file name. - e.g. `warped_` will result in `warped_image.nii.gz`. + e.g. `warped` will result in `warped_image.nii.gz`. default: "${meta.id}" - suffix: type: string description: | - Suffix to add to the output file name. - e.g. `_warped` will result in `image_warped.nii.gz`. - default: "__warped" + Obligatory suffix to add to the output file name to prevent overwrite + of input files. e.g. : the suffix `warped` will result in the name `image_warped.nii.gz`. + default: "warped" - suffix_qc: type: string description: | @@ -33,6 +33,7 @@ args: description: | Dimensionality of input images. e.g. `2` for 2D images, `3` for 3D images. + default: 3 - image_type: type: integer description: | @@ -57,6 +58,7 @@ args: Interpolation method to use for the transformation. Content in `[...]` is optional. Refer the the antsApplyTransforms documentation for more details. + default: Linear choices: - Linear - NearestNeighbor @@ -71,6 +73,7 @@ args: - output_dtype: type: string description: Output data type for the warped image. + default: default choices: - char - uchar @@ -84,6 +87,7 @@ args: description: | Default value to use for the input image. It specifies the voxel value when the input point maps outside the output domain. + default: 0 - run_qc: type: boolean description: | diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap index 5f0b6df2..aa9496a2 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap @@ -7,7 +7,7 @@ { "id": "test" }, - "test_b0_to_template_warped.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" + "test_b0_to_template.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" ] ], "1": [ @@ -37,7 +37,7 @@ { "id": "test" }, - "test_b0_to_template_warped.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" + "test_b0_to_template.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" ] ] } @@ -56,7 +56,7 @@ ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nextflow": "25.04.8" }, "timestamp": "2025-10-09T20:09:58.870177157" } diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config b/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config index e7494ca3..21a130ea 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/nextflow.config @@ -1,7 +1,7 @@ process { withName: "REGISTRATION_ANTSAPPLYTRANSFORMS" { ext.interpolation = "Linear" - ext.first_suffix = "to_template" + ext.suffix = "to_template" ext.dimensionality = 3 ext.image_type = 0 ext.output_dtype = "float" diff --git a/modules/nf-neuro/registration/synthmorph/environment.yml b/modules/nf-neuro/registration/synthmorph/environment.yml new file mode 100644 index 00000000..74450f6b --- /dev/null +++ b/modules/nf-neuro/registration/synthmorph/environment.yml @@ -0,0 +1,3 @@ +channels: [] +dependencies: [] +name: registration_synthmorph diff --git a/modules/nf-neuro/registration/synthregistration/main.nf b/modules/nf-neuro/registration/synthmorph/main.nf similarity index 99% rename from modules/nf-neuro/registration/synthregistration/main.nf rename to modules/nf-neuro/registration/synthmorph/main.nf index cb4530a0..7082ba87 100644 --- a/modules/nf-neuro/registration/synthregistration/main.nf +++ b/modules/nf-neuro/registration/synthmorph/main.nf @@ -1,4 +1,4 @@ -process REGISTRATION_SYNTHREGISTRATION { +process REGISTRATION_SYNTHMORPH { tag "$meta.id" label 'process_high' diff --git a/modules/nf-neuro/registration/synthregistration/meta.yml b/modules/nf-neuro/registration/synthmorph/meta.yml similarity index 99% rename from modules/nf-neuro/registration/synthregistration/meta.yml rename to modules/nf-neuro/registration/synthmorph/meta.yml index d424a8dc..72c12183 100644 --- a/modules/nf-neuro/registration/synthregistration/meta.yml +++ b/modules/nf-neuro/registration/synthmorph/meta.yml @@ -1,5 +1,5 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/nf-core/modules/master/modules/meta-schema.json -name: registration_synthregistration +name: registration_synthmorph description: Perform registration using SynthMorph from Freesurfer. Outputs transforms in Freesurfer format .lta for affine and .nii.gz (synthmorph also supports .mgz) for deform, both in RAS orientation. Conversion to other formats is done using lta_convert diff --git a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test b/modules/nf-neuro/registration/synthmorph/tests/main.nf.test similarity index 91% rename from modules/nf-neuro/registration/synthregistration/tests/main.nf.test rename to modules/nf-neuro/registration/synthmorph/tests/main.nf.test index 5209aa36..e2065f6a 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test +++ b/modules/nf-neuro/registration/synthmorph/tests/main.nf.test @@ -1,13 +1,13 @@ nextflow_process { - name "Test Process REGISTRATION_SYNTHREGISTRATION" + name "Test Process REGISTRATION_SYNTHMORPH" script "../main.nf" - process "REGISTRATION_SYNTHREGISTRATION" + process "REGISTRATION_SYNTHMORPH" tag "modules" tag "modules_nfneuro" tag "registration" - tag "registration/synthregistration" + tag "registration/synthmorph" tag "subworkflows" tag "subworkflows/load_test_data" @@ -27,7 +27,7 @@ nextflow_process { } } - test("registration - synthregistration") { + test("registration - synthmorph") { config "./nextflow.config" when { process { @@ -59,7 +59,7 @@ nextflow_process { } } - test("registration - synthregistration - stub-run") { + test("registration - synthmorph - stub-run") { tag "stub" options "-stub-run" when { diff --git a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap b/modules/nf-neuro/registration/synthmorph/tests/main.nf.test.snap similarity index 97% rename from modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap rename to modules/nf-neuro/registration/synthmorph/tests/main.nf.test.snap index 1c7affdc..a543d03b 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/synthmorph/tests/main.nf.test.snap @@ -1,5 +1,5 @@ { - "registration - synthregistration": { + "registration - synthmorph": { "content": [ { "backward_affine": [ @@ -94,7 +94,7 @@ }, "timestamp": "2025-10-16T15:22:15.176985467" }, - "registration - synthregistration - stub-run": { + "registration - synthmorph - stub-run": { "content": [ [ "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" @@ -106,4 +106,4 @@ }, "timestamp": "2025-07-19T04:08:35.236332874" } -} \ No newline at end of file +} diff --git a/modules/nf-neuro/registration/synthregistration/tests/nextflow.config b/modules/nf-neuro/registration/synthmorph/tests/nextflow.config similarity index 84% rename from modules/nf-neuro/registration/synthregistration/tests/nextflow.config rename to modules/nf-neuro/registration/synthmorph/tests/nextflow.config index a08f4c71..b5a2b4fa 100644 --- a/modules/nf-neuro/registration/synthregistration/tests/nextflow.config +++ b/modules/nf-neuro/registration/synthmorph/tests/nextflow.config @@ -1,5 +1,5 @@ process { - withName: "REGISTRATION_SYNTHREGISTRATION" { + withName: "REGISTRATION_SYNTHMORPH" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } ext.models = ["affine", "deform"] ext.regularization = 0.9 diff --git a/modules/nf-neuro/registration/synthmorph/tests/tags.yml b/modules/nf-neuro/registration/synthmorph/tests/tags.yml new file mode 100644 index 00000000..8e3b6188 --- /dev/null +++ b/modules/nf-neuro/registration/synthmorph/tests/tags.yml @@ -0,0 +1,2 @@ +registration/synthmorph: + - "modules/nf-neuro/registration/synthmorph/**" diff --git a/modules/nf-neuro/registration/synthregistration/environment.yml b/modules/nf-neuro/registration/synthregistration/environment.yml deleted file mode 100644 index 13b71ee4..00000000 --- a/modules/nf-neuro/registration/synthregistration/environment.yml +++ /dev/null @@ -1,3 +0,0 @@ -channels: [] -dependencies: [] -name: registration_synthregistration diff --git a/modules/nf-neuro/registration/synthregistration/tests/tags.yml b/modules/nf-neuro/registration/synthregistration/tests/tags.yml deleted file mode 100644 index e06c6bf6..00000000 --- a/modules/nf-neuro/registration/synthregistration/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -registration/synthregistration: - - "modules/nf-neuro/registration/synthregistration/**" diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test index 256642f3..c2e63aae 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test @@ -74,7 +74,7 @@ nextflow_workflow { } test("rbx - download atlas - synthmorph registration") { - config "./synthregistration.config" + config "./synthmorph.config" when { workflow { diff --git a/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config b/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config index 1798856e..12eec6f8 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config +++ b/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config @@ -1,5 +1,5 @@ process { - withName: "REGISTRATION_SYNTHREGISTRATION" { + withName: "REGISTRATION_SYNTHMORPH" { ext.models = ["affine"] ext.regularization = 0.9 ext.steps = 9 diff --git a/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config b/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config index 17605070..8f8d1d65 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config +++ b/subworkflows/nf-neuro/output_template_space/tests/synthmorph.config @@ -1,5 +1,5 @@ process { - withName: "REGISTRATION_SYNTHREGISTRATION" { + withName: "REGISTRATION_SYNTHMORPH" { ext.models = ["affine"] ext.extent = 192 memory = "2G" diff --git a/subworkflows/nf-neuro/registration/main.nf b/subworkflows/nf-neuro/registration/main.nf index 46c350b5..7177c7ee 100644 --- a/subworkflows/nf-neuro/registration/main.nf +++ b/subworkflows/nf-neuro/registration/main.nf @@ -1,7 +1,7 @@ include { REGISTRATION_ANATTODWI } from '../../../modules/nf-neuro/registration/anattodwi/main' include { REGISTRATION_ANTS } from '../../../modules/nf-neuro/registration/ants/main' include { REGISTRATION_EASYREG } from '../../../modules/nf-neuro/registration/easyreg/main' -include { REGISTRATION_SYNTHREGISTRATION } from '../../../modules/nf-neuro/registration/synthregistration/main' +include { REGISTRATION_SYNTHMORPH } from '../../../modules/nf-neuro/registration/synthmorph/main' include { REGISTRATION_CONVERT } from '../../../modules/nf-neuro/registration/convert/main' params.run_easyreg = false @@ -69,24 +69,24 @@ workflow REGISTRATION { ch_register = ch_fixed_image .join(ch_moving_image) - REGISTRATION_SYNTHREGISTRATION ( ch_register ) - ch_versions = ch_versions.mix(REGISTRATION_SYNTHREGISTRATION.out.versions.first()) + REGISTRATION_SYNTHMORPH ( ch_register ) + ch_versions = ch_versions.mix(REGISTRATION_SYNTHMORPH.out.versions.first()) // Tag all synthmorph transforms per type, and index if in a chain. This info will be // used after conversion to sort out the transforms from the conversion module. - ch_convert_forward_affine = REGISTRATION_SYNTHREGISTRATION.out.forward_affine + ch_convert_forward_affine = REGISTRATION_SYNTHMORPH.out.forward_affine .map{ meta, forward_affine -> [meta, [tag: "forward_affine"], forward_affine] } - ch_convert_forward_warp = REGISTRATION_SYNTHREGISTRATION.out.forward_warp + ch_convert_forward_warp = REGISTRATION_SYNTHMORPH.out.forward_warp .map{ meta, forward_warp -> [meta, [tag: "forward_warp"], forward_warp] } - ch_convert_backward_affine = REGISTRATION_SYNTHREGISTRATION.out.backward_affine + ch_convert_backward_affine = REGISTRATION_SYNTHMORPH.out.backward_affine .map{ meta, backward_affine -> [meta, [tag: "backward_affine"], backward_affine] } - ch_convert_backward_warp = REGISTRATION_SYNTHREGISTRATION.out.backward_warp + ch_convert_backward_warp = REGISTRATION_SYNTHMORPH.out.backward_warp .map{ meta, backward_warp -> [meta, [tag: "backward_warp"], backward_warp] } - ch_convert_forward_image_transform = REGISTRATION_SYNTHREGISTRATION.out.forward_image_transform + ch_convert_forward_image_transform = REGISTRATION_SYNTHMORPH.out.forward_image_transform .map{ meta, transforms -> [meta, [tag: "forward_image_transform"], 0.. [meta, tag + [idx: idx], transform]} - ch_convert_backward_image_transform = REGISTRATION_SYNTHREGISTRATION.out.backward_image_transform + ch_convert_backward_image_transform = REGISTRATION_SYNTHMORPH.out.backward_image_transform .map{ meta, transforms -> [meta, [tag: "backward_image_transform"], 0.. [meta, tag + [idx: idx], transform]} @@ -133,7 +133,7 @@ workflow REGISTRATION { } // ** Set compulsory outputs ** // - out_image_warped = REGISTRATION_SYNTHREGISTRATION.out.image_warped + out_image_warped = REGISTRATION_SYNTHMORPH.out.image_warped out_forward_affine = ch_conversion_outputs.forward_affine out_forward_warp = ch_conversion_outputs.forward_warp out_backward_affine = ch_conversion_outputs.backward_affine diff --git a/subworkflows/nf-neuro/registration/meta.yml b/subworkflows/nf-neuro/registration/meta.yml index ac52882e..552defb2 100644 --- a/subworkflows/nf-neuro/registration/meta.yml +++ b/subworkflows/nf-neuro/registration/meta.yml @@ -21,7 +21,7 @@ description: | - Synthmorph (ML): params.run_synthmorph = true - module: REGISTRATION_SYNTHREGISTRATION + module: REGISTRATION_SYNTHMORPH Run SynthMorph any-to-any modality registration. By default, the algorithm is configured to run a chain of affin+deformable transformations, making it suitable for use with most modules @@ -46,7 +46,7 @@ components: - registration/ants - registration/convert - registration/easyreg - - registration/synthregistration + - registration/synthmorph input: - ch_fixed_image: type: file @@ -165,7 +165,7 @@ output: - segmentation: type: file description: | - ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) + ONLY PROVIDED BY REGISTRATION_SYNTHMORPH. Channel containing the SynthSeg v2 (non-robust) segmentation + parcellation in moving space (floating in Easyreg naming convention). Structure: [ val(meta), path(segmentation) ] pattern: "*.{nii,nii.gz}" @@ -173,7 +173,7 @@ output: - reference_segmentation: type: file description: | - ONLY PROVIDED BY REGISTRATION_SYNTHREGISTRATION. Channel containing the SynthSeg v2 (non-robust) + ONLY PROVIDED BY REGISTRATION_SYNTHMORPH. Channel containing the SynthSeg v2 (non-robust) segmentation + parcellation in fixed space (reference in Easyreg naming convention). Structure: [ val(meta), path(reference_segmentation) ] pattern: "*.{nii,nii.gz}" diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test b/subworkflows/nf-neuro/registration/tests/main.nf.test index 71137826..1a941fdc 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test @@ -15,7 +15,7 @@ nextflow_workflow { tag "registration/ants" tag "registration/convert" tag "registration/easyreg" - tag "registration/synthregistration" + tag "registration/synthmorph" tag "load_test_data" @@ -208,7 +208,7 @@ nextflow_workflow { } test("registration - Synthmorph") { - config "./synthregistration.config" + config "./synthmorph.config" when { workflow { """ diff --git a/subworkflows/nf-neuro/registration/tests/synthregistration.config b/subworkflows/nf-neuro/registration/tests/synthregistration.config index 1798856e..12eec6f8 100644 --- a/subworkflows/nf-neuro/registration/tests/synthregistration.config +++ b/subworkflows/nf-neuro/registration/tests/synthregistration.config @@ -1,5 +1,5 @@ process { - withName: "REGISTRATION_SYNTHREGISTRATION" { + withName: "REGISTRATION_SYNTHMORPH" { ext.models = ["affine"] ext.regularization = 0.9 ext.steps = 9 From 10b76807b5e4e3dd5251725f7fe9cfd895ff5b03 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 16 Oct 2025 19:53:33 +0000 Subject: [PATCH 32/37] finish filenaming update to synthmorph + fixes --- .../registration/antsapplytransforms/main.nf | 2 +- .../registration/antsapplytransforms/meta.yml | 4 ++-- .../registration/synthmorph/tests/main.nf.test.snap | 12 ++++++------ .../{synthregistration.config => synthmorph.config} | 0 .../{synthregistration.config => synthmorph.config} | 0 5 files changed, 9 insertions(+), 9 deletions(-) rename subworkflows/nf-neuro/bundle_seg/tests/{synthregistration.config => synthmorph.config} (100%) rename subworkflows/nf-neuro/registration/tests/{synthregistration.config => synthmorph.config} (100%) diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index 48851ff7..386b70b8 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -8,7 +8,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { tuple val(meta), path(images, arity: '1..*'), path(reference), path(transformations, arity: '1..*') output: - tuple val(meta), path("*.nii.gz") , emit: warped_image + tuple val(meta), path("*.{nii.nii.gz}") , emit: warped_image tuple val(meta), path("*_registration_antsapplytransforms_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions diff --git a/modules/nf-neuro/registration/antsapplytransforms/meta.yml b/modules/nf-neuro/registration/antsapplytransforms/meta.yml index 89e6303a..a8511e7b 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/meta.yml +++ b/modules/nf-neuro/registration/antsapplytransforms/meta.yml @@ -127,10 +127,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*_warped.nii.gz": + - "*.{nii.nii.gz}": type: file description: Warped image(s). - pattern: "*_warped.{nii.nii.gz}" + pattern: "*.{nii.nii.gz}" ontologies: [] mqc: - - meta: diff --git a/modules/nf-neuro/registration/synthmorph/tests/main.nf.test.snap b/modules/nf-neuro/registration/synthmorph/tests/main.nf.test.snap index a543d03b..2f86a41a 100644 --- a/modules/nf-neuro/registration/synthmorph/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/synthmorph/tests/main.nf.test.snap @@ -84,7 +84,7 @@ ] ], "versions": [ - "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" + "versions.yml:md5,0375426411588cd1712e84ad66aab5ca" ] } ], @@ -92,18 +92,18 @@ "nf-test": "0.9.0", "nextflow": "25.04.8" }, - "timestamp": "2025-10-16T15:22:15.176985467" + "timestamp": "2025-10-16T19:51:21.67628815" }, "registration - synthmorph - stub-run": { "content": [ [ - "versions.yml:md5,c9f5ddf6ca4a08a71b117bdb7653c7f9" + "versions.yml:md5,0375426411588cd1712e84ad66aab5ca" ] ], "meta": { "nf-test": "0.9.0", - "nextflow": "25.04.6" + "nextflow": "25.04.8" }, - "timestamp": "2025-07-19T04:08:35.236332874" + "timestamp": "2025-10-16T19:51:37.175530527" } -} +} \ No newline at end of file diff --git a/subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config b/subworkflows/nf-neuro/bundle_seg/tests/synthmorph.config similarity index 100% rename from subworkflows/nf-neuro/bundle_seg/tests/synthregistration.config rename to subworkflows/nf-neuro/bundle_seg/tests/synthmorph.config diff --git a/subworkflows/nf-neuro/registration/tests/synthregistration.config b/subworkflows/nf-neuro/registration/tests/synthmorph.config similarity index 100% rename from subworkflows/nf-neuro/registration/tests/synthregistration.config rename to subworkflows/nf-neuro/registration/tests/synthmorph.config From 655586ac89bae44a63e64dfbb21ee450197a49b8 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 16 Oct 2025 20:52:11 +0000 Subject: [PATCH 33/37] fix antsapplytransforms. resnap subworkflows versions --- modules/nf-neuro/registration/antsapplytransforms/main.nf | 2 +- modules/nf-neuro/registration/antsapplytransforms/meta.yml | 4 ++-- subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap | 2 +- subworkflows/nf-neuro/registration/tests/main.nf.test.snap | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/nf-neuro/registration/antsapplytransforms/main.nf b/modules/nf-neuro/registration/antsapplytransforms/main.nf index 386b70b8..437edf41 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/main.nf +++ b/modules/nf-neuro/registration/antsapplytransforms/main.nf @@ -8,7 +8,7 @@ process REGISTRATION_ANTSAPPLYTRANSFORMS { tuple val(meta), path(images, arity: '1..*'), path(reference), path(transformations, arity: '1..*') output: - tuple val(meta), path("*.{nii.nii.gz}") , emit: warped_image + tuple val(meta), path("*.{nii,nii.gz}") , emit: warped_image tuple val(meta), path("*_registration_antsapplytransforms_mqc.gif") , emit: mqc, optional: true path "versions.yml" , emit: versions diff --git a/modules/nf-neuro/registration/antsapplytransforms/meta.yml b/modules/nf-neuro/registration/antsapplytransforms/meta.yml index a8511e7b..e3182eef 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/meta.yml +++ b/modules/nf-neuro/registration/antsapplytransforms/meta.yml @@ -127,10 +127,10 @@ output: description: | Groovy Map containing sample information e.g. `[ id:'test', single_end:false ]` - - "*.{nii.nii.gz}": + - "*.{nii,nii.gz}": type: file description: Warped image(s). - pattern: "*.{nii.nii.gz}" + pattern: "*.{nii,nii.gz}" ontologies: [] mqc: - - meta: diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index 29d31cde..c81054ac 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -50,7 +50,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.8" }, - "timestamp": "2025-10-16T16:28:52.712317132" + "timestamp": "2025-10-16T20:38:06.608019246" }, "rbx - download atlas - ants registration": { "content": [ diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index c481285e..20bf452e 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -64,7 +64,7 @@ ], "versions": [ "versions.yml:md5,300199ef2ea6dd6438553c3ec2615e58", - "versions.yml:md5,f0fa799dd0d27d1974ea409d9c9e5da7" + "versions.yml:md5,5bc0d347809508f4b94ebe433b0f21b9" ] } ], @@ -72,7 +72,7 @@ "nf-test": "0.9.0", "nextflow": "25.04.8" }, - "timestamp": "2025-10-16T15:28:24.402873254" + "timestamp": "2025-10-16T20:51:47.326447932" }, "registration - easyreg": { "content": [ From 5b55b4e371c998598994d3039ff941bbd7c06a12 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 16 Oct 2025 20:52:41 +0000 Subject: [PATCH 34/37] add timeout to retried steps in github workflows, to try to unstuck long running downloads and untar --- .github/workflows/lint_component.yml | 3 +++ .github/workflows/run_checks_suite.yml | 3 +++ .github/workflows/test_component.yml | 3 +++ 3 files changed, 9 insertions(+) diff --git a/.github/workflows/lint_component.yml b/.github/workflows/lint_component.yml index c6077000..966f1853 100644 --- a/.github/workflows/lint_component.yml +++ b/.github/workflows/lint_component.yml @@ -48,6 +48,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: | python-version: "3.10" @@ -60,6 +61,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: | distribution: "temurin" @@ -69,6 +71,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: nf-core/setup-nextflow@561fcfc7146dcb12e3871909b635ab092a781f34 # v2.0.0 with: | version: ${{ inputs.nextflow_version }} diff --git a/.github/workflows/run_checks_suite.yml b/.github/workflows/run_checks_suite.yml index 8557d366..90a48cee 100644 --- a/.github/workflows/run_checks_suite.yml +++ b/.github/workflows/run_checks_suite.yml @@ -28,6 +28,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: | python-version: "3.11" @@ -49,6 +50,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: | node-version: "20" @@ -69,6 +71,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: | node-version: "20" diff --git a/.github/workflows/test_component.yml b/.github/workflows/test_component.yml index 05c640b6..6c619d5f 100644 --- a/.github/workflows/test_component.yml +++ b/.github/workflows/test_component.yml @@ -80,6 +80,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: | python-version: "3.11" @@ -89,6 +90,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: | distribution: "temurin" @@ -98,6 +100,7 @@ jobs: uses: Wandalen/wretry.action@v3.7.2 with: attempt_delay: 5000 + time_out: 600000 action: nf-core/setup-nextflow@561fcfc7146dcb12e3871909b635ab092a781f34 # v2.0.0 with: | version: ${{ inputs.nextflow_version }} From 92195175de028790560b91ce12d796e6c63f1966 Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Thu, 16 Oct 2025 21:02:31 +0000 Subject: [PATCH 35/37] remove retries, as they seem to hang up the workflows --- .github/workflows/lint_component.yml | 26 ++++++---------------- .github/workflows/run_checks_suite.yml | 30 ++++++++------------------ .github/workflows/test_component.yml | 29 ++++++++----------------- 3 files changed, 25 insertions(+), 60 deletions(-) diff --git a/.github/workflows/lint_component.yml b/.github/workflows/lint_component.yml index 966f1853..18a8a2c6 100644 --- a/.github/workflows/lint_component.yml +++ b/.github/workflows/lint_component.yml @@ -45,36 +45,24 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Python - uses: Wandalen/wretry.action@v3.7.2 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: - attempt_delay: 5000 - time_out: 600000 - action: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: | - python-version: "3.10" + python-version: "3.10" - uses: abatilo/actions-poetry@7b6d33e44b4f08d7021a1dee3c044e9c253d6439 # v3.0.0 with: poetry-version: "1.8.*" - name: Setup Java - uses: Wandalen/wretry.action@v3.7.2 + uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: - attempt_delay: 5000 - time_out: 600000 - action: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: | - distribution: "temurin" - java-version: "17" + distribution: "temurin" + java-version: "17" - name: Setup nextflow - uses: Wandalen/wretry.action@v3.7.2 + uses: nf-core/setup-nextflow@561fcfc7146dcb12e3871909b635ab092a781f34 # v2.0.0 with: - attempt_delay: 5000 - time_out: 600000 - action: nf-core/setup-nextflow@561fcfc7146dcb12e3871909b635ab092a781f34 # v2.0.0 - with: | - version: ${{ inputs.nextflow_version }} + version: ${{ inputs.nextflow_version }} - name: Install nf-core tools run: | diff --git a/.github/workflows/run_checks_suite.yml b/.github/workflows/run_checks_suite.yml index 90a48cee..434bccdf 100644 --- a/.github/workflows/run_checks_suite.yml +++ b/.github/workflows/run_checks_suite.yml @@ -25,14 +25,10 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Python - uses: Wandalen/wretry.action@v3.7.2 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: - attempt_delay: 5000 - time_out: 600000 - action: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: | - python-version: "3.11" - cache: "pip" + python-version: "3.11" + cache: "pip" - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 # FIXME Flip this off once we get to less than a couple hundred. Adding @@ -47,14 +43,10 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Node - uses: Wandalen/wretry.action@v3.7.2 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: - attempt_delay: 5000 - time_out: 600000 - action: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: | - node-version: "20" - cache: "npm" + node-version: "20" + cache: "npm" - name: Install Prettier run: npm ci @@ -68,14 +60,10 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Node - uses: Wandalen/wretry.action@v3.7.2 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: - attempt_delay: 5000 - time_out: 600000 - action: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: | - node-version: "20" - cache: "npm" + node-version: "20" + cache: "npm" - name: Install editorconfig-checker run: npm ci diff --git a/.github/workflows/test_component.yml b/.github/workflows/test_component.yml index 6c619d5f..bd558f69 100644 --- a/.github/workflows/test_component.yml +++ b/.github/workflows/test_component.yml @@ -77,33 +77,22 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Python - uses: Wandalen/wretry.action@v3.7.2 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: - attempt_delay: 5000 - time_out: 600000 - action: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - with: | - python-version: "3.11" - cache: "pip" + python-version: "3.11" + cache: "pip" - name: Setup Java - uses: Wandalen/wretry.action@v3.7.2 + uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: - attempt_delay: 5000 - time_out: 600000 - action: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 - with: | - distribution: "temurin" - java-version: "17" + distribution: "temurin" + java-version: "17" - name: Setup nextflow - uses: Wandalen/wretry.action@v3.7.2 + uses: nf-core/setup-nextflow@561fcfc7146dcb12e3871909b635ab092a781f34 # v2.0.0 with: - attempt_delay: 5000 - time_out: 600000 - action: nf-core/setup-nextflow@561fcfc7146dcb12e3871909b635ab092a781f34 # v2.0.0 - with: | - version: ${{ inputs.nextflow_version }} + version: ${{ inputs.nextflow_version }} + - uses: nf-core/setup-nf-test@fbd9d701dd1f41a38b151a737a0f12e97f3c4c56 # v1.3.5 with: version: ${{ inputs.nf_test_version }} From 74181e9f66228d5e35e80d408086d676ce73b0ab Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Fri, 24 Oct 2025 16:37:00 +0000 Subject: [PATCH 36/37] snapshot update --- .../anattodwi/tests/main.nf.test.snap | 83 +++- .../registration/ants/tests/main.nf.test.snap | 418 ++++++++++++++---- .../tests/main.nf.test.snap | 132 +++++- .../convert/tests/main.nf.test.snap | 72 +-- poetry.lock | 208 ++++----- .../bundle_seg/tests/main.nf.test.snap | 44 +- .../nf-neuro/output_template_space/main.nf | 11 +- .../tests/main.nf.test.snap | 39 +- .../tests/nextflow.config | 2 +- .../registration/tests/main.nf.test.snap | 131 +----- .../topup_eddy/tests/main.nf.test.snap | 2 +- .../tractoflow/tests/main.nf.test.snap | 5 +- 12 files changed, 691 insertions(+), 456 deletions(-) diff --git a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap index f9705138..b9ca0127 100644 --- a/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/anattodwi/tests/main.nf.test.snap @@ -21,7 +21,7 @@ ] ], "10": [ - "versions.yml:md5,4d59aa7132ca8851c32f00b29da08d34" + "versions.yml:md5,f7db1ae1e2dd017daa92c91fbd41a28f" ], "2": [ [ @@ -51,7 +51,61 @@ ] ], "5": [ - "versions.yml:md5,f49f4ab58360830a5cdb39d7530b45b1" + [ + { + "id": "test", + "single_end": false + }, + [ + "test_forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", + "test_forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + ] + ] + ], + "6": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test_backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + ] + ] + ], + "7": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_backward0_affine.mat:md5,13ea200e4b163f8a47038ff61524cb1b", + "test_backward1_warp.nii.gz:md5,6a04d7c100075b4ba7a276a55a4094bd" + ] + ] + ], + "8": [ + [ + { + "id": "test", + "single_end": false + }, + [ + "test_forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5", + "test_forward1_affine.mat:md5,18d03f6c1fd587b00b3bc9363eb8ed4f" + ] + ] + ], + "9": [ + [ + { + "id": "test", + "single_end": false + }, + "test_registration_anattodwi_mqc.gif:md5,9cbc1ce8755821996dae18080cf0a23c" + ] ], "anat_warped": [ [ @@ -156,35 +210,26 @@ ] ], "versions": [ - "versions.yml:md5,f49f4ab58360830a5cdb39d7530b45b1" - ], - "warp": [ - [ - { - "id": "test", - "single_end": false - }, - "test__forward0_warp.nii.gz:md5,aa42d4dd6f227d986cd99df45425d5c5" - ] + "versions.yml:md5,f7db1ae1e2dd017daa92c91fbd41a28f" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-09T20:08:38.758050028" + "timestamp": "2025-10-28T12:57:20.84201822" }, "registration - anattodwi -stub-run": { "content": [ [ - "versions.yml:md5,f49f4ab58360830a5cdb39d7530b45b1" + "versions.yml:md5,f7db1ae1e2dd017daa92c91fbd41a28f" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-09T20:08:45.279539751" + "timestamp": "2025-10-28T12:57:40.842368795" } } \ No newline at end of file diff --git a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap index 4bb9572b..75d3eb00 100644 --- a/modules/nf-neuro/registration/ants/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/ants/tests/main.nf.test.snap @@ -1,5 +1,17 @@ { - "registration - ants": { + "registration - ants - stub": { + "content": [ + [ + "versions.yml:md5,78610891ed0adf1a5fe5f0de034d7555" + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-28T13:00:52.757761907" + }, + "registration - ants - SyN quick": { "content": [ { "0": [ @@ -7,7 +19,7 @@ { "id": "test" }, - "test__warped.nii.gz:md5,6491f46d2c2cae09338effb989ec3bf7" + "test_t1_warped.nii.gz:md5,5534f8cb21fcc44f577d520e6083bb83" ] ], "1": [ @@ -15,15 +27,18 @@ { "id": "test" }, - "test__output0GenericAffine.mat:md5,3b6d0eaddd216d15bf50a116c2f09065" + "test_forward1_affine.mat:md5,dde4de8a1ca4ff1647e55dc1fece402c" ] ], + "10": [ + "versions.yml:md5,78610891ed0adf1a5fe5f0de034d7555" + ], "2": [ [ { "id": "test" }, - "test__output1InverseAffine.mat:md5,14b90a8217065e42b21102de73a489c1" + "test_forward0_warp.nii.gz:md5,96b2d18c7537db76366e4557b44f24fe" ] ], "3": [ @@ -31,7 +46,7 @@ { "id": "test" }, - "test__output1Warp.nii.gz:md5,db8e148adf0e32d551cf5e75ca3e76ab" + "test_backward1_warp.nii.gz:md5,28f58437d878a6ea0c81c0e780e2333f" ] ], "4": [ @@ -39,70 +54,165 @@ { "id": "test" }, - "test__output0InverseWarp.nii.gz:md5,3069b784eaa199078d21ecbd5366e27b" + "test_backward0_affine.mat:md5,8cc894275b42e3b78efca499caf22e30" ] ], "5": [ - + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,96b2d18c7537db76366e4557b44f24fe", + "test_forward1_affine.mat:md5,dde4de8a1ca4ff1647e55dc1fece402c" + ] + ] ], "6": [ - "versions.yml:md5,99bd266eefb45cc5ba309704aeecac74" + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,8cc894275b42e3b78efca499caf22e30", + "test_backward1_warp.nii.gz:md5,28f58437d878a6ea0c81c0e780e2333f" + ] + ] ], - "affine": [ + "7": [ [ { "id": "test" }, - "test__output0GenericAffine.mat:md5,3b6d0eaddd216d15bf50a116c2f09065" + [ + "test_backward0_affine.mat:md5,8cc894275b42e3b78efca499caf22e30", + "test_backward1_warp.nii.gz:md5,28f58437d878a6ea0c81c0e780e2333f" + ] ] ], - "image": [ + "8": [ [ { "id": "test" }, - "test__warped.nii.gz:md5,6491f46d2c2cae09338effb989ec3bf7" + [ + "test_forward0_warp.nii.gz:md5,96b2d18c7537db76366e4557b44f24fe", + "test_forward1_affine.mat:md5,dde4de8a1ca4ff1647e55dc1fece402c" + ] ] ], - "inverse_affine": [ + "9": [ [ { "id": "test" }, - "test__output1InverseAffine.mat:md5,14b90a8217065e42b21102de73a489c1" + "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,e5730d99d11edfc9802776c782edbf17" ] ], - "inverse_warp": [ + "backward_affine": [ [ { "id": "test" }, - "test__output0InverseWarp.nii.gz:md5,3069b784eaa199078d21ecbd5366e27b" + "test_backward0_affine.mat:md5,8cc894275b42e3b78efca499caf22e30" ] ], - "mqc": [ - + "backward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,8cc894275b42e3b78efca499caf22e30", + "test_backward1_warp.nii.gz:md5,28f58437d878a6ea0c81c0e780e2333f" + ] + ] ], - "versions": [ - "versions.yml:md5,99bd266eefb45cc5ba309704aeecac74" + "backward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,96b2d18c7537db76366e4557b44f24fe", + "test_forward1_affine.mat:md5,dde4de8a1ca4ff1647e55dc1fece402c" + ] + ] ], - "warp": [ + "backward_warp": [ [ { "id": "test" }, - "test__output1Warp.nii.gz:md5,db8e148adf0e32d551cf5e75ca3e76ab" + "test_backward1_warp.nii.gz:md5,28f58437d878a6ea0c81c0e780e2333f" ] + ], + "forward_affine": [ + [ + { + "id": "test" + }, + "test_forward1_affine.mat:md5,dde4de8a1ca4ff1647e55dc1fece402c" + ] + ], + "forward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,96b2d18c7537db76366e4557b44f24fe", + "test_forward1_affine.mat:md5,dde4de8a1ca4ff1647e55dc1fece402c" + ] + ] + ], + "forward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,8cc894275b42e3b78efca499caf22e30", + "test_backward1_warp.nii.gz:md5,28f58437d878a6ea0c81c0e780e2333f" + ] + ] + ], + "forward_warp": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz:md5,96b2d18c7537db76366e4557b44f24fe" + ] + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,5534f8cb21fcc44f577d520e6083bb83" + ] + ], + "mqc": [ + [ + { + "id": "test" + }, + "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,e5730d99d11edfc9802776c782edbf17" + ] + ], + "versions": [ + "versions.yml:md5,78610891ed0adf1a5fe5f0de034d7555" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-09T20:09:06.126342072" + "timestamp": "2025-10-28T13:00:13.19463937" }, - "registration - ants - quick": { + "registration - ants - SyN": { "content": [ { "0": [ @@ -110,7 +220,7 @@ { "id": "test" }, - "test__warped.nii.gz:md5,45822afae6c0dc33551b690f6f10dbe4" + "test_t1_warped.nii.gz:md5,8d9c289924c4d2c8edab3feae669d1c3" ] ], "1": [ @@ -118,15 +228,18 @@ { "id": "test" }, - "test__output0GenericAffine.mat:md5,17e711c6a2f73415269b4272344890bc" + "test_forward1_affine.mat:md5,16a42a74c35c9fda7786250b333bef86" ] ], + "10": [ + "versions.yml:md5,78610891ed0adf1a5fe5f0de034d7555" + ], "2": [ [ { "id": "test" }, - "test__output1InverseAffine.mat:md5,e5df1f989e0340746d9742ff2d0a7a99" + "test_forward0_warp.nii.gz:md5,9a3b969b74ac82ab0940b8b94677c7b9" ] ], "3": [ @@ -134,7 +247,7 @@ { "id": "test" }, - "test__output1Warp.nii.gz:md5,813a4218d33d5acfebadc4ba0e49df8b" + "test_backward1_warp.nii.gz:md5,3f2d23cce4fbcf970099eecd629d4019" ] ], "4": [ @@ -142,7 +255,7 @@ { "id": "test" }, - "test__output0InverseWarp.nii.gz:md5,813a4218d33d5acfebadc4ba0e49df8b" + "test_backward0_affine.mat:md5,317e067757768c8e75de9d12f84563c9" ] ], "5": [ @@ -150,72 +263,147 @@ { "id": "test" }, - "test_T1_to_DWI_registration_ants_mqc.gif:md5,9cdd7e9bf7facc3f95a61de03e15d47d" + [ + "test_forward0_warp.nii.gz:md5,9a3b969b74ac82ab0940b8b94677c7b9", + "test_forward1_affine.mat:md5,16a42a74c35c9fda7786250b333bef86" + ] ] ], "6": [ - "versions.yml:md5,99bd266eefb45cc5ba309704aeecac74" + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,317e067757768c8e75de9d12f84563c9", + "test_backward1_warp.nii.gz:md5,3f2d23cce4fbcf970099eecd629d4019" + ] + ] ], - "affine": [ + "7": [ [ { "id": "test" }, - "test__output0GenericAffine.mat:md5,17e711c6a2f73415269b4272344890bc" + [ + "test_backward0_affine.mat:md5,317e067757768c8e75de9d12f84563c9", + "test_backward1_warp.nii.gz:md5,3f2d23cce4fbcf970099eecd629d4019" + ] ] ], - "image": [ + "8": [ [ { "id": "test" }, - "test__warped.nii.gz:md5,45822afae6c0dc33551b690f6f10dbe4" + [ + "test_forward0_warp.nii.gz:md5,9a3b969b74ac82ab0940b8b94677c7b9", + "test_forward1_affine.mat:md5,16a42a74c35c9fda7786250b333bef86" + ] ] ], - "inverse_affine": [ + "9": [ + + ], + "backward_affine": [ [ { "id": "test" }, - "test__output1InverseAffine.mat:md5,e5df1f989e0340746d9742ff2d0a7a99" + "test_backward0_affine.mat:md5,317e067757768c8e75de9d12f84563c9" ] ], - "inverse_warp": [ + "backward_image_transform": [ [ { "id": "test" }, - "test__output0InverseWarp.nii.gz:md5,813a4218d33d5acfebadc4ba0e49df8b" + [ + "test_backward0_affine.mat:md5,317e067757768c8e75de9d12f84563c9", + "test_backward1_warp.nii.gz:md5,3f2d23cce4fbcf970099eecd629d4019" + ] ] ], - "mqc": [ + "backward_tractogram_transform": [ [ { "id": "test" }, - "test_T1_to_DWI_registration_ants_mqc.gif:md5,9cdd7e9bf7facc3f95a61de03e15d47d" + [ + "test_forward0_warp.nii.gz:md5,9a3b969b74ac82ab0940b8b94677c7b9", + "test_forward1_affine.mat:md5,16a42a74c35c9fda7786250b333bef86" + ] ] ], - "versions": [ - "versions.yml:md5,99bd266eefb45cc5ba309704aeecac74" + "backward_warp": [ + [ + { + "id": "test" + }, + "test_backward1_warp.nii.gz:md5,3f2d23cce4fbcf970099eecd629d4019" + ] ], - "warp": [ + "forward_affine": [ [ { "id": "test" }, - "test__output1Warp.nii.gz:md5,813a4218d33d5acfebadc4ba0e49df8b" + "test_forward1_affine.mat:md5,16a42a74c35c9fda7786250b333bef86" ] + ], + "forward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,9a3b969b74ac82ab0940b8b94677c7b9", + "test_forward1_affine.mat:md5,16a42a74c35c9fda7786250b333bef86" + ] + ] + ], + "forward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,317e067757768c8e75de9d12f84563c9", + "test_backward1_warp.nii.gz:md5,3f2d23cce4fbcf970099eecd629d4019" + ] + ] + ], + "forward_warp": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz:md5,9a3b969b74ac82ab0940b8b94677c7b9" + ] + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,8d9c289924c4d2c8edab3feae669d1c3" + ] + ], + "mqc": [ + + ], + "versions": [ + "versions.yml:md5,78610891ed0adf1a5fe5f0de034d7555" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.7" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-09T20:09:21.409703964" + "timestamp": "2025-10-28T12:58:47.595933738" }, - "registration - ants - options": { + "registration - ants - no warps": { "content": [ { "0": [ @@ -223,7 +411,7 @@ { "id": "test" }, - "test__warped.nii.gz:md5,c090343bdf2af2eac20a051b3cf9bb20" + "test_t1_warped.nii.gz:md5,c13330e3f71c57f2517dcd6f59f64ff1" ] ], "1": [ @@ -231,9 +419,12 @@ { "id": "test" }, - "test__output0GenericAffine.mat:md5,d3230976041b8532b14a00e2e5760395" + "test_forward1_affine.mat:md5,7387bc8f93dd29d2a0aadb9d5dc06d5b" ] ], + "10": [ + "versions.yml:md5,78610891ed0adf1a5fe5f0de034d7555" + ], "2": [ ], @@ -245,85 +436,134 @@ { "id": "test" }, - "test__output1InverseAffine.mat:md5,10a6c2eededdc85709bbff395f0aab3a" + "test_backward0_affine.mat:md5,733babe33e1656d0f85064caf24d6f82" ] - ], - "3": [ - - ], - "4": [ - ], "5": [ [ { "id": "test" }, - "test__registration_ants_mqc.gif:md5,1bfa145273f0ece8a2293efc7d2a8c2e" + [ + "test_forward1_affine.mat:md5,7387bc8f93dd29d2a0aadb9d5dc06d5b" + ] ] ], "6": [ - "versions.yml:md5,99bd266eefb45cc5ba309704aeecac74" + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,733babe33e1656d0f85064caf24d6f82" + ] + ] ], - "affine": [ + "7": [ [ { "id": "test" }, - "test__output0GenericAffine.mat:md5,d3230976041b8532b14a00e2e5760395" + [ + "test_backward0_affine.mat:md5,733babe33e1656d0f85064caf24d6f82" + ] ] ], - "image": [ + "8": [ [ { "id": "test" }, - "test__warped.nii.gz:md5,c090343bdf2af2eac20a051b3cf9bb20" + [ + "test_forward1_affine.mat:md5,7387bc8f93dd29d2a0aadb9d5dc06d5b" + ] ] ], - "inverse_affine": [ + "9": [ + + ], + "backward_affine": [ [ { "id": "test" }, - "test__output1InverseAffine.mat:md5,10a6c2eededdc85709bbff395f0aab3a" + "test_backward0_affine.mat:md5,733babe33e1656d0f85064caf24d6f82" ] ], - "inverse_warp": [ + "backward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,733babe33e1656d0f85064caf24d6f82" + ] + ] + ], + "backward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward1_affine.mat:md5,7387bc8f93dd29d2a0aadb9d5dc06d5b" + ] + ] + ], + "backward_warp": [ ], - "mqc": [ + "forward_affine": [ [ { "id": "test" }, - "test__registration_ants_mqc.gif:md5,1bfa145273f0ece8a2293efc7d2a8c2e" + "test_forward1_affine.mat:md5,7387bc8f93dd29d2a0aadb9d5dc06d5b" ] ], - "versions": [ - "versions.yml:md5,99bd266eefb45cc5ba309704aeecac74" + "forward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward1_affine.mat:md5,7387bc8f93dd29d2a0aadb9d5dc06d5b" + ] + ] ], - "warp": [ + "forward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,733babe33e1656d0f85064caf24d6f82" + ] + ] + ], + "forward_warp": [ + + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,c13330e3f71c57f2517dcd6f59f64ff1" + ] + ], + "mqc": [ + ], + "versions": [ + "versions.yml:md5,78610891ed0adf1a5fe5f0de034d7555" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.7" - }, - "timestamp": "2025-10-09T20:09:34.159219563" - }, - "registration - ants - stub": { - "content": [ - [ - "versions.yml:md5,99bd266eefb45cc5ba309704aeecac74" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-09T20:09:40.567822165" + "timestamp": "2025-10-28T13:00:29.996790917" } } \ No newline at end of file diff --git a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap index aa9496a2..07555956 100644 --- a/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/antsapplytransforms/tests/main.nf.test.snap @@ -19,7 +19,7 @@ ] ], "2": [ - "versions.yml:md5,fad1b8896193c2260d2e7f7916ab7130" + "versions.yml:md5,bb62f30da9c67a5b3ee5d8316ca38cc5" ], "mqc": [ [ @@ -30,7 +30,7 @@ ] ], "versions": [ - "versions.yml:md5,fad1b8896193c2260d2e7f7916ab7130" + "versions.yml:md5,bb62f30da9c67a5b3ee5d8316ca38cc5" ], "warped_image": [ [ @@ -43,21 +43,135 @@ } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-09T20:09:53.057544388" + "timestamp": "2025-10-28T13:11:02.911101572" + }, + "registration - antsapplytransforms": { + "content": [ + { + "0": [ + [ + { + "id": "test", + "single_end": false + }, + "test_b0_to_template.nii.gz:md5,9e2bcde0e32d10aa9bfbfedfddb65dc3" + ] + ], + "1": [ + [ + { + "id": "test", + "single_end": false + }, + "test_b0_to_template_registration_antsapplytransforms_mqc.gif:md5,a03fb2d2bc43f533144a8633947d3601" + ] + ], + "2": [ + "versions.yml:md5,bb62f30da9c67a5b3ee5d8316ca38cc5" + ], + "mqc": [ + [ + { + "id": "test", + "single_end": false + }, + "test_b0_to_template_registration_antsapplytransforms_mqc.gif:md5,a03fb2d2bc43f533144a8633947d3601" + ] + ], + "versions": [ + "versions.yml:md5,bb62f30da9c67a5b3ee5d8316ca38cc5" + ], + "warped_image": [ + [ + { + "id": "test", + "single_end": false + }, + "test_b0_to_template.nii.gz:md5,9e2bcde0e32d10aa9bfbfedfddb65dc3" + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-28T13:10:09.054640289" }, "registration - antsapplytransforms - stub-run": { "content": [ [ - "versions.yml:md5,fad1b8896193c2260d2e7f7916ab7130" + "versions.yml:md5,bb62f30da9c67a5b3ee5d8316ca38cc5" ] ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" + }, + "timestamp": "2025-10-28T13:12:56.162636033" + }, + "registration - antsapplytransforms - multiple images": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + [ + "test_b0_copy_to_template.nii.gz:md5,00916b78f727d65a811774f932aa9ce7", + "test_b0_to_template.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" + ] + ] + ], + "1": [ + [ + { + "id": "test" + }, + [ + "test_b0_copy_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2", + "test_b0_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2" + ] + ] + ], + "2": [ + "versions.yml:md5,bb62f30da9c67a5b3ee5d8316ca38cc5" + ], + "mqc": [ + [ + { + "id": "test" + }, + [ + "test_b0_copy_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2", + "test_b0_to_template_registration_antsapplytransforms_mqc.gif:md5,f92266ae3c705c11fb3f552ca44f8fe2" + ] + ] + ], + "versions": [ + "versions.yml:md5,bb62f30da9c67a5b3ee5d8316ca38cc5" + ], + "warped_image": [ + [ + { + "id": "test" + }, + [ + "test_b0_copy_to_template.nii.gz:md5,00916b78f727d65a811774f932aa9ce7", + "test_b0_to_template.nii.gz:md5,00916b78f727d65a811774f932aa9ce7" + ] + ] + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-09T20:09:58.870177157" + "timestamp": "2025-10-28T13:12:40.241476817" } } \ No newline at end of file diff --git a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap index ad5184d8..246df87b 100644 --- a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap @@ -28,99 +28,69 @@ "content": [ { "0": [ - [ - { - "id": "test" - }, - "test_out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" - ] + ], "1": [ - "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" + ], "transformation": [ - [ - { - "id": "test" - }, - "test_out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" - ] + ], "versions": [ - "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" + ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-16T15:03:28.499786859" + "timestamp": "2025-10-28T13:36:01.430079972" }, "registration - convert - mixed - to itk": { "content": [ { "0": [ - [ - { - "id": "test1" - }, - "test1_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" - ] + ], "1": [ - "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" + ], "transformation": [ - [ - { - "id": "test1" - }, - "test1_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" - ] + ], "versions": [ - "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" + ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-16T15:03:38.467678996" + "timestamp": "2025-10-28T13:36:10.32322425" }, "registration - convert - deformation - ras to itk (lps)": { "content": [ { "0": [ - [ - { - "id": "test" - }, - "test_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" - ] + ], "1": [ - "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" + ], "transformation": [ - [ - { - "id": "test" - }, - "test_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" - ] + ], "versions": [ - "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" + ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-16T15:03:18.528152956" + "timestamp": "2025-10-28T13:35:51.861013613" } } \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 4d0c5986..3d52216b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "annotated-types" @@ -1017,85 +1017,85 @@ files = [ [[package]] name = "numpy" -version = "2.3.3" +version = "2.3.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.11" files = [ - {file = "numpy-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ffc4f5caba7dfcbe944ed674b7eef683c7e94874046454bb79ed7ee0236f59d"}, - {file = "numpy-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e7e946c7170858a0295f79a60214424caac2ffdb0063d4d79cb681f9aa0aa569"}, - {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:cd4260f64bc794c3390a63bf0728220dd1a68170c169088a1e0dfa2fde1be12f"}, - {file = "numpy-2.3.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f0ddb4b96a87b6728df9362135e764eac3cfa674499943ebc44ce96c478ab125"}, - {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:afd07d377f478344ec6ca2b8d4ca08ae8bd44706763d1efb56397de606393f48"}, - {file = "numpy-2.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc92a5dedcc53857249ca51ef29f5e5f2f8c513e22cfb90faeb20343b8c6f7a6"}, - {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7af05ed4dc19f308e1d9fc759f36f21921eb7bbfc82843eeec6b2a2863a0aefa"}, - {file = "numpy-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:433bf137e338677cebdd5beac0199ac84712ad9d630b74eceeb759eaa45ddf30"}, - {file = "numpy-2.3.3-cp311-cp311-win32.whl", hash = "sha256:eb63d443d7b4ffd1e873f8155260d7f58e7e4b095961b01c91062935c2491e57"}, - {file = "numpy-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:ec9d249840f6a565f58d8f913bccac2444235025bbb13e9a4681783572ee3caa"}, - {file = "numpy-2.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:74c2a948d02f88c11a3c075d9733f1ae67d97c6bdb97f2bb542f980458b257e7"}, - {file = "numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf"}, - {file = "numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25"}, - {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe"}, - {file = "numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b"}, - {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8"}, - {file = "numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20"}, - {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea"}, - {file = "numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7"}, - {file = "numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf"}, - {file = "numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb"}, - {file = "numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5"}, - {file = "numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf"}, - {file = "numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7"}, - {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6"}, - {file = "numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7"}, - {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c"}, - {file = "numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93"}, - {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae"}, - {file = "numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86"}, - {file = "numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8"}, - {file = "numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf"}, - {file = "numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5"}, - {file = "numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc"}, - {file = "numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc"}, - {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b"}, - {file = "numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19"}, - {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30"}, - {file = "numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e"}, - {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3"}, - {file = "numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea"}, - {file = "numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd"}, - {file = "numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d"}, - {file = "numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1"}, - {file = "numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593"}, - {file = "numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652"}, - {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7"}, - {file = "numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a"}, - {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe"}, - {file = "numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421"}, - {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021"}, - {file = "numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf"}, - {file = "numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0"}, - {file = "numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8"}, - {file = "numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe"}, - {file = "numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00"}, - {file = "numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a"}, - {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d"}, - {file = "numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a"}, - {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54"}, - {file = "numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e"}, - {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097"}, - {file = "numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970"}, - {file = "numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5"}, - {file = "numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f"}, - {file = "numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b"}, - {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1e02c7159791cd481e1e6d5ddd766b62a4d5acf8df4d4d1afe35ee9c5c33a41e"}, - {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:dca2d0fc80b3893ae72197b39f69d55a3cd8b17ea1b50aa4c62de82419936150"}, - {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:99683cbe0658f8271b333a1b1b4bb3173750ad59c0c61f5bbdc5b318918fffe3"}, - {file = "numpy-2.3.3-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d9d537a39cc9de668e5cd0e25affb17aec17b577c6b3ae8a3d866b479fbe88d0"}, - {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8596ba2f8af5f93b01d97563832686d20206d303024777f6dfc2e7c7c3f1850e"}, - {file = "numpy-2.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1ec5615b05369925bd1125f27df33f3b6c8bc10d788d5999ecd8769a1fa04db"}, - {file = "numpy-2.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2e267c7da5bf7309670523896df97f93f6e469fb931161f483cd6882b3b1a5dc"}, - {file = "numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029"}, + {file = "numpy-2.3.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e78aecd2800b32e8347ce49316d3eaf04aed849cd5b38e0af39f829a4e59f5eb"}, + {file = "numpy-2.3.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7fd09cc5d65bda1e79432859c40978010622112e9194e581e3415a3eccc7f43f"}, + {file = "numpy-2.3.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1b219560ae2c1de48ead517d085bc2d05b9433f8e49d0955c82e8cd37bd7bf36"}, + {file = "numpy-2.3.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:bafa7d87d4c99752d07815ed7a2c0964f8ab311eb8168f41b910bd01d15b6032"}, + {file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36dc13af226aeab72b7abad501d370d606326a0029b9f435eacb3b8c94b8a8b7"}, + {file = "numpy-2.3.4-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7b2f9a18b5ff9824a6af80de4f37f4ec3c2aab05ef08f51c77a093f5b89adda"}, + {file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9984bd645a8db6ca15d850ff996856d8762c51a2239225288f08f9050ca240a0"}, + {file = "numpy-2.3.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:64c5825affc76942973a70acf438a8ab618dbd692b84cd5ec40a0a0509edc09a"}, + {file = "numpy-2.3.4-cp311-cp311-win32.whl", hash = "sha256:ed759bf7a70342f7817d88376eb7142fab9fef8320d6019ef87fae05a99874e1"}, + {file = "numpy-2.3.4-cp311-cp311-win_amd64.whl", hash = "sha256:faba246fb30ea2a526c2e9645f61612341de1a83fb1e0c5edf4ddda5a9c10996"}, + {file = "numpy-2.3.4-cp311-cp311-win_arm64.whl", hash = "sha256:4c01835e718bcebe80394fd0ac66c07cbb90147ebbdad3dcecd3f25de2ae7e2c"}, + {file = "numpy-2.3.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ef1b5a3e808bc40827b5fa2c8196151a4c5abe110e1726949d7abddfe5c7ae11"}, + {file = "numpy-2.3.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c2f91f496a87235c6aaf6d3f3d89b17dba64996abadccb289f48456cff931ca9"}, + {file = "numpy-2.3.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:f77e5b3d3da652b474cc80a14084927a5e86a5eccf54ca8ca5cbd697bf7f2667"}, + {file = "numpy-2.3.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8ab1c5f5ee40d6e01cbe96de5863e39b215a4d24e7d007cad56c7184fdf4aeef"}, + {file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77b84453f3adcb994ddbd0d1c5d11db2d6bda1a2b7fd5ac5bd4649d6f5dc682e"}, + {file = "numpy-2.3.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4121c5beb58a7f9e6dfdee612cb24f4df5cd4db6e8261d7f4d7450a997a65d6a"}, + {file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:65611ecbb00ac9846efe04db15cbe6186f562f6bb7e5e05f077e53a599225d16"}, + {file = "numpy-2.3.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dabc42f9c6577bcc13001b8810d300fe814b4cfbe8a92c873f269484594f9786"}, + {file = "numpy-2.3.4-cp312-cp312-win32.whl", hash = "sha256:a49d797192a8d950ca59ee2d0337a4d804f713bb5c3c50e8db26d49666e351dc"}, + {file = "numpy-2.3.4-cp312-cp312-win_amd64.whl", hash = "sha256:985f1e46358f06c2a09921e8921e2c98168ed4ae12ccd6e5e87a4f1857923f32"}, + {file = "numpy-2.3.4-cp312-cp312-win_arm64.whl", hash = "sha256:4635239814149e06e2cb9db3dd584b2fa64316c96f10656983b8026a82e6e4db"}, + {file = "numpy-2.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c090d4860032b857d94144d1a9976b8e36709e40386db289aaf6672de2a81966"}, + {file = "numpy-2.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a13fc473b6db0be619e45f11f9e81260f7302f8d180c49a22b6e6120022596b3"}, + {file = "numpy-2.3.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:3634093d0b428e6c32c3a69b78e554f0cd20ee420dcad5a9f3b2a63762ce4197"}, + {file = "numpy-2.3.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:043885b4f7e6e232d7df4f51ffdef8c36320ee9d5f227b380ea636722c7ed12e"}, + {file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ee6a571d1e4f0ea6d5f22d6e5fbd6ed1dc2b18542848e1e7301bd190500c9d7"}, + {file = "numpy-2.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc8a63918b04b8571789688b2780ab2b4a33ab44bfe8ccea36d3eba51228c953"}, + {file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40cc556d5abbc54aabe2b1ae287042d7bdb80c08edede19f0c0afb36ae586f37"}, + {file = "numpy-2.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ecb63014bb7f4ce653f8be7f1df8cbc6093a5a2811211770f6606cc92b5a78fd"}, + {file = "numpy-2.3.4-cp313-cp313-win32.whl", hash = "sha256:e8370eb6925bb8c1c4264fec52b0384b44f675f191df91cbe0140ec9f0955646"}, + {file = "numpy-2.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:56209416e81a7893036eea03abcb91c130643eb14233b2515c90dcac963fe99d"}, + {file = "numpy-2.3.4-cp313-cp313-win_arm64.whl", hash = "sha256:a700a4031bc0fd6936e78a752eefb79092cecad2599ea9c8039c548bc097f9bc"}, + {file = "numpy-2.3.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:86966db35c4040fdca64f0816a1c1dd8dbd027d90fca5a57e00e1ca4cd41b879"}, + {file = "numpy-2.3.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:838f045478638b26c375ee96ea89464d38428c69170360b23a1a50fa4baa3562"}, + {file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d7315ed1dab0286adca467377c8381cd748f3dc92235f22a7dfc42745644a96a"}, + {file = "numpy-2.3.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:84f01a4d18b2cc4ade1814a08e5f3c907b079c847051d720fad15ce37aa930b6"}, + {file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:817e719a868f0dacde4abdfc5c1910b301877970195db9ab6a5e2c4bd5b121f7"}, + {file = "numpy-2.3.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85e071da78d92a214212cacea81c6da557cab307f2c34b5f85b628e94803f9c0"}, + {file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2ec646892819370cf3558f518797f16597b4e4669894a2ba712caccc9da53f1f"}, + {file = "numpy-2.3.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:035796aaaddfe2f9664b9a9372f089cfc88bd795a67bd1bfe15e6e770934cf64"}, + {file = "numpy-2.3.4-cp313-cp313t-win32.whl", hash = "sha256:fea80f4f4cf83b54c3a051f2f727870ee51e22f0248d3114b8e755d160b38cfb"}, + {file = "numpy-2.3.4-cp313-cp313t-win_amd64.whl", hash = "sha256:15eea9f306b98e0be91eb344a94c0e630689ef302e10c2ce5f7e11905c704f9c"}, + {file = "numpy-2.3.4-cp313-cp313t-win_arm64.whl", hash = "sha256:b6c231c9c2fadbae4011ca5e7e83e12dc4a5072f1a1d85a0a7b3ed754d145a40"}, + {file = "numpy-2.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:81c3e6d8c97295a7360d367f9f8553973651b76907988bb6066376bc2252f24e"}, + {file = "numpy-2.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7c26b0b2bf58009ed1f38a641f3db4be8d960a417ca96d14e5b06df1506d41ff"}, + {file = "numpy-2.3.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:62b2198c438058a20b6704351b35a1d7db881812d8512d67a69c9de1f18ca05f"}, + {file = "numpy-2.3.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:9d729d60f8d53a7361707f4b68a9663c968882dd4f09e0d58c044c8bf5faee7b"}, + {file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd0c630cf256b0a7fd9d0a11c9413b42fef5101219ce6ed5a09624f5a65392c7"}, + {file = "numpy-2.3.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5e081bc082825f8b139f9e9fe42942cb4054524598aaeb177ff476cc76d09d2"}, + {file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15fb27364ed84114438fff8aaf998c9e19adbeba08c0b75409f8c452a8692c52"}, + {file = "numpy-2.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:85d9fb2d8cd998c84d13a79a09cc0c1091648e848e4e6249b0ccd7f6b487fa26"}, + {file = "numpy-2.3.4-cp314-cp314-win32.whl", hash = "sha256:e73d63fd04e3a9d6bc187f5455d81abfad05660b212c8804bf3b407e984cd2bc"}, + {file = "numpy-2.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:3da3491cee49cf16157e70f607c03a217ea6647b1cea4819c4f48e53d49139b9"}, + {file = "numpy-2.3.4-cp314-cp314-win_arm64.whl", hash = "sha256:6d9cd732068e8288dbe2717177320723ccec4fb064123f0caf9bbd90ab5be868"}, + {file = "numpy-2.3.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:22758999b256b595cf0b1d102b133bb61866ba5ceecf15f759623b64c020c9ec"}, + {file = "numpy-2.3.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9cb177bc55b010b19798dc5497d540dea67fd13a8d9e882b2dae71de0cf09eb3"}, + {file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0f2bcc76f1e05e5ab58893407c63d90b2029908fa41f9f1cc51eecce936c3365"}, + {file = "numpy-2.3.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dc20bde86802df2ed8397a08d793da0ad7a5fd4ea3ac85d757bf5dd4ad7c252"}, + {file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e199c087e2aa71c8f9ce1cb7a8e10677dc12457e7cc1be4798632da37c3e86e"}, + {file = "numpy-2.3.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85597b2d25ddf655495e2363fe044b0ae999b75bc4d630dc0d886484b03a5eb0"}, + {file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04a69abe45b49c5955923cf2c407843d1c85013b424ae8a560bba16c92fe44a0"}, + {file = "numpy-2.3.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e1708fac43ef8b419c975926ce1eaf793b0c13b7356cfab6ab0dc34c0a02ac0f"}, + {file = "numpy-2.3.4-cp314-cp314t-win32.whl", hash = "sha256:863e3b5f4d9915aaf1b8ec79ae560ad21f0b8d5e3adc31e73126491bb86dee1d"}, + {file = "numpy-2.3.4-cp314-cp314t-win_amd64.whl", hash = "sha256:962064de37b9aef801d33bc579690f8bfe6c5e70e29b61783f60bcba838a14d6"}, + {file = "numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29"}, + {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6e274603039f924c0fe5cb73438fa9246699c78a6df1bd3decef9ae592ae1c05"}, + {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d149aee5c72176d9ddbc6803aef9c0f6d2ceeea7626574fc68518da5476fa346"}, + {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:6d34ed9db9e6395bb6cd33286035f73a59b058169733a9db9f85e650b88df37e"}, + {file = "numpy-2.3.4-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:fdebe771ca06bb8d6abce84e51dca9f7921fe6ad34a0c914541b063e9a68928b"}, + {file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e92defe6c08211eb77902253b14fe5b480ebc5112bc741fd5e9cd0608f847"}, + {file = "numpy-2.3.4-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13b9062e4f5c7ee5c7e5be96f29ba71bc5a37fed3d1d77c37390ae00724d296d"}, + {file = "numpy-2.3.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:81b3a59793523e552c4a96109dde028aa4448ae06ccac5a76ff6532a85558a7f"}, + {file = "numpy-2.3.4.tar.gz", hash = "sha256:a7d018bfedb375a8d979ac758b120ba846a7fe764911a64465fd87b8729f4a6a"}, ] [[package]] @@ -1269,13 +1269,13 @@ ubiquerg = ">=0.6.3" [[package]] name = "peppy" -version = "0.40.7" +version = "0.40.8" description = "A python-based project metadata manager for portable encapsulated projects" optional = false python-versions = "*" files = [ - {file = "peppy-0.40.7-py3-none-any.whl", hash = "sha256:5d2351f6cee6172eb82b90149b931a7827ed0445965b23ba3c36ddb70b3c2b3e"}, - {file = "peppy-0.40.7.tar.gz", hash = "sha256:5e3ddce8b5ef70bdf81e2839d5429bee267549265c07e0618469fe70a716e8ea"}, + {file = "peppy-0.40.8-py3-none-any.whl", hash = "sha256:9d146f8db5a7867de754a63b7012ead1b884c0dddb2609e878ee5548701cd59e"}, + {file = "peppy-0.40.8.tar.gz", hash = "sha256:2dcfe8e348130e94570340e2dfc96ce672d8af78c8ae97e21f2b0afe22ce2a8a"}, ] [package.dependencies] @@ -1510,24 +1510,34 @@ wcwidth = "*" [[package]] name = "psutil" -version = "7.1.0" +version = "7.1.2" description = "Cross-platform lib for process and system monitoring." optional = false python-versions = ">=3.6" files = [ - {file = "psutil-7.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76168cef4397494250e9f4e73eb3752b146de1dd950040b29186d0cce1d5ca13"}, - {file = "psutil-7.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:5d007560c8c372efdff9e4579c2846d71de737e4605f611437255e81efcca2c5"}, - {file = "psutil-7.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22e4454970b32472ce7deaa45d045b34d3648ce478e26a04c7e858a0a6e75ff3"}, - {file = "psutil-7.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c70e113920d51e89f212dd7be06219a9b88014e63a4cec69b684c327bc474e3"}, - {file = "psutil-7.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d4a113425c037300de3ac8b331637293da9be9713855c4fc9d2d97436d7259d"}, - {file = "psutil-7.1.0-cp37-abi3-win32.whl", hash = "sha256:09ad740870c8d219ed8daae0ad3b726d3bf9a028a198e7f3080f6a1888b99bca"}, - {file = "psutil-7.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:57f5e987c36d3146c0dd2528cd42151cf96cd359b9d67cfff836995cc5df9a3d"}, - {file = "psutil-7.1.0-cp37-abi3-win_arm64.whl", hash = "sha256:6937cb68133e7c97b6cc9649a570c9a18ba0efebed46d8c5dae4c07fa1b67a07"}, - {file = "psutil-7.1.0.tar.gz", hash = "sha256:655708b3c069387c8b77b072fc429a57d0e214221d01c0a772df7dfedcb3bcd2"}, + {file = "psutil-7.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0cc5c6889b9871f231ed5455a9a02149e388fffcb30b607fb7a8896a6d95f22e"}, + {file = "psutil-7.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8e9e77a977208d84aa363a4a12e0f72189d58bbf4e46b49aae29a2c6e93ef206"}, + {file = "psutil-7.1.2-cp313-cp313t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d9623a5e4164d2220ecceb071f4b333b3c78866141e8887c072129185f41278"}, + {file = "psutil-7.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:364b1c10fe4ed59c89ec49e5f1a70da353b27986fa8233b4b999df4742a5ee2f"}, + {file = "psutil-7.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f101ef84de7e05d41310e3ccbdd65a6dd1d9eed85e8aaf0758405d022308e204"}, + {file = "psutil-7.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:20c00824048a95de67f00afedc7b08b282aa08638585b0206a9fb51f28f1a165"}, + {file = "psutil-7.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:e09cfe92aa8e22b1ec5e2d394820cf86c5dff6367ac3242366485dfa874d43bc"}, + {file = "psutil-7.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fa6342cf859c48b19df3e4aa170e4cfb64aadc50b11e06bb569c6c777b089c9e"}, + {file = "psutil-7.1.2-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:625977443498ee7d6c1e63e93bacca893fd759a66c5f635d05e05811d23fb5ee"}, + {file = "psutil-7.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a24bcd7b7f2918d934af0fb91859f621b873d6aa81267575e3655cd387572a7"}, + {file = "psutil-7.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:329f05610da6380982e6078b9d0881d9ab1e9a7eb7c02d833bfb7340aa634e31"}, + {file = "psutil-7.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:7b04c29e3c0c888e83ed4762b70f31e65c42673ea956cefa8ced0e31e185f582"}, + {file = "psutil-7.1.2-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c9ba5c19f2d46203ee8c152c7b01df6eec87d883cfd8ee1af2ef2727f6b0f814"}, + {file = "psutil-7.1.2-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a486030d2fe81bec023f703d3d155f4823a10a47c36784c84f1cc7f8d39bedb"}, + {file = "psutil-7.1.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3efd8fc791492e7808a51cb2b94889db7578bfaea22df931424f874468e389e3"}, + {file = "psutil-7.1.2-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2aeb9b64f481b8eabfc633bd39e0016d4d8bbcd590d984af764d80bf0851b8a"}, + {file = "psutil-7.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:8e17852114c4e7996fe9da4745c2bdef001ebbf2f260dec406290e66628bdb91"}, + {file = "psutil-7.1.2-cp37-abi3-win_arm64.whl", hash = "sha256:3e988455e61c240cc879cb62a008c2699231bf3e3d061d7fce4234463fd2abb4"}, + {file = "psutil-7.1.2.tar.gz", hash = "sha256:aa225cdde1335ff9684708ee8c72650f6598d5ed2114b9a7c5802030b1785018"}, ] [package.extras] -dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pyreadline", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel", "wheel", "wmi"] +dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pyreadline", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "validate-pyproject[all]", "virtualenv", "vulture", "wheel", "wheel", "wmi"] test = ["pytest", "pytest-instafail", "pytest-subtests", "pytest-xdist", "pywin32", "setuptools", "wheel", "wmi"] [[package]] @@ -1543,13 +1553,13 @@ files = [ [[package]] name = "pydantic" -version = "2.12.2" +version = "2.12.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" files = [ - {file = "pydantic-2.12.2-py3-none-any.whl", hash = "sha256:25ff718ee909acd82f1ff9b1a4acfd781bb23ab3739adaa7144f19a6a4e231ae"}, - {file = "pydantic-2.12.2.tar.gz", hash = "sha256:7b8fa15b831a4bbde9d5b84028641ac3080a4ca2cbd4a621a661687e741624fd"}, + {file = "pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf"}, + {file = "pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74"}, ] [package.dependencies] @@ -2282,13 +2292,13 @@ files = [ [[package]] name = "ruamel-yaml" -version = "0.18.15" +version = "0.18.16" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = ">=3.8" files = [ - {file = "ruamel.yaml-0.18.15-py3-none-any.whl", hash = "sha256:148f6488d698b7a5eded5ea793a025308b25eca97208181b6a026037f391f701"}, - {file = "ruamel.yaml-0.18.15.tar.gz", hash = "sha256:dbfca74b018c4c3fba0b9cc9ee33e53c371194a9000e694995e620490fd40700"}, + {file = "ruamel.yaml-0.18.16-py3-none-any.whl", hash = "sha256:048f26d64245bae57a4f9ef6feb5b552a386830ef7a826f235ffb804c59efbba"}, + {file = "ruamel.yaml-0.18.16.tar.gz", hash = "sha256:a6e587512f3c998b2225d68aa1f35111c29fad14aed561a26e73fab729ec5e5a"}, ] [package.dependencies] @@ -2541,13 +2551,13 @@ typer = ["typer (>=0.9.0)"] [[package]] name = "typer" -version = "0.19.2" +version = "0.20.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.8" files = [ - {file = "typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9"}, - {file = "typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca"}, + {file = "typer-0.20.0-py3-none-any.whl", hash = "sha256:5b463df6793ec1dca6213a3cf4c0f03bc6e322ac5e16e13ddd622a889489784a"}, + {file = "typer-0.20.0.tar.gz", hash = "sha256:1aaf6494031793e4876fb0bacfa6a912b551cf43c1e63c800df8b1a866720c37"}, ] [package.dependencies] diff --git a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap index c81054ac..a155eb84 100644 --- a/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/bundle_seg/tests/main.nf.test.snap @@ -2,36 +2,6 @@ "rbx - download atlas - synthmorph registration": { "content": [ { - "0": [ - [ - { - "id": "test", - "single_end": false - }, - [ - "test__AF_L_cleaned.trk:md5,b9a6567efffa206202f37c11afea2391", - "test__CC_Fr_2_cleaned.trk:md5,ad18f4415d6d5baae1ec81359ccffecb", - "test__CC_Pr_Po_cleaned.trk:md5,dca763cddc2decfa64baf452cc035b5a", - "test__CG_R_An_cleaned.trk:md5,79c5f2469b1fcae2599247ced8d68e07", - "test__CG_R_cleaned.trk:md5,79c5f2469b1fcae2599247ced8d68e07", - "test__FPT_L_Brainstem_cleaned.trk:md5,d6c9af62d9ad65d95257093148bf4d9a", - "test__FPT_L_cleaned.trk:md5,d6c9af62d9ad65d95257093148bf4d9a", - "test__ILF_L_cleaned.trk:md5,00f9f6e33e59bfe8bbe3a5afd18b0f2e", - "test__MCP_cleaned.trk:md5,ed86370180b35e125ae410aa3d520625", - "test__OR_ML_L_cleaned.trk:md5,721b658ed8a4de104c4e7c207d4fe170", - "test__POPT_R_Brainstem_cleaned.trk:md5,6c07d476650f4bca894c4c2454a1783f", - "test__POPT_R_cleaned.trk:md5,6c07d476650f4bca894c4c2454a1783f", - "test__PYT_L_cleaned.trk:md5,ac9973ef987c34ecee0328004033ea46", - "test__PYT_R_Brainstem_cleaned.trk:md5,28b4be34422e356030b6b081efca31d5", - "test__PYT_R_cleaned.trk:md5,50f8127bbaab6f4b9fea790a7c11679d", - "test__SLF_L_cleaned.trk:md5,3660a62ee7e0e413f7417e80c1842e60" - ] - ] - ], - "1": [ - "versions.yml:md5,84a499436fbf8f1367ec4d8b21cf3abd", - "versions.yml:md5,94e5ea77581b6f43f79c3e7e4fc03030" - ], "bundles": [ [ { @@ -41,16 +11,16 @@ ] ], "versions": [ - "versions.yml:md5,00dbfc46ac61e9445b3ec72920926402", + "versions.yml:md5,43c929afa23d3d0382a449b9ba99d7fb", "versions.yml:md5,afaf6c2953accc507d8777303eea8718" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-16T20:38:06.608019246" + "timestamp": "2025-10-28T15:47:10.799145752" }, "rbx - download atlas - ants registration": { "content": [ @@ -64,15 +34,15 @@ ] ], "versions": [ - "versions.yml:md5,386ca841f44a73e4f5cf04171ce7f503", + "versions.yml:md5,9a3df973fb36ebec9763f10ff59ad875", "versions.yml:md5,afaf6c2953accc507d8777303eea8718" ] } ], "meta": { - "nf-test": "0.9.0", + "nf-test": "0.9.3", "nextflow": "25.04.8" }, - "timestamp": "2025-10-16T16:25:01.408812547" + "timestamp": "2025-10-24T15:13:08.130425506" } } \ No newline at end of file diff --git a/subworkflows/nf-neuro/output_template_space/main.nf b/subworkflows/nf-neuro/output_template_space/main.nf index 24dd7dc4..0a5a9997 100644 --- a/subworkflows/nf-neuro/output_template_space/main.nf +++ b/subworkflows/nf-neuro/output_template_space/main.nf @@ -29,12 +29,13 @@ workflow OUTPUT_TEMPLATE_SPACE { // ** or default to $outdir/../templateflow) ** // if ( !file("${params.templateflow_home}/tpl-${params.template}").exists() ) { log.info("Template ${params.template} not found in " + - "${params.templateflow_home}. Will be downloaded." + - "If you do not have access to the internet while running" + - "this pipeline, please download the template manually" + + "${params.templateflow_home}. Will be downloaded. " + + "If you do not have access to the internet while running " + + "this pipeline, please download the template manually " + "and provide the location using --templateflow_home.") - log.info("${params.template} will be downloaded at resolution " + - "${params.templateflow_res} from cohort ${params.templateflow_cohort}.") + log.info("Downloading ${params.template} :") + log.info(" - Resolution : ${params.templateflow_res}mm ") + log.info(" - Cohort : ${params.templateflow_cohort ?: "none"}") UTILS_TEMPLATEFLOW ( [ diff --git a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap index 75f90558..ec2a521a 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/output_template_space/tests/main.nf.test.snap @@ -58,20 +58,21 @@ ], "versions": [ "versions.yml:md5,08c023826481c9130c3914096cda7f63", + "versions.yml:md5,4e02408f236932635d1e7585d80d16a1", + "versions.yml:md5,5091055c3aacdbd4dccc294cc841b8b3", "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", "versions.yml:md5,53e0a593f56efd67061357b22888233f", - "versions.yml:md5,a8806981919b9cc22e2e1b374119a4e6", - "versions.yml:md5,cc26da22b51bd5b3e2a161a9b30c4f0c", - "versions.yml:md5,d6bae503d4e56ee4c5c8f9f951394aec", - "versions.yml:md5,e9d4549cb032979391719cd59bcfae59" + "versions.yml:md5,837bc1b10db6cb6c459b8871725ba254", + "versions.yml:md5,9013974da5ab5a7ae91e580948968e75", + "versions.yml:md5,957fd24bd8b559411e3a565ac7313f40" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-17T17:39:24.646305544" + "timestamp": "2025-10-28T15:51:42.158522262" }, "Template MNI152NLin2009aAsym - no brain mask": { "content": [ @@ -138,20 +139,20 @@ ], "versions": [ "versions.yml:md5,08c023826481c9130c3914096cda7f63", + "versions.yml:md5,2b72cc481686daf9f4a00587bbf1efa3", + "versions.yml:md5,4e02408f236932635d1e7585d80d16a1", + "versions.yml:md5,5091055c3aacdbd4dccc294cc841b8b3", "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", "versions.yml:md5,53e0a593f56efd67061357b22888233f", - "versions.yml:md5,a8806981919b9cc22e2e1b374119a4e6", - "versions.yml:md5,cc26da22b51bd5b3e2a161a9b30c4f0c", - "versions.yml:md5,d6bae503d4e56ee4c5c8f9f951394aec", - "versions.yml:md5,e9d4549cb032979391719cd59bcfae59" + "versions.yml:md5,957fd24bd8b559411e3a565ac7313f40" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-16T15:53:24.130917882" + "timestamp": "2025-10-28T15:50:40.403026792" }, "Template MNI152NLin2009cAsym - local templates": { "content": [ @@ -218,19 +219,19 @@ ], "versions": [ "versions.yml:md5,08c023826481c9130c3914096cda7f63", + "versions.yml:md5,2b72cc481686daf9f4a00587bbf1efa3", "versions.yml:md5,4e02408f236932635d1e7585d80d16a1", + "versions.yml:md5,5091055c3aacdbd4dccc294cc841b8b3", "versions.yml:md5,513f314aaedec96c49c67ed0bd3bbf4b", "versions.yml:md5,53e0a593f56efd67061357b22888233f", - "versions.yml:md5,82fa7e33467013d6fb309385e7a70aba", - "versions.yml:md5,e5d4ec0205b4e948c5e5c3e4579ce5d0", - "versions.yml:md5,ea689c85377dd23d74af147457113bf6" + "versions.yml:md5,957fd24bd8b559411e3a565ac7313f40" ] } ], "meta": { - "nf-test": "0.9.0", + "nf-test": "0.9.3", "nextflow": "25.04.8" }, - "timestamp": "2025-10-16T15:51:15.187833232" + "timestamp": "2025-10-24T14:50:02.140523373" } } \ No newline at end of file diff --git a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config index 39c89e79..5e7ad9ef 100644 --- a/subworkflows/nf-neuro/output_template_space/tests/nextflow.config +++ b/subworkflows/nf-neuro/output_template_space/tests/nextflow.config @@ -16,7 +16,7 @@ process { ext.default_val = 0 ext.run_qc = true } - withName: "WARPMASKS" { + withName: "WARPMASK" { ext.interpolation = "NearestNeighbor" ext.dimensionality = 3 ext.image_type = 1 diff --git a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap index 20bf452e..bc02436a 100644 --- a/subworkflows/nf-neuro/registration/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/registration/tests/main.nf.test.snap @@ -256,135 +256,20 @@ ] ], "versions": [ - "versions.yml:md5,5f3f8c831b55885ffcc7bd976939dbad" + "versions.yml:md5,2740f4407177a63180822db9890b82fc" ] } ], "meta": { - "nf-test": "0.9.0", + "nf-test": "0.9.3", "nextflow": "25.04.8" }, - "timestamp": "2025-10-16T15:27:00.460253907" + "timestamp": "2025-10-24T16:25:08.767472444" }, "registration - ANTs - Anat to DWI": { "content": [ { - "affine": [ - [ - { - "id": "test" - }, - "test__forward1_affine.mat" - ] - ], - "image_transform": [ - [ - { - "id": "test" - }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" - ] - ], - "image_warped": [ - [ - { - "id": "test" - }, - "test__T1w_warped.nii.gz" - ] - ], - "inverse_affine": [ - [ - { - "id": "test" - }, - "test__backward0_affine.mat" - ] - ], - "inverse_image_transform": [ - [ - { - "id": "test" - }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" - ] - ], - "inverse_tractogram_transform": [ - [ - { - "id": "test" - }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" - ] - ], - "inverse_warp": [ - [ - { - "id": "test" - }, - "test__backward1_warp.nii.gz" - ] - ], - "mqc": [ - [ - { - "id": "test" - }, - "test__registration_anattodwi_mqc.gif" - ] - ], - "tractogram_transform": [ - [ - { - "id": "test" - }, - "test__backward0_affine.mat", - "test__backward1_warp.nii.gz" - ] - ], - "versions": [ - "versions.yml:md5,0f0af6043cb0549dd850d1f59d0c7190" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.7" - }, - "timestamp": "2025-10-17T17:41:51.560683985" - }, - "registration - SyNQuick": { - "content": [ - { - "affine": [ - [ - { - "id": "test" - }, - "test__forward1_affine.mat" - ] - ], - "image_transform": [ - [ - { - "id": "test" - }, - "test__forward0_warp.nii.gz", - "test__forward1_affine.mat" - ] - ], - "image_warped": [ - [ - { - "id": "test" - }, - "test__t1_warped.nii.gz" - ] - ], - "inverse_affine": [ + "backward_affine": [ [ { "id": "test" @@ -469,14 +354,14 @@ ] ], "versions": [ - "versions.yml:md5,42f2dcb95a2cf29b157dbaebf162d2dd" + "versions.yml:md5,21ba9553a13abb65e62caa26aa079736" ] } ], "meta": { - "nf-test": "0.9.0", - "nextflow": "25.04.8" + "nf-test": "0.9.3", + "nextflow": "25.10.0" }, - "timestamp": "2025-10-17T17:41:57.285829729" + "timestamp": "2025-10-28T16:02:30.217450739" } } \ No newline at end of file diff --git a/subworkflows/nf-neuro/topup_eddy/tests/main.nf.test.snap b/subworkflows/nf-neuro/topup_eddy/tests/main.nf.test.snap index 5a1990c5..f7682c92 100644 --- a/subworkflows/nf-neuro/topup_eddy/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/topup_eddy/tests/main.nf.test.snap @@ -206,4 +206,4 @@ }, "timestamp": "2025-09-24T13:08:23.941067656" } -} +} \ No newline at end of file diff --git a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap index cf88761e..39fe6e5c 100644 --- a/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap +++ b/subworkflows/nf-neuro/tractoflow/tests/main.nf.test.snap @@ -376,13 +376,12 @@ ], "versions": [ "versions.yml:md5,0db65009e955d16a3cf997ed4401166d", - "versions.yml:md5,1019ce5b5db942aa4e239be81640fe1a", "versions.yml:md5,21aeeda82df6de4b5bdd1c6bb9930eb0", "versions.yml:md5,46756f8a550da8585f854b45afd1036d", "versions.yml:md5,5011203328febedfa9c5af5684bcc20c", "versions.yml:md5,6f86cbe9b96fbefff47fe66fcb287678", "versions.yml:md5,7cabc91ec64b5e824e9b8f60d7dcf930", - "versions.yml:md5,91878ccc28dd256f9f90600fc048c99f", + "versions.yml:md5,91bb720c5b6b219ae9d7e0f671592381", "versions.yml:md5,955e704dfd97848e196333d0cecf0451", "versions.yml:md5,ee0cb6ae187add67175c9997ef1a5fd1" ], @@ -421,7 +420,7 @@ } ], "meta": { - "nf-test": "0.9.0", + "nf-test": "0.9.3", "nextflow": "25.04.8" }, "timestamp": "2025-10-17T17:43:41.279576493" From 5865aa6a296886ce6165c8ffe27e05215fc708cd Mon Sep 17 00:00:00 2001 From: Alex Valcourt Caron Date: Wed, 29 Oct 2025 11:41:58 -0400 Subject: [PATCH 37/37] need to be part of root group to copy the license correctly. Tested other registration tests to check it doesn't affect other containers --- .../convert/tests/main.nf.test.snap | 60 ++++++++++++++----- tests/config/nextflow.config | 6 +- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap index 246df87b..a5d2e898 100644 --- a/modules/nf-neuro/registration/convert/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/convert/tests/main.nf.test.snap @@ -28,16 +28,26 @@ "content": [ { "0": [ - + [ + { + "id": "test" + }, + "test_out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" + ] ], "1": [ - + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ], "transformation": [ - + [ + { + "id": "test" + }, + "test_out_affine.mat:md5,c88fcae39c94d8af95ca00592c2f2634" + ] ], "versions": [ - + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] } ], @@ -45,22 +55,32 @@ "nf-test": "0.9.3", "nextflow": "25.10.0" }, - "timestamp": "2025-10-28T13:36:01.430079972" + "timestamp": "2025-10-29T11:13:34.703328482" }, "registration - convert - mixed - to itk": { "content": [ { "0": [ - + [ + { + "id": "test1" + }, + "test1_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + ] ], "1": [ - + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ], "transformation": [ - + [ + { + "id": "test1" + }, + "test1_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + ] ], "versions": [ - + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] } ], @@ -68,22 +88,32 @@ "nf-test": "0.9.3", "nextflow": "25.10.0" }, - "timestamp": "2025-10-28T13:36:10.32322425" + "timestamp": "2025-10-29T11:13:43.762952295" }, "registration - convert - deformation - ras to itk (lps)": { "content": [ { "0": [ - + [ + { + "id": "test" + }, + "test_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + ] ], "1": [ - + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ], "transformation": [ - + [ + { + "id": "test" + }, + "test_out_warp.nii.gz:md5,69052e6226da946bad1f9466285cbb89" + ] ], "versions": [ - + "versions.yml:md5,8fa42279d7793bb057cd5680bcb241e7" ] } ], @@ -91,6 +121,6 @@ "nf-test": "0.9.3", "nextflow": "25.10.0" }, - "timestamp": "2025-10-28T13:35:51.861013613" + "timestamp": "2025-10-29T11:13:25.855140969" } } \ No newline at end of file diff --git a/tests/config/nextflow.config b/tests/config/nextflow.config index 4e825599..20e45ccd 100644 --- a/tests/config/nextflow.config +++ b/tests/config/nextflow.config @@ -49,7 +49,7 @@ profiles { } docker { docker.enabled = true - docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + docker.runOptions = '-u $(id -u):$(id -g) --group-add root --platform=linux/amd64' } docker_self_hosted{ docker.enabled = true @@ -62,10 +62,10 @@ profiles { docker.runOptions = '--platform=linux/amd64' } arm { - docker.runOptions = '-u $(id -u):$(id -g) --platform=linux/amd64' + docker.runOptions = '-u $(id -u):$(id -g) --group-add root --platform=linux/amd64' } gpu { - docker.runOptions = '-u $(id -u):$(id -g) --gpus all' + docker.runOptions = '-u $(id -u):$(id -g) --group-add root --gpus all' apptainer.runOptions = '--nv' singularity.runOptions = '--nv' }