Poor Fieldmap <-> Functional Registration in fMRIPrep (highly variable step)

Summary of what happened:

I’m testing the newest version of fMRIPrep on a small dataset, 1 participant scanned on 9 scanners. For one of the sessions, the EPI ↔ functional registration is quite bad.

In that run, an anatomical mask was provided through the --derivatives argument (it’s a mask calculated by synthstrip and is very good). However, when I don’t provide the mask, the registration looks fine.

(The exclusion of cerebellum is real and not an artifact of figure cropping)

Note that the registration ends up bad when using or not using synthstrip’s --no-csf flag.

Are there gotcha’s when providing pre-specified masks? For example, when providing anatomical masks, do I also need to provide masks for the functionals (and/or fmaps)? Or, do I need to ensure that the mask covers or doesn’t cover certain structures (brainstem, cerebellum, etc)?

(FWIW, if this seems like a possible bug, I’d be happy/motivated to dig around)

Command used (and if a helper script was used, a link to the helper script or the command generated):

docker run \
  --rm -it \
  -v $PWD:$PWD \
  nipreps/fmriprep:24.0.1 \
  --notrack \
  --fs-license-file $PWD/license  \
  --work-dir $PWD/work2 \
  --task-id rest \
  --derivatives synthstrip=$PWD/sourcedata/synthstrip \
  --dummy-scans 15 \
  $PWD/rawdata \
  $PWD/derivatives/fmriprep-synthstrip \
  participant

vs

docker run \
  --rm -it \
  -v $PWD:$PWD \
  nipreps/fmriprep:24.0.1 \
  --notrack \
  --fs-license-file $PWD/license \
  --dummy-scans 15 \
  --work-dir $PWD/work \
  --task-id rest \
  $PWD/rawdata \
  $PWD/derivatives \
  participant

Version:

24.0.1

Environment (Docker, Singularity / Apptainer, custom installation):

Docker

Data formatted according to a validatable standard? Please provide the output of the validator:

bids-validator@1.14.6
(node:9) Warning: Closing directory handle on garbage collection
(Use `node --trace-warnings ...` to show where the warning was created)
	1: [WARN] The recommended file /README is very small. Please consider expanding it with additional information about the dataset. (code: 213 - README_FILE_SMALL)
		./README

	Please visit https://neurostars.org/search?q=README_FILE_SMALL for existing conversations about this issue.

        Summary:                  Available Tasks:        Available Modalities: 
        18 Files, 771.33MB        cuff                    MRI                   
        1 - Subject               rest                                          
        1 - Session                                                             


	If you have any questions, please post on https://neurostars.org/tags/bids.

Relevant log outputs (up to 20 lines):

240905-21:54:38,271 nipype.workflow IMPORTANT:
	 Building fMRIPrep's workflow:
           * BIDS dataset path: /Users/psadil/Desktop/NStravel2/rawdata.
           * Participant list: ['travel2'].
           * Run identifier: 20240905-215427_aff96021-2fa0-443f-8faf-7280522b1da7.
           * Output spaces: MNI152NLin2009cAsym:res-native.
           * Searching for derivatives: [PosixPath('/Users/psadil/Desktop/NStravel2/sourcedata/synthstrip')].
           * Pre-run FreeSurfer's SUBJECTS_DIR: /Users/psadil/Desktop/NStravel2/derivatives/fmriprep-synthstrip/sourcedata/freesurfer.
240905-21:54:38,814 nipype.workflow INFO:
	 ANAT Stage 1: Adding template workflow
240905-21:54:39,171 nipype.workflow INFO:
	 ANAT Found brain mask
240905-21:54:39,171 nipype.workflow INFO:
	 ANAT Skipping skull-strip, INU-correction only
240905-21:54:39,186 nipype.workflow INFO:
	 ANAT Stage 3: Preparing segmentation workflow
240905-21:54:39,190 nipype.workflow INFO:
	 ANAT Stage 4: Preparing normalization workflow for ['MNI152NLin2009cAsym']
240905-21:54:39,199 nipype.workflow INFO:
	 ANAT Stage 5: Preparing surface reconstruction workflow
240905-21:54:39,215 nipype.workflow INFO:
	 ANAT Found brain mask - skipping Stage 6

Screenshots / relevant information:

See above


From digging around, I’m pretty sure that this coregistration failure is unrelated to the mask. Instead, it seems like the misregistration is from an unstable step. The node’s working directory is

work/fmriprep_24_0_wf/sub_[sub]_wf/bold_ses_[ses]_task_[task]_run_[run]_wf/bold_fit_wf/fmapreg_wf/coregister

underneath which is a command like


