-polort value can't be over

AFNI version info (afni -ver):
Precompiled binary linux_ubuntu_16_64: Feb 5 2024 (Version AFNI_24.0.05 'Caracalla')

Dear AFNI experts,

I'm trying to generally follow afni_proc.py example 11 to pre-process some stroke patient data for eventual functional connectivity analysis. A couple of them have gone fine, but for one subject I get this error:

-- detrend -polort 1249, new eset = ts.1.det.r01.nii.gz
++ 3dTproject: AFNI version=AFNI_24.0.05 (Feb  5 2024) [64-bit]
++ Authored by: Cox the Algebraic (Linear)
** FATAL ERROR: -polort value can't be over 20 :-(

When I look at the tcsh script that afni_proc.py generated, I see this line:

# QC: look for columns of high variance
find_variance_lines.tcsh -polort 1249 -nerode 2 \
       -rdir vlines.pb00.tcat                   \
       pb00.$subj.r*.tcat+orig.HEAD |& tee out.vlines.pb00.tcat.txt

I'm pasting my afni_proc.py command below, in hopes that someone can help resolve my confusion on this issue.

afni_proc.py                                                         \
    -subj_id                  $subj                                  \
    -copy_anat                anat_warped/anatSS.${subj}.nii             \
    -blocks                   despike tshift align tlrc volreg blur mask          \
                              scale regress                          \
-anat_has_skull no \
-anat_follower anat_w_skull anat $subj/SUMA/${subj}_SurfVol.nii \
-anat_follower_ROI aaseg anat $subj/SUMA/aparc.a2009s+aseg.nii.gz \
-anat_follower_ROI aeseg epi $subj/SUMA/aparc.a2009s+aseg.nii.gz \
-anat_follower_ROI FSvent epi $subj/SUMA/fs_ap_latvent.nii.gz \
-anat_follower_ROI FSWe epi $subj/SUMA/fs_ap_wm.nii.gz \
-anat_follower_erode FSvent FSWe \
-dsets run1_CM.nii.gz run2_CM.nii.gz run3_CM.nii.gz run4_CM.nii.gz \
-tcat_remove_first_trs 2 \
-align_unifize_epi local \
-align_opts_aea -epi_strip 3dSkullStrip \
		-skullstrip_opts -blur_fwhm 3 -push_to_edge \
		-cost crM \
		-giant_move  \
	        -check_flip  \
-tlrc_base /usr/local/afni/bin/MNI152_2009_template_SSW.nii.gz \
-tlrc_NL_warp \
-tlrc_NL_warped_dsets anat_warped/anatQQ.$subj.nii anat_warped/anatQQ.$subj.aff12.1D anat_warped/anatQQ.${subj}_WARP.nii \
-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.7 \
-regress_censor_outliers 0.3 \
-regress_apply_mot_types demean deriv \
-regress_est_blur_epits \
-regress_est_blur_errts \
-scr_overwrite \
-html_review_style pythonic \
-execute

Howdy-

Thanks for posting the AP command.

That suggests that there are a loooooot of time points there (or, at least, a very long time interval across the start/finish of the concatenated set of runs)? The polort regressors are included to capture baseline drift and slow fluctuation. The default polort value, described in the afni_proc.py, comes from this rule (where run_length is total duration in seconds):

-regress_polort DEGREE  : specify the polynomial degree of baseline

        e.g. -regress_polort 2
        default: 1 + floor(run_length / 150.0)

But, as noted there, you can specify your own number with the -regress_polort .. option. I think you probably don't want more than 7-8 degree, because they can get wonky/unstable. So, you could specify a low polort and to still capture more baseline drive invoke a high-pass filter. This is suggested in the AP help under the same option:

  * It is also possible to use a high-pass filter to model baseline
    drift (using sinusoids).  Since sinusoids do not model quadratic
    drift well, one could consider using both, as in:

        -regress_polort 2         \
        -regress_bandpass 0.01 1

    Here, the sinusoids allow every frequency from 0.01 on up to pass
    (assuming the Nyquist frequency is <= 1), modeling the lower
    frequencies as regressors of no interest, along with 3 terms for
    polort 2.

Does that seem reasonable?

And for here is that same AP command with options vertically aligned, in case that is helpful:

