Differences between whole-brain and masked ALFF values

Hi,

Summary of what happened:

Large differences between ALFF values in the hippocampus obtained from a CIFTI output (hippocampal ALFF values still in volumetric space) and the ones obtained from the NIFTI whole brain output.

Setup:

  • Data: ABCD dataset, downloaded with Datalad.
  • Container: Singularity container for XCP-D.
  • Version: XCP-D v0.10.0rc3

Description of the problem

A colleague ran the XCP-D pipeline with the CIFTI output. As we decided to share the resources, I extracted the volumetric hippocampal ALFF values from

*space-fsLR_den-91k_stat-alff_boldmap.dscalar.nii

with the command

wb_command -cifti-separate sub-XXX_ses-baselineYear1Arm1_task-rest_run-02_space-fsLR_den-91k_stat-alff_boldmap.dscalar.nii COLUMN -volume HIPPOCAMPUS_LEFT hippocampus_L.nii.gz

However, due to misalignment with the current hippocampal surface that I have (after adjusting for resolution and space), we decided to re-run the pipeline but this time to get the volumetric ALFF values for the whole brain. To our surprise, the ALFF values (in blue in Fig.1) of the hippocampus were much lower than the ones obtained with the hippocampal mask (in orange).


Fig. 1

We were wondering if the calculations may change depending on the output format, especially when considering allocortical and subcortical structures. The hippocampus mask extracted from the CIFTI file seems to be in the right place when plotted on the whole brain ALFF NIFTI file.

Excerpt of my colleague’s code:

# Apply transformation if output mask does not already exist
            if [ ! -f "$output_mask" ]; then
                echo "Applying transformation..."
                antsApplyTransforms -d 3 -i "$mask_file" -r "$tpl_file" -n NearestNeighbor \
                    -t "$transform_file" -o "$output_mask" || {
                    echo "Error applying transformation for $mask_file"
                    missing_files_errors+=("$sub: Error applying transformation for $mask_file")
                    continue
                }
                echo "Transformation applied successfully!"
            else
                echo "Mask transformation output already exists for $mask_file"
            fi
            
            # Check if required BOLD data exists in fsLR space
            fsLR_bold_files=$(find "$subject_dir/ses-baselineYear1Arm1/func/" -name "*_space-fsLR_den-91k_bold.dtseries.nii" 2>/dev/null)
            if [ -z "$fsLR_bold_files" ]; then
                echo "No BOLD data found in fsLR space for $sub. Skipping XCP-D processing."
                missing_files_errors+=("$sub: No BOLD data in fsLR space")
            else
            	# Run XCP-D post-processing pipeline
            	echo "Running XCP-D pipeline"
            
            	singularity run \
            	-B /data/ABCD:/data/ABCD \
            	--cleanenv /data/xcp_d-0.10.1.sif \
            	/data/ABCD/ABCD_fMRIprep/fmriprep \
            	/data/ABCD/XCP-D_output \
            	participant \
            	--mode 'none' \
            	--participant-label "${sub#sub-}" \
            	--bids-filter-file /data/ABCD/bids_filter_file.json \
            	--nprocs 36 \
            	--input-type 'fmriprep' \
            	--file-format 'cifti' \
            	--dummy-scans 'auto' \
            	--despike 'y' \
            	--nuisance-regressors /data/ABCD/custom_confounds_24P_csf_wm.yaml \
            	--fd-thresh 0.3 \
            	--output-type 'censored' \
            	--combine-runs 'n' \
            	--smoothing 6 \
            	--motion-filter-type 'none' \
            	--head-radius 50 \
            	--lower-bpf 0.01 \
            	--upper-bpf 0.08 \
            	--bpf-order 2 \
            	--min-time 240 \
            	--atlases '4S456Parcels' \
            	--min-coverage 0.5 \
            	--create-matrices 240 all \
            	--work-dir /data/ABCD/work \
            	--warp-surfaces-native2std 'n' \
            	--abcc-qc 'n' \
            	--linc-qc 'y' \

where
mask_file = {sub}_ses-baselineYear1Arm1"*desc-brain_mask.nii.gz;
transform_file = {sub}_ses-baselineYear1Arm1"*from-T1w_to-MNI152NLin6Asym_mode-image_xfm.h5
output_mask = {sub}_ses-baselineYear1Arm1_space-MNI152NLin6Asym_desc-brain_mask.nii.gz
tpl_file = /data/tpl-MNI152NLin6Asym/tpl-MNI152NLin6Asym_res-01_T1w.nii.gz

