Skip to content

Conventions

conventions

The common file format for anything that implies transformations is the ITK format :

Transformation typeformat
linear transformations (e.g. rigid and affine).mat
non-linear warps and deformation fields.nii.gz

To guarantee perfect interaction between all components of its library, nf-neuro imposes linear algebra order of operations (from right to left) when applying transformations.

To define a sequence of transformations, use either a list or a glob pattern to a list of transformation files

Consider the following sequence of transformations :

movingT1T2T3fixedmoving \xrightarrow[T_1]{} \bullet \xrightarrow[T_2]{} \bullet \xrightarrow[T_3]{} fixed

and 3 channels, one for each transformation. Use the following to output a channel in the right order :

// All channels are joined on meta, the basic required
// metadata defining a subject, minimally [id: id]
ch_transformations = ch_T1
.join(ch_T2)
.join(ch_T3)
.map{ meta, t1, t2, t3 -> [ meta, [ t3, t2, t1 ] ] }

Registration modules must output their transforms in lists following linear algebra ordering. Additionally, for compatibility with legacy modules, they also must provide individual outputs for an affine and a deformation field (and their inverses).

The following output channels are required :

Channel nameTransformation
image_transformTransformation from moving space to fixed space
inverse_image_transformTransformation from fixed space to moving space
tractogram_transformReversed and inversed transformation from moving space to fixed space
(usually the same as the inverse_image_transform)
inverse_tractogram_transformReversed and inversed transformation from fixed space to moving space
(usually the same as the image_transform)

Transformation files must be collected in one single path variable with a glob pattern, using the arity parameter to cast it as a list of files (see example below).

output:
tuple val(meta), path("*__transform*.{mat,nii.gz}", arity: '1..*') , emit: image_transform
tuple val(meta), path("*__inverse_transform*.{mat,nii.gz}", arity: '1..*'), emit: inverse_image_transform
tuple val(meta), path("*__inverse_transform*.{mat,nii.gz}", arity: '1..*'), emit: tractogram_transform
tuple val(meta), path("*__transform*.{mat,nii.gz}", arity: '1..*') , emit: inverse_tractogram_transform
script:
def prefix = meta.id
"""
# Moving space
touch ${prefix}__transformZ.mat
touch ${prefix}__transformY.mat
touch ${prefix}__transformX.nii.gz
# Fixed space
touch ${prefix}__inverse_transformZ.nii.gz
touch ${prefix}__inverse_transformY.mat
touch ${prefix}__inverse_transformX.mat
# Moving space
"""

All modules that use transformations and need them provided in input should expect a chain of transformations in the form of a list and ordered as stated above. If they only use parts of it, they should parse through it to select the transformations to apply. Define the input variable using a path and the arity parameter in order to ensure it is interpreted as a list in the script section of the module :

input:
tuple val(meta), ..., path(transformations, arity: '1..*')
...
script:
"""
for transform in $transformations
do
echo "I'm doing good work using transformation : \$transform"
done
"""

nf-neuro provides its own custom convention for transformations, based on two required labels that must appear in any transformation filenames :

Format: *_<backward|forward><index>_*.<mat|nii.gz>

  • The direction of the transformation is defined by either the forward or backward label.
  • The label is suffixed with the transformation index in the chain of transformations between spaces. To follow linear algebra order of transformation, indexes are given in inorder, from N - 1 (first) to 0 (last), given N transformation steps.