afni_proc.py                                                                 \
    -subj_id                  $subj                                          \
    -copy_anat                anat_warped/anatSS.${subj}.nii                 \
    -blocks                   despike tshift align tlrc volreg blur mask     \
                              scale regress                                  \
    -anat_has_skull           no                                             \
    -anat_follower            anat_w_skull anat                              \
                              $subj/SUMA/${subj}_SurfVol.nii                 \
    -anat_follower_ROI        aaseg anat $subj/SUMA/aparc.a2009s+aseg.nii.gz \
    -anat_follower_ROI        aeseg epi $subj/SUMA/aparc.a2009s+aseg.nii.gz  \
    -anat_follower_ROI        FSvent epi $subj/SUMA/fs_ap_latvent.nii.gz     \
    -anat_follower_ROI        FSWe epi $subj/SUMA/fs_ap_wm.nii.gz            \
    -anat_follower_erode      FSvent FSWe                                    \
    -dsets                    run1_CM.nii.gz run2_CM.nii.gz run3_CM.nii.gz   \
                              run4_CM.nii.gz                                 \
    -tcat_remove_first_trs    2                                              \
    -align_unifize_epi        local                                          \
    -align_opts_aea           -epi_strip 3dSkullStrip                        \
                              -skullstrip_opts                               \
                              -blur_fwhm 3                                   \
                              -push_to_edge                                  \
                              -cost crM                                      \
                              -giant_move                                    \
                              -check_flip                                    \
    -tlrc_base                /usr/local/afni/bin/MNI152_2009_template_SSW.nii.gz \
    -tlrc_NL_warp                                                            \
    -tlrc_NL_warped_dsets     anat_warped/anatQQ.$subj.nii                   \
                              anat_warped/anatQQ.$subj.aff12.1D              \
                              anat_warped/anatQQ.${subj}_WARP.nii            \
    -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.7                                            \
    -regress_censor_outliers  0.3                                            \
    -regress_apply_mot_types  demean deriv                                   \
    -regress_est_blur_epits                                                  \
    -regress_est_blur_errts                                                  \
    -scr_overwrite                                                           \
    -html_review_style        pythonic                                       \
    -execute

A couple other comments:

One thing to note, those seem like pretty high -regress_censor_* .. values. We often have -regress_censor_outliers 0.05, meaning a time point that has >=5% of voxels being time series outliers would be censored; a 30% censor limit seems like a pretty high bar. If a brain volume has 20% outliers, for example, that would seem to indicate large motion effects in the time series there. The -regress_censor_motion 0.7 value is also higher than I am used to seeing (e.g., 0.2-0.3 or so), but I know for some subject groups some analyses tend to allow for more motion; it can be a tricky trade-off to make.

Secondly, I see you are loading in ROIs as followers and you mention doing a connectivity analysis. That is great, but if you plan to do an ROI-based analysis, then you likely should not blur your data. We would recommend removing the "blur" block and -blur* .. options. The reason is that blurring smears signal across ROI boundaries, artificially increasing local correlation. Your time series will be averaged within the ROIs, anyways, so they still will get some "blurring" to hopefully enhance SNR. But additional blur during processing would not be advised.

--pt

Thank you, Paul, for that helpful and comprehensive reply!

In light of your explanation, I think I see what happened, though I'm not sure why it happened. Basically, the TR length (time step) for the EPI runs got erroneously written out as 3600s. The actual TR, as correctly specified in the original NIFTI files I got from my collaborator, was 4.4s. The EPI data are oblique relative to the anatomy scan, so I used this command that you helped me out with a couple of years ago to manually set the centers of both types of scans:

set anat_00 = struct.nii
set anat_cm = anat_CM.nii.gz
foreach run (`count -d 1 1 4`)
set rest_00 = ${subj}_run${run}.nii.gz
set rest_cm = run${run}_CM.nii.gz
cp $datadir/BOLD/$subj/$epoch/${rest_00} "${rest_cm}"
3dCM   -set 0 0 0   "${rest_cm}"
end

# anat
cp $datadir/T1/$subj/$epoch/"${anat_00}" "${anat_cm}"
3dCM   -set 0 0 0   "${anat_cm}"

Somehow after doing that, the TR for the functional scans gets changed from 4.4s to 3600s.
I guess I could just run 3drefit or something like that to manually change the TR back to what it should be, but it's curious that this happened in the first place.

Actually, editing this to say that the source file also has the wrong TR. I had a skull stripped and non-skull stripped version. Only the skull stripped version has the right TR. So it's an issue with the source file I was reading from.

Best,
Will

Wow, I'm not sure how that 4.4s -> 3600s came about! If it were 4.4s -> 4400s, then I would guess something that should have been recorded as "ms" got recorded as "s". Hmm, I hope you can find the root of what happened there.

I don't quite understand about the skullstripping---is it the EPI volumes being skullstripped?

--pt

Yes, EPI volumes being skullstripped. It's probably not interesting enough to go into, but briefly these are Arterial Spin Labeling data, where the TRs alternate between a tagging pulse and an EPI readout. My collaborator used some FSL tool to strip out the TRs with ASL tags because they won't be useful for a resting state analysis. Apparently the TR label got messed up somewhere in that process.

Interesting. I guess that certainly is a different set of (pre)preprocessing needs than a standard FMRI dataset.

--pt