Excerpt of my code with alterations to return whole-brain volumetric ALFF values:

output_mask="${sub}_ses-baselineYear1Arm1_space-MNI152NLin6Asym_desc-brain_mask.nii.gz"
            tpl_file="/data/pt_02983/data/ALFF/test/test2/tpl-MNI152NLin6Asym/tpl-MNI152NLin6Asym_res-02_T1w.nii.gz"

            # pull ants container if needed
            if [ ! -f /data/software/containers/ants_2.5.3.sif ]; then
                echo "Pulling ANTs container..."
                mkdir -p /data/software/containers
                singularity pull /data/software/containers/ants_2.5.3.sif docker://antsx/ants:2.5.3
            fi

                echo "Running antsApplyTransforms for anatomical brain mask..."
                singularity exec \
                    --cleanenv \
                    -B /data:/data \
                    /data/software/containers/ants_2.5.3.sif \
                    antsApplyTransforms -d 3 -v 1 \
                    -i "$mask_file" \
                    -r "$tpl_file" \
                    -n NearestNeighbor \
                    -t "$transform_file" \
                    -o "$output_mask" || {
                        echo "Error applying transformation for $mask_file"
                        continue
                    }
                echo "Transformation applied successfully!"

            # now handle the functional files
            cd ../func/ || {
                echo "Missing functional directory for $sub"
                missing_files_errors+=("$sub: Missing functional directory")
                continue
            }

            for bold_file in *task-rest_run-*_space-MNI152NLin6Asym_desc-smoothAROMAnonaggr_bold.nii.gz; do
                bold_file=$(echo "$bold_file" | sed 's/"//g;s/@$//')

                if [ -f "$bold_file" ]; then
                    symlink_file="${bold_file/_desc-smoothAROMAnonaggr/_desc-preproc}"
                    if [ ! -f "$symlink_file" ]; then
                        ln -s "$bold_file" "$symlink_file"
                    fi

                    boldref_file="${bold_file/_desc-smoothAROMAnonaggr_bold/_boldref}"
                    if [ ! -f "$boldref_file" ]; then
                        fslroi "$bold_file" "$boldref_file" 0 1
                    fi

                    # extract run id
                    run=$(echo "$bold_file" | grep -o "run-[0-9][0-9]")

                    # define run-specific anatomical mask symlink name
                    anatomical_mask_run="${sub}_ses-baselineYear1Arm1_task-rest_${run}_space-MNI152NLin6Asym_desc-brain_mask.nii.gz"

                    if [ ! -f "$anatomical_mask_run" ]; then
                        ln -s "$(realpath ../anat/${output_mask})" "$anatomical_mask_run"
                        echo "Created run-specific mask: $anatomical_mask_run"
                    fi
                fi
            done

            # Run XCP-D post-processing pipeline
            echo "Running XCP-D pipeline"
            
            singularity run \
            -B /data/:/data \
            --cleanenv /data/xcp_d-0.10.0rc3.simg \
            /data/ABCD/ABCD_fMRIprep/fmriprep \
            /data/ALFF/test/test2/XCP-D_output/ \
            participant \
            --mode 'none' \
            --participant-label "${sub#sub-}" \
            --bids-filter-file /data/ALFF/test/test2/bids_filter_file.json \
            --nprocs 36 \
            --input-type 'fmriprep' \
            --file-format 'nifti' \
            --dummy-scans 'auto' \
            --despike 'y' \
            --nuisance-regressors /data/ALFF/test/test2/custom_confounds_24P_csf_wm.yaml \
            --fd-thresh 0.3 \
            --output-type 'censored' \
            --combine-runs 'n' \
            --smoothing 6 \
            --motion-filter-type 'none' \
            --head-radius 50 \
            --lower-bpf 0.01 \
            --upper-bpf 0.08 \
            --bpf-order 2 \
            --min-time 240 \
            --skip-parcellation \
            --create-matrices 240 all \
            --work-dir /data/ALFF/test/test2/work \
            --warp-surfaces-native2std 'n' \
            --abcc-qc 'n' \
            --linc-qc 'y' \

Thank you very much in advance! (:

Best,
Mylla

There should be no differences in how ALFF is calculated for CIFTIs and NIfTIs. I will try to reproduce this in my own data in the next few days, but I think something upstream of the ALFF calculation must be the cause.

1 Like