afni_proc.py -dxyz changed

Dear AFNI experts.

While checking AFNI 3dinfo, I noticed that in pb04, volume registration data, the voxel appears to have a size of 2.5mm iso-voxel.
When the initial 3 T MRI was acquired, the voxel size setting was 2.7mm iso-voxel (SIEMENS MAGNETOM Prisma).
We did not find the above issue at 2.0 mm iso-voxel, but we found the same issue at 2.7 mm iso-voxel.
I have attached the preprocessing code I used, can you tell me what the problem is?

Thank you for your kind advice,
Yonghyun

AFNI version info (afni -ver): Precompiled binary linux_ubuntu_16_64: Apr 18 2023 (Version AFNI_23.1.01 'Publius Helvius Pertinax')

#!/bin/zsh

## ======================================= ##

## $# = the number of arguments
while (( $# )); do
	key="$1"
	case $key in
##		pattern)
##			sentence
##		;;
		-s | --subject)
			subj="$2"
		;;
	esac
	shift ##takes one argument
done

## ======================================= ##

dir_root="/mnt/ext2/GA/fmri_data"
dir_raw="$dir_root/raw_data/$subj"
# dir_mask="$dir_root/masks"

## ======================================= ##

## I/O path, same as above, following earlier steps
dir_FreeSurfer="/mnt/ext4/GA/fmri_data/FreeSurfer"
if [[ ! -d $dir_FreeSurfer ]]; then
	mkdir -p -m 755 $dir_FreeSurfer
fi

if [[ ! -d $dir_FreeSurfer/$subj ]]; then
	source /usr/local/freesurfer/7.2.0/SetUpFreeSurfer.sh
    export SUBJECTS_DIR=${dir_FreeSurfer}

	## FS function
	recon-all								\
		-sid		$subj					\
		-sd			$dir_FreeSurfer			\
		-i			$dir_raw/T1.$subj.nii	\
		-all								\
	
	## AFNI-SUMA function: convert FS output
	@SUMA_Make_Spec_FS						\
		-NIFTI								\
		-fspath		$dir_FreeSurfer/$subj	\
		-sid		$subj

	3dQwarp -allineate -blur 0 3 										\
		-base "/usr/local/afni/abin/MNI152_2009_template_SSW.nii.gz"	\
		-source "$dir_FreeSurfer/$subj/SUMA/brain.nii.gz" 				\
		-prefix "$dir_FreeSurfer/$subj/SUMA/brain_qw.nii"
fi

## ======================================= ##
 
dir_output="/mnt/ext6/GA/fmri_data/preproc_data/$subj"

dir_script="/mnt/ext2/GA/scripts/afni_proc.py"
if [ ! -d $dir_script ]; then
	mkdir -p -m 755 $dir_script
fi

dsets=(`find $dir_raw -type f -name "func.r??.$subj.nii" | sort -t ' ' -k 1`)

cd $dir_script
afni_proc.py\
	-subj_id					$subj	\
	-out_dir					$dir_output	\
	-blocks						despike tshift align tlrc volreg blur mask scale regress	\
	-radial_correlate_blocks	tcat volreg	\
	-copy_anat					"$dir_FreeSurfer/$subj/SUMA/brain.nii.gz"		\
	-anat_has_skull				'no'	\
	-anat_follower				anat_w_skull anat "$dir_FreeSurfer/$subj/SUMA/T1.nii.gz"	\
	-anat_follower_ROI			aaseg anat	\
								"$dir_FreeSurfer/$subj/SUMA/aparc.a2009s+aseg_REN_all.nii.gz"	\
	-anat_follower_ROI			aeseg epi	\
								"$dir_FreeSurfer/$subj/SUMA/aparc.a2009s+aseg_REN_all.nii.gz"	\
	-anat_follower_ROI			FSvent epi "$dir_FreeSurfer/$subj/SUMA/fs_ap_latvent.nii.gz"	\
	-anat_follower_ROI			FSWe epi "$dir_FreeSurfer/$subj/SUMA/fs_ap_wm.nii.gz"		\
	-anat_follower_erode		FSvent FSWe	\
	-dsets						$dsets	\
	-tcat_remove_first_trs		0	\
	-blip_forward_dset			$dir_raw/func.r01.$subj.nii'[12]'	\
	-blip_reverse_dset			$dir_raw/dist_PA.$subj.nii			\
	-align_unifize_epi			'yes'	\
	-align_opts_aea				\
	-cost						lpc+ZZ	\
	-giant_move					\
	-resample					'off'	\
	-check_flip					\
	-tlrc_base					MNI152_2009_template_SSW.nii.gz		\
	-tlrc_NL_warp				\
	-volreg_align_to			MIN_OUTLIER	\
	-volreg_align_e2a			\
	-volreg_tlrc_warp			\
	-blur_size					4	\
	-mask_epi_anat				'yes'	\
	-regress_motion_per_run		\
	-regress_ROI_PC				FSvent 3	\
	-regress_ROI_PC_per_run		FSvent		\
	-regress_make_corr_vols		aeseg FSvent\
	-regress_anaticor_fast		\
	-regress_anaticor_label		FSWe\
	-regress_censor_motion		0.4	\
	-regress_censor_outliers	0.05\
	-regress_apply_mot_types	demean deriv
 #	-regress_est_blur_epits		\
 #	-regress_est_blur_errts		\
 #	-html_review_style			pythonic
 #	-tlrc_NL_warped_dsets		"$dir_FreeSurfer/$subj/SUMA/T1qw.nii" 						\
 #								"$dir_FreeSurfer/$subj/SUMA/T1qw_Allin.aff12.1D"			\
 #								"$dir_FreeSurfer/$subj/SUMA/T1qw_WARP.nii"					\

Howdy-

What you are observing is pretty expected with how afni_proc.py will process blocks in the order provided (and your order of blocks looks pretty standard).

Basically, the volreg block data will be on the final output grid for the processing. The final voxels will be isotropic, and if you don't specify any final voxel resolution, they will be slightly rounded up from your input data's minimal edge length. Personally, even if you like the default output voxel size, I feel it is clearest to specify it explicitly, which is done with the option -volreg_warp-dxyz ... The afni_proc.py help description for this option, which also provides the default internal rule for how a final voxel size will be chosen, is:

-volreg_warp_dxyz DXYZ  : grid dimensions for _align_e2a or _tlrc_warp

        e.g. -volreg_warp_dxyz 3.5
        default: min dim truncated to 3 significant bits
                 (see description, below)

    This option allows the user to specify the grid size for output
    datasets from the -volreg_tlrc_warp and -volreg_align_e2a options.
    In either case, the output grid will be isotropic voxels (cubes).

    By default, DXYZ is the minimum input dimension, truncated to
    3 significant bits (for integers, starts affecting them at 9, as
    9 requires 4 bits to represent).

    Some examples:
        ----------------------------  (integer range, so >= 4)
        8.00   ...  9.99   --> 8.0
        4.00   ...  4.99   --> 4.0
        ----------------------------  (3 significant bits)
        2.50   ...  2.99   --> 2.5
        2.00   ...  2.49   --> 2.0
        1.75   ...  1.99   --> 1.75
        1.50   ...  1.74   --> 1.5
        1.25   ...  1.49   --> 1.25
        1.00   ...  1.24   --> 1.0
        0.875  ...  0.99   --> 0.875
        0.75   ...  0.874  --> 0.75
        0.625  ...  0.74   --> 0.625
        0.50   ...  0.624  --> 0.50
        0.4375 ...  0.49   --> 0.4375
        0.375  ...  0.4374 --> 0.375

    One can optionally supply -volreg_warp_master as well.

    See also -volreg_warp_master.

So, in your case, you might include the option explicitly -volreg_warp_dxyz 2.5 or something. In general, the "slightly rounding up" guideline seems pretty useful, and so you might just be explicitly specifying the round-ish number you want, for clarity.

Looking at the table above, I think in the case you mention, the isotropic 2mm input just happened to be staying the same, whereas the 2.7 mm isotropic input was mapped to 2.5.

--pt

Thank you for your kind reply, I think I have clarified the issue.
However, I have one more question. Could the resolution change due to slight rounding compared to the initially set voxels affect the analysis of the fMRI data?

Indeed, that kind of instability is one additional reason to specify the final resolution explicitly. If the input voxel resolution were 1.99999997 mm, then the output would be 1.75 mm, while if the input were 2.0000001 mm then the output would be 2.0 mm. So, specifying what you would prefer adds both clarity and stability against floating point rounding issues.

--pt

All my questions have been answered. Thank you so much!