antsRegistration \
    --collapse-output-transforms 1 \
    --dimensionality 3 \
    --initial-moving-transform \
    \[ /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/fmap_preproc_wf/wf_auto_00000/brainextraction_wf/clipper_post/clipped.nii.gz, /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/bold_ses_NS_task_rest_run_01_wf/bold_fit_wf/enhance_and_skullstrip_bold_wf/n4_correct/sub-travel2_ses-NS_task-rest_run-01_bold_average_corrected.nii.gz, 1 \] \
    --initialize-transforms-per-stage 0 \
    --interpolation LanczosWindowedSinc \
    --output transform8 \
    --transform Rigid\[ 0.1 \] \
    --metric Mattes\[ /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/fmap_preproc_wf/wf_auto_00000/brainextraction_wf/clipper_post/clipped.nii.gz, /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/bold_ses_NS_task_rest_run_01_wf/bold_fit_wf/enhance_and_skullstrip_bold_wf/n4_correct/sub-travel2_ses-NS_task-rest_run-01_bold_average_corrected.nii.gz, 1, 32, Random, 0.25 \] \
    --convergence \[ 50, 1e-07, 5 \] \
    --smoothing-sigmas 8.0mm \
    --shrink-factors 2 \
    --use-histogram-matching 1 \
    --masks \[ /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/fmap_preproc_wf/wf_auto_00000/brainextraction_wf/masker/clipped_mask.nii.gz, /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/bold_ses_NS_task_rest_run_01_wf/bold_fit_wf/enhance_and_skullstrip_bold_wf/combine_masks/sub-travel2_ses-NS_task-rest_run-01_bold_average_corrected_brain_mask_maths.nii.gz \] \
    --transform Rigid\[ 0.1 \] \
    --metric Mattes\[ /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/fmap_preproc_wf/wf_auto_00000/brainextraction_wf/clipper_post/clipped.nii.gz, /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/bold_ses_NS_task_rest_run_01_wf/bold_fit_wf/enhance_and_skullstrip_bold_wf/n4_correct/sub-travel2_ses-NS_task-rest_run-01_bold_average_corrected.nii.gz, 1, 32, Random, 0.5 \] \
    --convergence \[ 20, 1e-08, 3 \] \
    --smoothing-sigmas 2.0mm \
    --shrink-factors 1 \
    --use-histogram-matching 1 \
    --masks \[ /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/fmap_preproc_wf/wf_auto_00000/brainextraction_wf/masker/clipped_mask.nii.gz, /Users/psadil/Desktop/NStravel2/work2/fmriprep_24_0_wf/sub_travel2_wf/bold_ses_NS_task_rest_run_01_wf/bold_fit_wf/enhance_and_skullstrip_bold_wf/combine_masks/sub-travel2_ses-NS_task-rest_run-01_bold_average_corrected_brain_mask_maths.nii.gz \] \
    --winsorize-image-intensities \[ 0.001, 0.999 \]  \
    --write-composite-transform 0

Running this command (and converting the result with ConcatenateXFMs) several times produces pretty variable transformation matrices. Here are 6

==> out1_fwd.tfm <==
#Insight Transform File V1.0
#Transform 0
Transform: AffineTransform_float_3_3
Parameters: 0.999672 -0.0016924 -0.0255665 0.00277344 0.999101 0.0423075 0.0254719 -0.0423645 0.998777 1.10469 -2.04965 0.734481
FixedParameters: 0 0 0
==> out2_fwd.tfm <==
#Insight Transform File V1.0
#Transform 0
Transform: AffineTransform_float_3_3
Parameters: 0.999889 0.00556549 -0.0138201 -0.00529245 0.999792 0.0197156 0.013927 -0.0196402 0.99971 0.274105 -1.77395 -0.445344
FixedParameters: 0 0 0
==> out3_fwd.tfm <==
#Insight Transform File V1.0
#Transform 0
Transform: AffineTransform_float_3_3
Parameters: 0.999479 -0.00549332 -0.0317923 0.00689586 0.999 0.0441753 0.0315179 -0.0443716 0.998518 1.41946 -2.57649 1.31726
FixedParameters: 0 0 0
==> out4_fwd.tfm <==
#Insight Transform File V1.0
#Transform 0
Transform: AffineTransform_float_3_3
Parameters: 0.987015 -0.0158937 -0.15984 0.037051 0.990786 0.130272 0.156297 -0.134503 0.978509 -12.1044 14.0549 -4.84802
FixedParameters: 0 0 0
==> out5_fwd.tfm <==
#Insight Transform File V1.0
#Transform 0
Transform: AffineTransform_float_3_3
Parameters: 0.96765 0.0557279 -0.246066 -0.0187037 0.988462 0.15031 0.251604 -0.140845 0.957527 -4.86533 4.64465 -8.38042
FixedParameters: 0 0 0
==> out6_fwd.tfm <==
#Insight Transform File V1.0
#Transform 0
Transform: AffineTransform_float_3_3
Parameters: 0.999198 -0.00150606 -0.0400227 0.00331347 0.998976 0.045132 0.0399137 -0.0452284 0.998179 2.26726 -2.61363 1.85205
FixedParameters: 0 0 0

This is discouraging because the images start out well-aligned and the masks look fine.

boldref

fmapref

masks

So, the issue is at least easy to detect automatically (large movement within the transformation matrices indicates some failure). And it seems like I could make this step at least reproducible by, e.g., setting the environment variable ANTS_RANDOM_SEED. But, are there suggestions for making this more robust?

Also, FWIW, the files can be shared