Skip to content

Process configuration

In nf-neuro, we use the task.ext parameter namespace to define configuration options that user can use to fine-tune the behavior of a module. Those options have two specificities :

  1. They are optional by default. If a parameter is not defined, task.ext.parameter will return the value null.
  2. They are static. Their value is bound to the module’s name. Dynamic parameters have to be defined using inputs.

The guidelines below present how to define those parameters, using the DENOISING_NLMEANS module example.

The command scil_denoising_nlmeans.py accepts a few parameters that allow users to adjust its execution to the nature of their data :

  • We can force the estimated noise distribution to be gaussian.
  • The noise distribution can be set to a given sigma, estimated by a basic_sigma method or using the piesno method.
  • We can set the number of coil use to acquire the MRI signal, using number_coils.
  • We can restrict the noise estimation space using a mask.
    • When using the basic_sigma method, it’s the mask_sigma parameter.
    • We can force the use of all voxel with sigma_from_all_voxels.

The definition of their parameter in the module go in the groovy header part of the script section, the one where the prefix and args variables are defined. Use the same operator logic, either the ternary or elvis operator, to define the parameters above.

The full modifications of the module is given below. Take note of the mask_sigma parameter, which required the addition of a new input, since it is a file which must be passed by nextflow at runtime. Also note the new optional output, that returns the noise mask when the piesno method is used :

input:
tuple val(meta), path(image), path(mask) /* optional, input = [] */, path(noise_mask) /* optional, input = [] */
output:
tuple val(meta), path("*__denoised.nii.gz"), emit: image
tuple val(meta), path("*__piesno_noise_mask.nii.gz"), emit: noise_mask, optional: true
path "versions.yml", emit: versions
script:
def prefix = task.ext.prefix ?: "${meta.id}"
def args = task.ext.args ?: []
def input_mask = mask ? "--mask_denoise $mask" : ""
def noise_mask = noise_mask ? "--mask_sigma $noise_mask" : ""
def ncoils = task.ext.number_of_coils ? "--number_coils $task.ext.number_of_coils" : "--number_coils 1"
def sigma = task.ext.sigma ? "--sigma $task.ext.sigma" : ""
def sigma_from_all_voxels = task.ext.sigma_from_all_voxels ? "--sigma_from_all_voxels" : ""
def gaussian = task.ext.gaussian ? "--gaussian" : ""
def method = ""
def save_mask = ""
if ( !sigma ) {
method = task.ext.method ? "--$task.ext.method" : "--basic_sigma"
save_mask = (task.ext.method == "piesno") ? "--save_piesno_mask ${prefix}__piesno_noise_mask.nii.gz" : ""
}
"""
export ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1
export OMP_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
scil_denoising_nlmeans.py $image ${prefix}__denoised.nii.gz $input_mask ${args.join(" ")} --processes $task.cpus
scil_denoising_nlmeans.py $image ${prefix}__denoised.nii.gz $input_mask $noise_mask $save_mask \
$ncoils $gaussian $method $sigma $sigma_from_all_voxels \
${args.join(" ")} --processes $tasks.cpus
"""
cat <<-END_VERSIONS > versions.yml
"${task.process}":
scilpy: \$(pip list | grep scilpy | tr -s ' ' | cut -d' ' -f2)
END_VERSIONS
"""

With that, the module can be configured to the full extent of the command line it encloses. You will see how to access those parameters in the subworkflow configuration section. For now, it’s time to setup a container to host your dependencies, so users don’t have to install them by themselves.