From 191152d5f2f9a0c1adc70b7a09a1369977bd2e29 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Devenyi" Date: Tue, 2 Jun 2026 12:04:37 -0400 Subject: [PATCH 1/4] Implementation of antsRegistration_affine_SyN.sh for registration --- .../cobralab_ants/environment.yml | 3 + .../registration/cobralab_ants/main.nf | 188 ++++++ .../registration/cobralab_ants/meta.yml | 354 +++++++++++ .../cobralab_ants/tests/main.nf.test | 195 ++++++ .../cobralab_ants/tests/main.nf.test.snap | 569 ++++++++++++++++++ .../cobralab_ants/tests/nextflow.config | 5 + .../tests/nextflow_no_warp.config | 8 + .../cobralab_ants/tests/nextflow_quick.config | 8 + .../registration/cobralab_ants/tests/tags.yml | 2 + 9 files changed, 1332 insertions(+) create mode 100644 modules/nf-neuro/registration/cobralab_ants/environment.yml create mode 100644 modules/nf-neuro/registration/cobralab_ants/main.nf create mode 100644 modules/nf-neuro/registration/cobralab_ants/meta.yml create mode 100644 modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test create mode 100644 modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap create mode 100644 modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config create mode 100644 modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config create mode 100644 modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config create mode 100644 modules/nf-neuro/registration/cobralab_ants/tests/tags.yml diff --git a/modules/nf-neuro/registration/cobralab_ants/environment.yml b/modules/nf-neuro/registration/cobralab_ants/environment.yml new file mode 100644 index 00000000..95ba3083 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/environment.yml @@ -0,0 +1,3 @@ +channels: [] +dependencies: [] +name: registration_cobralabants diff --git a/modules/nf-neuro/registration/cobralab_ants/main.nf b/modules/nf-neuro/registration/cobralab_ants/main.nf new file mode 100644 index 00000000..a8dbe1e4 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/main.nf @@ -0,0 +1,188 @@ + +process REGISTRATION_COBRALABANTS { + tag "$meta.id" + label 'process_medium' + + container "scilus/scilus:dev" + + input: + tuple val(meta), path(fixed_image), path(moving_image), path(mask) //** optional, input = [] **// + + 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("*_registration_ants_mqc.gif") , emit: mqc, optional: true + path "versions.yml" , emit: versions + + when: + task.ext.when == null || task.ext.when + + script: + def args = task.ext.args ?: '' + def prefix = task.ext.prefix ?: "${meta.id}" + def suffix_qc = task.ext.suffix_qc ?: "" + def run_qc = task.ext.run_qc as Boolean || false + + if ( mask ) args += " --fixed-mask $mask" + if ( task.ext.initial_transform ) args += " --initial-transform $task.ext.initial_transform" + if ( task.ext.float ) args += " --float" + if ( task.ext.float_linear ) args += " --float-linear" + if ( task.ext.float_nonlinear ) args += " --float-nonlinear" + if ( task.ext.histogram_matching ) args += " --histogram-matching" + if ( task.ext.rough ) args += " --rough" + if ( task.ext.fast ) args += " --fast" + if ( task.ext.mask_extract ) args += " --mask-extract" + if ( task.ext.mask_all_linear ) args += " --mask-all-linear" + if ( task.ext.keep_mask_after_extract ) args += " --keep-mask-after-extract" + if ( task.ext.resampled_linear_output ) args += " --resampled-linear-output $task.ext.resampled_linear_output" + if ( task.ext.linear_type ) args += " --linear-type $task.ext.linear_type" + if ( task.ext.close ) args += " --close" + if ( task.ext.convergence && task.ext.convergence != 1e-6 ) args += " --convergence $task.ext.convergence" + if ( task.ext.skip_linear ) args += " --skip-linear" + if ( task.ext.linear_metric && task.ext.linear_metric != 'Mattes' ) args += " --linear-metric $task.ext.linear_metric" + if ( task.ext.linear_shrink_factors ) args += " --linear-shrink-factors $task.ext.linear_shrink_factors" + if ( task.ext.linear_smoothing_sigmas ) args += " --linear-smoothing-sigmas $task.ext.linear_smoothing_sigmas" + if ( task.ext.linear_convergence ) args += " --linear-convergence $task.ext.linear_convergence" + if ( task.ext.final_iterations_linear && task.ext.final_iterations_linear != 50 ) args += " --final-iterations-linear $task.ext.final_iterations_linear" + if ( task.ext.kmeans_transformed_linear ) args += " --kmeans-transformed-linear" + if ( task.ext.skip_nonlinear ) args += " --skip-nonlinear" + if ( task.ext.syn_control && task.ext.syn_control != '0.4,4,0' ) args += " --syn-control $task.ext.syn_control" + if ( task.ext.syn_metric && task.ext.syn_metric != 'CC[4]' ) args += " --syn-metric $task.ext.syn_metric" + if ( task.ext.syn_shrink_factors ) args += " --syn-shrink-factors $task.ext.syn_shrink_factors" + if ( task.ext.syn_smoothing_sigmas ) args += " --syn-smoothing-sigmas $task.ext.syn_smoothing_sigmas" + if ( task.ext.syn_convergence ) args += " --syn-convergence $task.ext.syn_convergence" + if ( task.ext.final_iterations_nonlinear && task.ext.final_iterations_nonlinear != 20 ) args += " --final-iterations-nonlinear $task.ext.final_iterations_nonlinear" + if ( task.ext.winsorize_image_intensities ) args += " --winsorize-image-intensities $task.ext.winsorize_image_intensities" + if ( task.ext.clobber ) args += " --clobber" + if ( task.ext.verbose == false ) args += " --no-verbose" + if ( task.ext.debug ) args += " --debug" + + """ + export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=$task.cpus + export OMP_NUM_THREADS=1 + export OPENBLAS_NUM_THREADS=1 + + moving_id=\$(basename $moving_image .nii.gz) + moving_id=\${moving_id#${meta.id}_*} + + antsRegistration_affine_SyN.sh $args --resampled-output ${prefix}_\${moving_id}_warped.nii.gz $moving_image $fixed_image output + + mv output0GenericAffine.mat ${prefix}_forward1_affine.mat + + if [ "${task.ext.skip_nonlinear}" != "true" ]; then + 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] + + ### ** QC ** ### + 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}" + + # Get the middle slice + coronal_dim=\$((\$coronal_dim / 2)) + 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 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 + 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 != 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 + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\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 + """ + + 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 trap to ignore awaited non-zero exit codes + { + trap 'handle_code' ERR + antsRegistration_affine_SyN.sh -h + } + + antsApplyTransforms -h + 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 + + if $run_qc; then + touch ${prefix}_${suffix_qc}_registration_ants_mqc.gif + fi + + cat <<-END_VERSIONS > versions.yml + "${task.process}": + ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*: v?([0-9.a-zA-Z-]+).*/\\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/cobralab_ants/meta.yml b/modules/nf-neuro/registration/cobralab_ants/meta.yml new file mode 100644 index 00000000..b0e44a85 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/meta.yml @@ -0,0 +1,354 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/nf-neuro/modules/main/modules/meta-schema.json +name: "registration_cobralabants" +description: | + Image registration with antsRegistration_affine_SyN.sh from CoBrALab with automatic optimal pyramid generation. + + Defaults: 3D images and multi-stage registration (rigid + similarity + affine + deformable) + + Main features: + (1) Supports multiple linear and nonlinear registration stages controlled by fine-grained parameters (see args). + (2) Supports initial transformations (see `initial_transform` argument). + (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 + - registration + - antsRegistration_affine_SyN +tools: + - ANTs: + description: "Advanced Normalization Tools." + homepage: "https://github.com/ANTsX/ANTs" + documentation: "http://stnava.github.io/ANTsDoc/" + doi: "10.1038/s41598-021-87564-6" + - antsRegistration_affine_SyN.sh: + description: "CoBrALab wrapper around antsRegistration providing optimized registration pyramids." + homepage: "https://github.com/CoBrALab/antsRegistration_affine_SyN" + documentation: "https://github.com/CoBrALab/antsRegistration_affine_SyN/blob/master/README.md" + - 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: + - fast: + type: boolean + description: "Use Mattes for deformation registration stages" + default: false + - histogram_matching: + type: boolean + description: "Perform histogram matching between images before registration." + default: false + - initial_transform: + type: string + description: Algorithmic initialization by geometric center, intensities, or origin or nothing + default: "com-masks" + choices: + - com-masks + - com + - cov + - origin + - none + - 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: "" + - mask_extract: + type: boolean + description: "Use masks to extract input images, only works with both images masked" + default: false + - keep_mask_after_extract: + type: boolean + description: "Keep using masks for metric after extraction" + default: false + - mask_all_linear: + type: boolean + description: "Use masks on all linear stages" + default: false + - resampled_linear_output: + type: string + description: "Output resampled file(s) with only linear transform, repeat for resampling multispectral outputs" + default: "" + - linear_type: + type: string + description: "Type of linear transform" + default: "affine" + choices: + - "rigid" + - "lsq6" + - "similarity" + - "lsq9" + - "affine" + - "lsq12" + - close: + type: boolean + description: "Images are close in space and similarity, skip large scale pyramid search" + default: false + - convergence: + type: float + description: "Convergence stopping value for registration" + default: 1e-6 + - skip_linear: + type: boolean + description: "Skip the linear registration stages" + default: false + - linear_metric: + type: string + description: "Linear metric" + default: "Mattes" + - linear_shrink_factors: + type: string + description: "Override shrink factors for linear stage, provide to override automatic generation, must be provided with sigmas and convergence" + default: "" + - linear_smoothing_sigmas: + type: string + description: "Override smoothing sigmas for linear stage, provide to override automatic generation, must be provided with shrinks and convergence" + default: "" + - linear_convergence: + type: string + description: "Override convergence levels for linear stage, provide to override automatic generation, must be provided with shrinks and sigmas" + default: "" + - final_iterations_linear: + type: integer + description: "Maximum iterations at finest scale for linear automatic generation" + default: 50 + - kmeans_transformed_linear: + type: boolean + description: "KMeans cluster image intensities for linear registration" + default: false + - skip_nonlinear: + type: boolean + description: "Skip the nonlinear stage" + default: false + - syn_control: + type: string + description: "Non-linear (SyN) gradient and regularization parameters, not checked for correctness" + default: "0.4,4,0" + - syn_metric: + type: string + description: "Non-linear (SyN) metric and radius or bins, choose Mattes[32] for faster registrations" + default: "CC[4]" + - syn_shrink_factors: + type: string + description: "Shrink factors for Non-linear (SyN) stage, provide to override automatic generation, must be provided with sigmas and convergence" + default: "" + - syn_smoothing_sigmas: + type: string + description: "Smoothing sigmas for Non-linear (SyN) stage, provide to override automatic generation, must be provided with shrinks and convergence" + default: "" + - syn_convergence: + type: string + description: "Convergence levels for Non-linear (SyN) stage, provide to override automatic generation, must be provided with shrinks and sigmas" + default: "" + - final_iterations_nonlinear: + type: integer + description: "Maximum iterations at finest scale for non-linear automatic generation" + default: 20 + - winsorize_image_intensities: + type: string + description: "Winsorize data based on specified quantiles, comma separated lower,upper" + default: "" + - float: + type: boolean + description: "Calculate registration using float instead of double" + default: false + - float_linear: + type: boolean + description: "Calculate linear registration using float instead of double" + default: false + - float_nonlinear: + type: boolean + description: "Calculate nonlinear registration using float instead of double" + default: false + - clobber: + type: boolean + description: "Overwrite files that already exist" + default: false + - verbose: + type: boolean + description: "Run commands verbosely" + default: true + - debug: + type: boolean + description: "Show all internal commands and logic for debug" + default: false +input: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - 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 + - 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 for the fixed image + pattern: "*.{nii,nii.gz}" + mandatory: false + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format +output: + image_warped: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_warped.nii.gz": + type: file + description: Nifti volume after registration. + pattern: "*_warped.nii.gz" + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + forward_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 from moving to fixed + pattern: "*_forward1_affine.mat" + mandatory: false + ontologies: [] + forward_warp: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_forward0_warp.nii.gz": + type: file + description: Nifti volume containing warp field from moving to fixed + pattern: "*_forward0_warp.nii.gz" + mandatory: false + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + backward_warp: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_backward1_warp.nii.gz": + type: file + description: Nifti volume containing warp field from fixed to moving + pattern: "*_backward1_warp.nii.gz" + mandatory: false + ontologies: + - edam: http://edamontology.org/format_3989 # GZIP format + backward_affine: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_backward0_affine.mat": + type: file + description: Affine transformation from fixed to moving + pattern: "*_backward0_affine.mat" + mandatory: false + ontologies: [] + forward_image_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_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}" + ontologies: [] + backward_image_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_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}" + ontologies: [] + forward_tractogram_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_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}" + ontologies: [] + backward_tractogram_transform: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_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}" + ontologies: [] + mqc: + - - meta: + type: map + description: | + Groovy Map containing sample information + e.g. `[ id:'test', single_end:false ]` + - "*_registration_ants_mqc.gif": + type: file + description: .gif file containing quality control image for the registration + process. Made for use in MultiQC report. + pattern: "*_registration_ants_mqc.gif" + mandatory: false + ontologies: [] + versions: + - versions.yml: + type: file + description: File containing software versions + pattern: versions.yml + ontologies: + - edam: http://edamontology.org/format_3750 # YAML +authors: + - "@ThoumyreStanislas" + - "@AlexVCaron" + - "@gdevenyi" diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test new file mode 100644 index 00000000..e75defde --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test @@ -0,0 +1,195 @@ +nextflow_process { + + name "Test Process REGISTRATION_COBRALABANTS" + script "../main.nf" + process "REGISTRATION_COBRALABANTS" + config "./nextflow.config" + + tag "modules" + tag "modules_nfneuro" + tag "registration" + tag "registration/cobralab_ants" + + tag "subworkflows" + tag "subworkflows/load_test_data" + + setup { + run("LOAD_TEST_DATA", alias: "LOAD_DATA") { + script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf" + process { + """ + input[0] = Channel.from( [ "T1w.zip", "others.zip" ] ) + input[1] = "test.load-test-data" + """ + } + } + } + + test("registration - cobralab_ants - SyN") { + when { + process { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + T1w: it.simpleName == "T1w" + moving: it.simpleName == "others" + } + ch_T1w = ch_split_test_data.T1w.map{ + test_data_directory -> [ + [ id:'test' ], + 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_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) + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("registration - cobralab_ants - SyN quick") { + config "./nextflow_quick.config" + when { + process { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + T1w: it.simpleName == "T1w" + moving: it.simpleName == "others" + } + ch_T1w = ch_split_test_data.T1w.map{ + test_data_directory -> [ + [ id:'test' ], + 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_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) + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("registration - cobralab_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" + moving: it.simpleName == "others" + } + ch_T1w = ch_split_test_data.T1w.map{ + test_data_directory -> [ + [ id:'test' ], + 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_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) + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out).match() } + ) + } + } + + test("registration - cobralab_ants - stub") { + tag "stub" + options "-stub-run" + when { + process { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + T1w: it.simpleName == "T1w" + moving: it.simpleName == "others" + } + ch_T1w = ch_split_test_data.T1w.map{ + test_data_directory -> [ + [ id:'test' ], + 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_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) + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.versions).match() } + ) + } + } +} diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap new file mode 100644 index 00000000..dcb85a09 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap @@ -0,0 +1,569 @@ +{ + "registration - cobralab_ants - stub": { + "content": [ + [ + "versions.yml:md5,fade610633cb2889d7608994412cb9d1" + ] + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.6" + }, + "timestamp": "2026-06-01T20:27:53.507807183" + }, + "registration - cobralab_ants - SyN quick": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,251df364ff0159975fb478837a14ebf2" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + ] + ], + "10": [ + "versions.yml:md5,fade610633cb2889d7608994412cb9d1" + ], + "2": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404" + ] + ], + "3": [ + [ + { + "id": "test" + }, + "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + ] + ], + "4": [ + [ + { + "id": "test" + }, + "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f" + ] + ], + "5": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", + "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + ] + ] + ], + "6": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", + "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + ] + ] + ], + "7": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", + "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + ] + ] + ], + "8": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", + "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + ] + ] + ], + "9": [ + [ + { + "id": "test" + }, + "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,2cf4d372c3c6e3a2d0d609f30417cd0d" + ] + ], + "backward_affine": [ + [ + { + "id": "test" + }, + "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f" + ] + ], + "backward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", + "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + ] + ] + ], + "backward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", + "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + ] + ] + ], + "backward_warp": [ + [ + { + "id": "test" + }, + "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + ] + ], + "forward_affine": [ + [ + { + "id": "test" + }, + "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + ] + ], + "forward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", + "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + ] + ] + ], + "forward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", + "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + ] + ] + ], + "forward_warp": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404" + ] + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,251df364ff0159975fb478837a14ebf2" + ] + ], + "mqc": [ + [ + { + "id": "test" + }, + "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,2cf4d372c3c6e3a2d0d609f30417cd0d" + ] + ], + "versions": [ + "versions.yml:md5,fade610633cb2889d7608994412cb9d1" + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.6" + }, + "timestamp": "2026-06-04T15:11:15.281672876" + }, + "registration - cobralab_ants - SyN": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,16427678de29639812ba8d45ab06cb55" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + ] + ], + "10": [ + "versions.yml:md5,fade610633cb2889d7608994412cb9d1" + ], + "2": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898" + ] + ], + "3": [ + [ + { + "id": "test" + }, + "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + ] + ], + "4": [ + [ + { + "id": "test" + }, + "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e" + ] + ], + "5": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", + "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + ] + ] + ], + "6": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", + "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + ] + ] + ], + "7": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", + "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + ] + ] + ], + "8": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", + "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + ] + ] + ], + "9": [ + + ], + "backward_affine": [ + [ + { + "id": "test" + }, + "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e" + ] + ], + "backward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", + "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + ] + ] + ], + "backward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", + "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + ] + ] + ], + "backward_warp": [ + [ + { + "id": "test" + }, + "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + ] + ], + "forward_affine": [ + [ + { + "id": "test" + }, + "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + ] + ], + "forward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", + "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + ] + ] + ], + "forward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", + "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + ] + ] + ], + "forward_warp": [ + [ + { + "id": "test" + }, + "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898" + ] + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,16427678de29639812ba8d45ab06cb55" + ] + ], + "mqc": [ + + ], + "versions": [ + "versions.yml:md5,fade610633cb2889d7608994412cb9d1" + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.6" + }, + "timestamp": "2026-06-04T15:10:12.33587054" + }, + "registration - cobralab_ants - no warps": { + "content": [ + { + "0": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,0bb3a94c1006ca121c1850f8e8b0f2ff" + ] + ], + "1": [ + [ + { + "id": "test" + }, + "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + ] + ], + "10": [ + "versions.yml:md5,fade610633cb2889d7608994412cb9d1" + ], + "2": [ + + ], + "3": [ + + ], + "4": [ + [ + { + "id": "test" + }, + "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + ] + ], + "5": [ + [ + { + "id": "test" + }, + [ + "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + ] + ] + ], + "6": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + ] + ] + ], + "7": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + ] + ] + ], + "8": [ + [ + { + "id": "test" + }, + [ + "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + ] + ] + ], + "9": [ + + ], + "backward_affine": [ + [ + { + "id": "test" + }, + "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + ] + ], + "backward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + ] + ] + ], + "backward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + ] + ] + ], + "backward_warp": [ + + ], + "forward_affine": [ + [ + { + "id": "test" + }, + "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + ] + ], + "forward_image_transform": [ + [ + { + "id": "test" + }, + [ + "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + ] + ] + ], + "forward_tractogram_transform": [ + [ + { + "id": "test" + }, + [ + "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + ] + ] + ], + "forward_warp": [ + + ], + "image_warped": [ + [ + { + "id": "test" + }, + "test_t1_warped.nii.gz:md5,0bb3a94c1006ca121c1850f8e8b0f2ff" + ] + ], + "mqc": [ + + ], + "versions": [ + "versions.yml:md5,fade610633cb2889d7608994412cb9d1" + ] + } + ], + "meta": { + "nf-test": "0.9.3", + "nextflow": "25.04.6" + }, + "timestamp": "2026-06-04T15:11:31.970595368" + } +} \ No newline at end of file diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config new file mode 100644 index 00000000..bf69c192 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config @@ -0,0 +1,5 @@ +process { + withName: "REGISTRATION_COBRALABANTS" { + publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + } +} diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config new file mode 100644 index 00000000..3c048e11 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config @@ -0,0 +1,8 @@ +process { + withName: "REGISTRATION_COBRALABANTS" { + publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + ext.fast = true + ext.skip_nonlinear = true + ext.linear_type = 'rigid' + } +} diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config new file mode 100644 index 00000000..349e46c9 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config @@ -0,0 +1,8 @@ +process { + withName: "REGISTRATION_COBRALABANTS" { + publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + ext.fast = true + ext.run_qc = true + ext.suffix_qc = "T1_to_T1_slab" + } +} diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/tags.yml b/modules/nf-neuro/registration/cobralab_ants/tests/tags.yml new file mode 100644 index 00000000..84b612f3 --- /dev/null +++ b/modules/nf-neuro/registration/cobralab_ants/tests/tags.yml @@ -0,0 +1,2 @@ +registration/cobralab_ants: + - "modules/nf-neuro/registration/cobralab_ants/**" From 568e62e1b1b83eff1d77ee788fac0ee159bb7aae Mon Sep 17 00:00:00 2001 From: "Gabriel A. Devenyi" Date: Thu, 4 Jun 2026 11:24:48 -0400 Subject: [PATCH 2/4] Add moving mask support to cobralab_ants registration Split single mask input into separate fixed_mask and moving_mask inputs, matching the pattern from PR #367 for the ants registration module. antsRegistration_affine_SyN.sh supports --fixed-mask and --moving-mask as independent flags. --- modules/nf-neuro/registration/cobralab_ants/main.nf | 5 +++-- modules/nf-neuro/registration/cobralab_ants/meta.yml | 9 ++++++++- .../registration/cobralab_ants/tests/main.nf.test | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/nf-neuro/registration/cobralab_ants/main.nf b/modules/nf-neuro/registration/cobralab_ants/main.nf index a8dbe1e4..7890be49 100644 --- a/modules/nf-neuro/registration/cobralab_ants/main.nf +++ b/modules/nf-neuro/registration/cobralab_ants/main.nf @@ -6,7 +6,7 @@ process REGISTRATION_COBRALABANTS { container "scilus/scilus:dev" input: - tuple val(meta), path(fixed_image), path(moving_image), path(mask) //** optional, input = [] **// + tuple val(meta), path(fixed_image), path(moving_image), path(fixed_mask), path(moving_mask) //** optional, input = [] **// output: tuple val(meta), path("*_warped.nii.gz") , emit: image_warped @@ -30,7 +30,8 @@ process REGISTRATION_COBRALABANTS { def suffix_qc = task.ext.suffix_qc ?: "" def run_qc = task.ext.run_qc as Boolean || false - if ( mask ) args += " --fixed-mask $mask" + if ( fixed_mask ) args += " --fixed-mask $fixed_mask" + if ( moving_mask ) args += " --moving-mask $moving_mask" if ( task.ext.initial_transform ) args += " --initial-transform $task.ext.initial_transform" if ( task.ext.float ) args += " --float" if ( task.ext.float_linear ) args += " --float-linear" diff --git a/modules/nf-neuro/registration/cobralab_ants/meta.yml b/modules/nf-neuro/registration/cobralab_ants/meta.yml index b0e44a85..15b37ed6 100644 --- a/modules/nf-neuro/registration/cobralab_ants/meta.yml +++ b/modules/nf-neuro/registration/cobralab_ants/meta.yml @@ -206,13 +206,20 @@ input: mandatory: true ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format - - mask: + - fixed_mask: type: file description: Mask for the fixed image pattern: "*.{nii,nii.gz}" mandatory: false ontologies: - edam: http://edamontology.org/format_4001 # NIFTI format + - moving_mask: + type: file + description: Mask for the moving image + pattern: "*.{nii,nii.gz}" + mandatory: false + ontologies: + - edam: http://edamontology.org/format_4001 # NIFTI format output: image_warped: - - meta: diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test index e75defde..65b2ab31 100644 --- a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test +++ b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test @@ -55,6 +55,7 @@ nextflow_process { input[0] = ch_T1w .join(ch_moving) .join(ch_T1w_mask) + .map{ meta, fixed, moving, fixed_mask -> [meta, fixed, moving, fixed_mask, []] } """ } } @@ -97,6 +98,7 @@ nextflow_process { input[0] = ch_T1w .join(ch_moving) .join(ch_T1w_mask) + .map{ meta, fixed, moving, fixed_mask -> [meta, fixed, moving, fixed_mask, []] } """ } } @@ -139,6 +141,7 @@ nextflow_process { input[0] = ch_T1w .join(ch_moving) .join(ch_T1w_mask) + .map{ meta, fixed, moving, fixed_mask -> [meta, fixed, moving, fixed_mask, []] } """ } } @@ -182,6 +185,7 @@ nextflow_process { input[0] = ch_T1w .join(ch_moving) .join(ch_T1w_mask) + .map{ meta, fixed, moving, fixed_mask -> [meta, fixed, moving, fixed_mask, []] } """ } } From 6b9d768c99709bac7518783c7f0fc1fa006a2075 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Devenyi" Date: Fri, 5 Jun 2026 22:09:17 -0400 Subject: [PATCH 3/4] feat(cobralab_ants): add reproducibility mode, RNG seed, and single_thread support - Forward --reproducibility and --random-seed CLI flags to antsRegistration_affine_SyN.sh (CoBrALab PR #7) - Export ANTS_RANDOM_SEED env var (default 1234) for ancillary ANTs tools - Replace hardcoded thread counts with task.ext.single_thread-aware expressions for ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS and OMP_NUM_THREADS - Remove OPENBLAS_NUM_THREADS (set globally in test config) - Add reproducibility, ants_rng_seed, single_thread args to meta.yml Mirrors the pattern already applied to registration/ants (nf-neuro PR #342). --- modules/nf-neuro/registration/cobralab_ants/main.nf | 11 ++++++----- modules/nf-neuro/registration/cobralab_ants/meta.yml | 12 ++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/nf-neuro/registration/cobralab_ants/main.nf b/modules/nf-neuro/registration/cobralab_ants/main.nf index 7890be49..4d108dbe 100644 --- a/modules/nf-neuro/registration/cobralab_ants/main.nf +++ b/modules/nf-neuro/registration/cobralab_ants/main.nf @@ -3,7 +3,7 @@ process REGISTRATION_COBRALABANTS { tag "$meta.id" label 'process_medium' - container "scilus/scilus:dev" + container "scilus/scilus@sha256:6274eaf3b773019cd789e844c5aed591c50ed760b32e0ae03819cca4b8be66b9" input: tuple val(meta), path(fixed_image), path(moving_image), path(fixed_mask), path(moving_mask) //** optional, input = [] **// @@ -64,11 +64,12 @@ process REGISTRATION_COBRALABANTS { if ( task.ext.clobber ) args += " --clobber" if ( task.ext.verbose == false ) args += " --no-verbose" if ( task.ext.debug ) args += " --debug" - + if ( task.ext.reproducibility ) args += " --reproducibility" + if ( task.ext.ants_rng_seed ) args += " --random-seed $task.ext.ants_rng_seed" """ - export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=$task.cpus - export OMP_NUM_THREADS=1 - export OPENBLAS_NUM_THREADS=1 + export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=${task.ext.single_thread ? 1 : task.cpus} + export ANTS_RANDOM_SEED=${task.ext.ants_rng_seed ?: 1234} + export OMP_NUM_THREADS=${task.ext.single_thread ? 1 : task.cpus} moving_id=\$(basename $moving_image .nii.gz) moving_id=\${moving_id#${meta.id}_*} diff --git a/modules/nf-neuro/registration/cobralab_ants/meta.yml b/modules/nf-neuro/registration/cobralab_ants/meta.yml index 15b37ed6..67eafd4b 100644 --- a/modules/nf-neuro/registration/cobralab_ants/meta.yml +++ b/modules/nf-neuro/registration/cobralab_ants/meta.yml @@ -186,6 +186,18 @@ args: type: boolean description: "Show all internal commands and logic for debug" default: false + - reproducibility: + type: boolean + description: "Use reproducible registration: GC metric for linear stages and fixed random seed." + default: false + - ants_rng_seed: + type: integer + description: "Random seed for ANTs registration. Setting a fixed seed can help with reproducibility of results." + default: 1234 + - single_thread: + type: boolean + description: If true, the command will be run in single-threaded mode. By default, the command will use multiple threads based on the number of CPUs allocated to the task. + default: false input: - - meta: type: map From cb0a599df658150768aadd7fd52903053e5894b2 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Devenyi" Date: Thu, 11 Jun 2026 13:03:45 -0400 Subject: [PATCH 4/4] Update cobralab_ants test snapshots with reproducible results --- .../registration/cobralab_ants/main.nf | 2 +- .../cobralab_ants/tests/main.nf.test | 2 +- .../cobralab_ants/tests/main.nf.test.snap | 142 +++++++++--------- .../cobralab_ants/tests/nextflow.config | 2 + .../tests/nextflow_no_warp.config | 1 + .../cobralab_ants/tests/nextflow_quick.config | 1 + 6 files changed, 77 insertions(+), 73 deletions(-) diff --git a/modules/nf-neuro/registration/cobralab_ants/main.nf b/modules/nf-neuro/registration/cobralab_ants/main.nf index 4d108dbe..eb36bda1 100644 --- a/modules/nf-neuro/registration/cobralab_ants/main.nf +++ b/modules/nf-neuro/registration/cobralab_ants/main.nf @@ -3,7 +3,7 @@ process REGISTRATION_COBRALABANTS { tag "$meta.id" label 'process_medium' - container "scilus/scilus@sha256:6274eaf3b773019cd789e844c5aed591c50ed760b32e0ae03819cca4b8be66b9" + container "scilus/scilus@sha256:2e781993f602bf93aaab24e2ac436b2059d606842263452dc133f74c15485ce1" input: tuple val(meta), path(fixed_image), path(moving_image), path(fixed_mask), path(moving_mask) //** optional, input = [] **// diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test index 65b2ab31..2dad002c 100644 --- a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test +++ b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test @@ -3,7 +3,6 @@ nextflow_process { name "Test Process REGISTRATION_COBRALABANTS" script "../main.nf" process "REGISTRATION_COBRALABANTS" - config "./nextflow.config" tag "modules" tag "modules_nfneuro" @@ -26,6 +25,7 @@ nextflow_process { } test("registration - cobralab_ants - SyN") { + config "./nextflow.config" when { process { """ diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap index dcb85a09..ec466242 100644 --- a/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap +++ b/modules/nf-neuro/registration/cobralab_ants/tests/main.nf.test.snap @@ -19,7 +19,7 @@ { "id": "test" }, - "test_t1_warped.nii.gz:md5,251df364ff0159975fb478837a14ebf2" + "test_t1_warped.nii.gz:md5,23e254700ff411b46818bbb67f102514" ] ], "1": [ @@ -27,7 +27,7 @@ { "id": "test" }, - "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + "test_forward1_affine.mat:md5,e5e110233d5c9d0dce703df27fd1ba7b" ] ], "10": [ @@ -38,7 +38,7 @@ { "id": "test" }, - "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404" + "test_forward0_warp.nii.gz:md5,dc9841eb5c9e20bbc3ec1493e20c92a9" ] ], "3": [ @@ -46,7 +46,7 @@ { "id": "test" }, - "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + "test_backward1_warp.nii.gz:md5,b8b052fafb8b55883967fc38807a8b2c" ] ], "4": [ @@ -54,7 +54,7 @@ { "id": "test" }, - "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f" + "test_backward0_affine.mat:md5,82ad025c50d3208f467de007c4f10302" ] ], "5": [ @@ -63,8 +63,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", - "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + "test_forward0_warp.nii.gz:md5,dc9841eb5c9e20bbc3ec1493e20c92a9", + "test_forward1_affine.mat:md5,e5e110233d5c9d0dce703df27fd1ba7b" ] ] ], @@ -74,8 +74,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", - "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + "test_backward0_affine.mat:md5,82ad025c50d3208f467de007c4f10302", + "test_backward1_warp.nii.gz:md5,b8b052fafb8b55883967fc38807a8b2c" ] ] ], @@ -85,8 +85,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", - "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + "test_backward0_affine.mat:md5,82ad025c50d3208f467de007c4f10302", + "test_backward1_warp.nii.gz:md5,b8b052fafb8b55883967fc38807a8b2c" ] ] ], @@ -96,8 +96,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", - "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + "test_forward0_warp.nii.gz:md5,dc9841eb5c9e20bbc3ec1493e20c92a9", + "test_forward1_affine.mat:md5,e5e110233d5c9d0dce703df27fd1ba7b" ] ] ], @@ -106,7 +106,7 @@ { "id": "test" }, - "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,2cf4d372c3c6e3a2d0d609f30417cd0d" + "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,1a0f150e41349c5bc22fc07bef176f56" ] ], "backward_affine": [ @@ -114,7 +114,7 @@ { "id": "test" }, - "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f" + "test_backward0_affine.mat:md5,82ad025c50d3208f467de007c4f10302" ] ], "backward_image_transform": [ @@ -123,8 +123,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", - "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + "test_backward0_affine.mat:md5,82ad025c50d3208f467de007c4f10302", + "test_backward1_warp.nii.gz:md5,b8b052fafb8b55883967fc38807a8b2c" ] ] ], @@ -134,8 +134,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", - "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + "test_forward0_warp.nii.gz:md5,dc9841eb5c9e20bbc3ec1493e20c92a9", + "test_forward1_affine.mat:md5,e5e110233d5c9d0dce703df27fd1ba7b" ] ] ], @@ -144,7 +144,7 @@ { "id": "test" }, - "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + "test_backward1_warp.nii.gz:md5,b8b052fafb8b55883967fc38807a8b2c" ] ], "forward_affine": [ @@ -152,7 +152,7 @@ { "id": "test" }, - "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + "test_forward1_affine.mat:md5,e5e110233d5c9d0dce703df27fd1ba7b" ] ], "forward_image_transform": [ @@ -161,8 +161,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404", - "test_forward1_affine.mat:md5,075f81dc68b1029823df393b7c529f09" + "test_forward0_warp.nii.gz:md5,dc9841eb5c9e20bbc3ec1493e20c92a9", + "test_forward1_affine.mat:md5,e5e110233d5c9d0dce703df27fd1ba7b" ] ] ], @@ -172,8 +172,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,7e4bcdeba4072df66b4634c686d7321f", - "test_backward1_warp.nii.gz:md5,1e94d029a2ab34cfed15360649d8e631" + "test_backward0_affine.mat:md5,82ad025c50d3208f467de007c4f10302", + "test_backward1_warp.nii.gz:md5,b8b052fafb8b55883967fc38807a8b2c" ] ] ], @@ -182,7 +182,7 @@ { "id": "test" }, - "test_forward0_warp.nii.gz:md5,409f8d6e8456f739ba57365edec91404" + "test_forward0_warp.nii.gz:md5,dc9841eb5c9e20bbc3ec1493e20c92a9" ] ], "image_warped": [ @@ -190,7 +190,7 @@ { "id": "test" }, - "test_t1_warped.nii.gz:md5,251df364ff0159975fb478837a14ebf2" + "test_t1_warped.nii.gz:md5,23e254700ff411b46818bbb67f102514" ] ], "mqc": [ @@ -198,7 +198,7 @@ { "id": "test" }, - "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,2cf4d372c3c6e3a2d0d609f30417cd0d" + "test_T1_to_T1_slab_registration_ants_mqc.gif:md5,1a0f150e41349c5bc22fc07bef176f56" ] ], "versions": [ @@ -210,7 +210,7 @@ "nf-test": "0.9.3", "nextflow": "25.04.6" }, - "timestamp": "2026-06-04T15:11:15.281672876" + "timestamp": "2026-06-11T16:15:15.067300669" }, "registration - cobralab_ants - SyN": { "content": [ @@ -220,7 +220,7 @@ { "id": "test" }, - "test_t1_warped.nii.gz:md5,16427678de29639812ba8d45ab06cb55" + "test_t1_warped.nii.gz:md5,5d32e5aaa5b73cca5b36d24170720780" ] ], "1": [ @@ -228,7 +228,7 @@ { "id": "test" }, - "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + "test_forward1_affine.mat:md5,4b1b6bab4bdd42485f6953bc1bd6d3ad" ] ], "10": [ @@ -239,7 +239,7 @@ { "id": "test" }, - "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898" + "test_forward0_warp.nii.gz:md5,2e7949517d52491062852f01e4da6b8e" ] ], "3": [ @@ -247,7 +247,7 @@ { "id": "test" }, - "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + "test_backward1_warp.nii.gz:md5,30267a9e734d39f1deb3908a91e7439e" ] ], "4": [ @@ -255,7 +255,7 @@ { "id": "test" }, - "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e" + "test_backward0_affine.mat:md5,29da22d3313ea1e77fe529fe40856888" ] ], "5": [ @@ -264,8 +264,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", - "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + "test_forward0_warp.nii.gz:md5,2e7949517d52491062852f01e4da6b8e", + "test_forward1_affine.mat:md5,4b1b6bab4bdd42485f6953bc1bd6d3ad" ] ] ], @@ -275,8 +275,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", - "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + "test_backward0_affine.mat:md5,29da22d3313ea1e77fe529fe40856888", + "test_backward1_warp.nii.gz:md5,30267a9e734d39f1deb3908a91e7439e" ] ] ], @@ -286,8 +286,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", - "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + "test_backward0_affine.mat:md5,29da22d3313ea1e77fe529fe40856888", + "test_backward1_warp.nii.gz:md5,30267a9e734d39f1deb3908a91e7439e" ] ] ], @@ -297,8 +297,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", - "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + "test_forward0_warp.nii.gz:md5,2e7949517d52491062852f01e4da6b8e", + "test_forward1_affine.mat:md5,4b1b6bab4bdd42485f6953bc1bd6d3ad" ] ] ], @@ -310,7 +310,7 @@ { "id": "test" }, - "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e" + "test_backward0_affine.mat:md5,29da22d3313ea1e77fe529fe40856888" ] ], "backward_image_transform": [ @@ -319,8 +319,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", - "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + "test_backward0_affine.mat:md5,29da22d3313ea1e77fe529fe40856888", + "test_backward1_warp.nii.gz:md5,30267a9e734d39f1deb3908a91e7439e" ] ] ], @@ -330,8 +330,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", - "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + "test_forward0_warp.nii.gz:md5,2e7949517d52491062852f01e4da6b8e", + "test_forward1_affine.mat:md5,4b1b6bab4bdd42485f6953bc1bd6d3ad" ] ] ], @@ -340,7 +340,7 @@ { "id": "test" }, - "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + "test_backward1_warp.nii.gz:md5,30267a9e734d39f1deb3908a91e7439e" ] ], "forward_affine": [ @@ -348,7 +348,7 @@ { "id": "test" }, - "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + "test_forward1_affine.mat:md5,4b1b6bab4bdd42485f6953bc1bd6d3ad" ] ], "forward_image_transform": [ @@ -357,8 +357,8 @@ "id": "test" }, [ - "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898", - "test_forward1_affine.mat:md5,7599899766c24369a972b558d780b11d" + "test_forward0_warp.nii.gz:md5,2e7949517d52491062852f01e4da6b8e", + "test_forward1_affine.mat:md5,4b1b6bab4bdd42485f6953bc1bd6d3ad" ] ] ], @@ -368,8 +368,8 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,b109ceb4cf5c8960e8daab2f35ffca2e", - "test_backward1_warp.nii.gz:md5,bc4f4c050b3cf86b6afe90c84639bfd4" + "test_backward0_affine.mat:md5,29da22d3313ea1e77fe529fe40856888", + "test_backward1_warp.nii.gz:md5,30267a9e734d39f1deb3908a91e7439e" ] ] ], @@ -378,7 +378,7 @@ { "id": "test" }, - "test_forward0_warp.nii.gz:md5,301fc34d0477c991e0c92a0dd7123898" + "test_forward0_warp.nii.gz:md5,2e7949517d52491062852f01e4da6b8e" ] ], "image_warped": [ @@ -386,7 +386,7 @@ { "id": "test" }, - "test_t1_warped.nii.gz:md5,16427678de29639812ba8d45ab06cb55" + "test_t1_warped.nii.gz:md5,5d32e5aaa5b73cca5b36d24170720780" ] ], "mqc": [ @@ -401,7 +401,7 @@ "nf-test": "0.9.3", "nextflow": "25.04.6" }, - "timestamp": "2026-06-04T15:10:12.33587054" + "timestamp": "2026-06-11T15:53:25.107843075" }, "registration - cobralab_ants - no warps": { "content": [ @@ -411,7 +411,7 @@ { "id": "test" }, - "test_t1_warped.nii.gz:md5,0bb3a94c1006ca121c1850f8e8b0f2ff" + "test_t1_warped.nii.gz:md5,09c3e38493c4439c8620fd8e27218873" ] ], "1": [ @@ -419,7 +419,7 @@ { "id": "test" }, - "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + "test_forward1_affine.mat:md5,5fc835b00438fe1a11d6fe798acb26a7" ] ], "10": [ @@ -436,7 +436,7 @@ { "id": "test" }, - "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + "test_backward0_affine.mat:md5,0c8c61274750378e99e49907b7fae7de" ] ], "5": [ @@ -445,7 +445,7 @@ "id": "test" }, [ - "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + "test_forward1_affine.mat:md5,5fc835b00438fe1a11d6fe798acb26a7" ] ] ], @@ -455,7 +455,7 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + "test_backward0_affine.mat:md5,0c8c61274750378e99e49907b7fae7de" ] ] ], @@ -465,7 +465,7 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + "test_backward0_affine.mat:md5,0c8c61274750378e99e49907b7fae7de" ] ] ], @@ -475,7 +475,7 @@ "id": "test" }, [ - "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + "test_forward1_affine.mat:md5,5fc835b00438fe1a11d6fe798acb26a7" ] ] ], @@ -487,7 +487,7 @@ { "id": "test" }, - "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + "test_backward0_affine.mat:md5,0c8c61274750378e99e49907b7fae7de" ] ], "backward_image_transform": [ @@ -496,7 +496,7 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + "test_backward0_affine.mat:md5,0c8c61274750378e99e49907b7fae7de" ] ] ], @@ -506,7 +506,7 @@ "id": "test" }, [ - "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + "test_forward1_affine.mat:md5,5fc835b00438fe1a11d6fe798acb26a7" ] ] ], @@ -518,7 +518,7 @@ { "id": "test" }, - "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + "test_forward1_affine.mat:md5,5fc835b00438fe1a11d6fe798acb26a7" ] ], "forward_image_transform": [ @@ -527,7 +527,7 @@ "id": "test" }, [ - "test_forward1_affine.mat:md5,bcb3f5a67b2b7972a4580caf550de668" + "test_forward1_affine.mat:md5,5fc835b00438fe1a11d6fe798acb26a7" ] ] ], @@ -537,7 +537,7 @@ "id": "test" }, [ - "test_backward0_affine.mat:md5,aa2ac6458276be35d966c1792106eabe" + "test_backward0_affine.mat:md5,0c8c61274750378e99e49907b7fae7de" ] ] ], @@ -549,7 +549,7 @@ { "id": "test" }, - "test_t1_warped.nii.gz:md5,0bb3a94c1006ca121c1850f8e8b0f2ff" + "test_t1_warped.nii.gz:md5,09c3e38493c4439c8620fd8e27218873" ] ], "mqc": [ @@ -564,6 +564,6 @@ "nf-test": "0.9.3", "nextflow": "25.04.6" }, - "timestamp": "2026-06-04T15:11:31.970595368" + "timestamp": "2026-06-11T16:15:46.96759771" } } \ No newline at end of file diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config index bf69c192..bbf77b79 100644 --- a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config +++ b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow.config @@ -1,5 +1,7 @@ process { withName: "REGISTRATION_COBRALABANTS" { publishDir = { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" } + ext.reproducibility = true + ext.single_thread = true } } diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config index 3c048e11..68453933 100644 --- a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config +++ b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_no_warp.config @@ -4,5 +4,6 @@ process { ext.fast = true ext.skip_nonlinear = true ext.linear_type = 'rigid' + ext.single_thread = true } } diff --git a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config index 349e46c9..5750c2b0 100644 --- a/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config +++ b/modules/nf-neuro/registration/cobralab_ants/tests/nextflow_quick.config @@ -4,5 +4,6 @@ process { ext.fast = true ext.run_qc = true ext.suffix_qc = "T1_to_T1_slab" + ext.single_thread = true } }