Pre-Processing Using afni_proc.py: Alignment (-cmass) and Masking (-mask_epi_anat) Issues

AFNI version info (afni -ver): AFNI_25.0.11 'Severus Alexander'

I'm using AFNI for the first time for a group project (assessing false positive rates in fMRI analysis via a comparison of 3dttest++ and -etac analyses on pseudostimulus timings/false tasks), and my group and I severely underestimated just how large the learning curve is for AFNI. We've spent about 20 hours debugging our pre-processing code, and the data still isn't in a place where it's usable. I'm having two main issues, one to do with alignment (-cmass) and masking (-mask_epi_anat) - the main questions are below, following my afni_proc.py pipeline.

Data used: Beijing dataset from the 1000 Functional Connectome Project (resting state data).

Here's the overall code we've created (we tried -giant_move to help with our alignment issues):

afni_proc.py \
-subj_id sub01018 \
-copy_anat sub01018/anat/mprage_skullstripped.nii.gz \
-anat_has_skull no \
-dsets sub01018/func/rest.nii.gz \
-blocks tshift align tlrc volreg mask blur scale \
-tshift_opts_ts -tpattern alt+z \
-align_opts_aea -cost lpa -giant_move -check_flip \
-tlrc_base MNI152_2009_template+tlrc \
-volreg_align_to first \
-volreg_align_e2a \
-volreg_tlrc_warp \
-mask_epi_anat yes \
-blur_size 4.0 \
-html_review_style pythonic

#Execute proc.sub01018 script
tcsh -xef proc.sub01018 2>&1 | tee output.proc.sub01018

The above code produces the following (apologies about the screenshot):

My two main questions:

  1. Alignment:
    I keep getting the warning/message to use -cmass when I run the proc.sub01018 script. However, when I tried adding -cmass to the -align_opts_aea line, I get a script failure error because it's expecting a parameter for -cmass. I then used -cmass+a (as per the 3dAllineate info page, AFNI program: 3dAllineate) and -cmass a, both of which result in a script failure error because it doesn't recognize the "a" after the -cmass command. What's the expected parameter for -cmass? Is it just "yes," similar to the parameter for -mask_epi_anat?
    Note: -giant_move did help alignment a bit, but I'd much rather use centre of mass calculations (this seems like a more flexible option given the next step is to loop the code for the rest of the subjects in the dataset), but it's been frustrating having my script fail whenever I try to use it.

For reference, these are the errors I'm receiving:

-cmass a (-align_opts_aea -cost lpa -cmass a -check_flip)
** ERROR: Unknown and Illegal option '-a' :-( :-( :-(
   Here's hoping these excerpts from '3dAllineate -help' enlighten:
    	'-ashift OR   }= Apply the shift parameters (#1-3) after OR'
    	'-autobox	= Expand the -automask function to enclose a rectangular'
    	'-allcost    	= Compute ALL available cost functionals and print them'
** 3dAllineate failure
** ERROR - script failed

-cmass+a (-align_opts_aea -cost lpa -cmass+a -check_flip)
** error: option -check_flip follows unknown arg #16 (-cmass+a)
** ERROR - script failed

-cmass (-align_opts_aea -cost lpa -cmass -check_flip)
** error: arg #16 (-cmass) requires 1 params, found 0
** ERROR - script failed
  1. Masking:
    The yellow box surrounding the epi data in non-brain regions didn't go away after I added the -mask_epi_anat yes command (which can be seen in the above image). Do I need to add -mask_apply epi in the line following -mask_epi_anat for the mask to work properly? Or is the excess yellow simply user error and my lack of knowledge on how to finesse the threshold overlay values in the AFNI GUI?

Any guidance would be much appreciated!!

Hi-

A useful resource to start with might be the afni_proc.py (AP) paper here. There is also the AFNI Academy channel here. Here are a couple articles about quality control in AFNI, here and here. And of course asking questions here is also useful (hopefully!).

Re. #2 (masking): using the mask block will estimate a mask and create it. You are using the option for it that we would normally add by default (-mask_epi_anat yes). The output mask of interest will be called mask_epi_anat.*+tlrc.HEAD. Importantly, we don't apply the mask to the data, so we can model and see results everywhere. That is important for quality control. Note the yellow there represents small, positive values, and that seems appropriate.

Re. #1 (alignment): if you have a standard EPI and T1w anatomical volume to align, then those have opposite tissue contrasts (ventricles are bright in one, and dark in the other; etc.). Therefore, you need to use a cost function that is appropriate for finding matches under those conditions (alignment considerations are discussed here). Instead of "lpa", we typically start with "lpc" or "lpc+ZZ"---the latter is slower but more robust in the early stages.

Re. alignment to standard space: we normally might run sswarper2 on human data to do both nonlinear alignment to a template (warping) and to skullstrip (ss). That would be run prior to afni_proc.py, and the results handed over for it to use. That way, you don't have to re-run nonlinear alignment within AP itself when rerunning it. This is a change you might consider for making later on, once we get through this initial troubleshooting.

  • Note that at present, your alignment to the template is not nonlinear, so there won't be very close alignment at the end. To have that be present, you would add -tlrc_NL_warp. However, at present that will slow down the processing (as noted above), so let's leave that out at the moment while troubleshooting other parts.

Re. AP warnings: there will likely be some internal program runs with warnings. Many of these are not necessarily bad, which I understand is confusing. If something goes wrong with processing, those might be places to look; some are just minor warnings/placemarkers in case of badness.

To your AP command: This looks like a setup for standard voxelwise analysis (because blurring is present), for resting state or naturalistic data (because no stimulus timing is provided). This is like Ex. 2 in the afni_proc.py paper, above. I compared options with that example set, and have some recommendations:

  • change EPI-anatomical alignment cost function, as discussed above. So, change -align_opts_aea -cost lpa -giant_move -check_flip to -align_opts_aea -cost lpc+ZZ -giant_move -check_flip

  • Something we added a couple years ago to help EPI-anatomical alignment in human data is local "unifizing" of EPI brightness, to not be thrown off by potential EPI inhomogeneity. This generally either has little effect if the data aren't inhomogeneous, or helps quite a lot. So, we consider it useful in all human data processing, to add -align_unifize_epi local.

  • the best way to pick a reference volume within the EPI for both motion correction and EPI-anatomical alignment is to use the "MIN_OUTLIER" keyword. The AP paper discusses this---basically, it is the best way to avoid a possibly motion-contaminated volume, which would be bad. So, change -volreg_align_to first to -volreg_align_to MIN_OUTLIER.

  • Include the "regress" block, so you get the quality control HTML which makes all the difference in checking your data. So, change -blocks tshift align tlrc volreg mask blur scale to -blocks tshift align tlrc volreg mask blur scale regress.

  • with adding hte regress block, it might just be useful to add a few regress-block options to show motion:

    # what we might include for default resting state processing
              -regress_apply_mot_types     demean deriv                        \
              -regress_motion_per_run                                          \
              -regress_censor_motion       0.2                                 \
              -regress_censor_outliers     0.05                                \
              -regress_est_blur_epits                                          \
              -regress_est_blur_errts                                          \
    
  • If you want to add some other QC options, you could add: -volreg_compute_tsnr yes (shows TSNR after volreg step).


So, that would make a possible updated AP command to run to be:

# updated AP command, without nonlinear alignment to template yet

afni_proc.py                                                                 \
    -subj_id                  sub01018                                       \
    -copy_anat                sub01018/anat/mprage_skullstripped.nii.gz      \
    -anat_has_skull           no                                             \
    -dsets                    sub01018/func/rest.nii.gz                      \
    -blocks                   tshift align tlrc volreg mask blur scale       \
                              regress                                        \
    -tshift_opts_ts           -tpattern alt+z                                \
    -align_unifize_epi        local                                          \
    -align_opts_aea           -cost lpc+ZZ                                   \
                              -giant_move                                    \
                              -check_flip                                    \
    -tlrc_base                MNI152_2009_template+tlrc                      \
    -volreg_align_to          MIN_OUTLIER                                    \
    -volreg_align_e2a                                                        \
    -volreg_tlrc_warp                                                        \
    -volreg_compute_tsnr      yes                                            \
    -mask_epi_anat            yes                                            \
    -blur_size                4.0                                            \
    -regress_apply_mot_types  demean deriv                                   \
    -regress_motion_per_run                                                  \
    -regress_censor_motion    0.2                                            \
    -regress_censor_outliers  0.05                                           \
    -regress_est_blur_epits                                                  \
    -regress_est_blur_errts                                                  \
    -html_review_style        pythonic

Please let us know how that sounds.

--pt

Also, I should mention that a good starting point for running AP might be the "simple" wrapper for single echo FMRI: ap_run_simple_rest.tcsh. This will process your data like resting state data and without full nonlinear alignment to a template, but it can get you going with a "vanilla mode" set of options and being able to the APQC HTML, too:

ap_run_simple_rest.tcsh                                                      \
    -subjid    <SUBJ_ID>                                                     \
    -run_proc                                                                \
    -run_ap                                                                  \
    -nt_rm     <SOME_NUMBER_OR_0>                                            \
    -anat     <DSET_ANAT>                                                    \
    -epi       <ONE_OR_MORE_EPI_DSETS>

That processing will actually look a lot like what was set up at the bottom of the previous post, except this one will assume the anatomical has its skull still on so would skullstrip (you could put in a with-skull-on dset here).

--pt

Hi pt,

Thank you so much for the detailed and thorough reply! Given my group and I are teaching ourselves AFNI, it was so helpful to read through what you said - and thank you for the paper links!

I ran the code you suggested in your initial reply. I hadn't included the regress block originally because I misunderstood the function of it (I thought that was for analysis, so I left it out of my pre-processing-only pipeline). Now I know why I didn't get the HMTL QC page!

Here's the entire QC output (sorry it's very long; I don't think you'd need it all, but I figured I'd include it all to be safe):

EPI to anat alignment seems quite off in original space, but the vol alignment seems to have pretty decent overlap between the two. There even seems to be decent overlap between anat and template space (though the cerebellum seems to be missing...?).

Given the alignment seems to be decent, should I still run nonlinear warping to standard space?

Additionally, if my next step is to loop this pre-processing code for the rest of my subjects, would -giant_move be appropriate? Does AP only move the data if it's needed or does it do the move regardless of initial alignment?

Looking forward to learning more!

Howdy-

Thanks for attaching the QC HTML. My TL;DR is that things look good for the processing being run.

  • The initial overlap (end of "vorig" section) might not be perfect---that's fine, as along as EPI-anatomical alignment works.
  • ... and the EPI-anatomical alignment in "ve2a" looks very nice to me---see how the cortical patterns and ventricle boundaries match up.
  • The anatomical-template alignment in "va2t" is fine for now---meaning that nonlinear alignment wasn't selected, so the sulcal-gyral alignment won't be perfect. With the affine alignment used, things look fine. That will essentially be the first pass of alignment before nonlinear refinement in the more complete alignment. So, this is good to see.
  • In "vstat", the resting state seedcorr maps look pretty reasonable for DMN. The visual cortex is surprisingly "light"---i.e., not filled in across the visual cortex---maybe more complete alignment will show a more filled pattern. But there aren't obvious artifacts.
  • In the "mot" section---doesn't look like you have a lot of motion, cool.
  • The TSNR plots and table look pretty reasonable. By looking at the TSNR table, the TSNR images and the "ve2a" images, it looks like you have pretty good cortical coverage. There is signal loss in the frontoinferior (VMPFC) regions and subcortex/temporal lobes, but this is pretty standard in FMRI.

I don't see a missing cerebellum? In which image is that?

I would look to run sswarper2 on the with-skull anatomical prior to afni_proc.py, and hten pass those results along. I am not sure how the anatomical was skullstripped, but I do see some bits of skull still left on. Hopefully sswarper2 would do a more precise job, as well as calculate nonlinear alignment to be used.

Re. giant_move: sure, you can leave it in. We typically do. There is a bit of difference in overlap between EPI and anatomical. It doesn't seem to be sending the data into a poor local minimum.

--pt

Hey there!

I'm glad my assessment of the QC output generally matched yours (as in, generally things look good). In terms of the missing cerebellum, that was the overlay in the anat to template alignment check. The template edges (red overlay) didn't include the cerebellum at 21L, for instance. My assumption is that that's by design...?

I'm running sswarper2 right now on the first subject to see how things look, and it is taking a very long time to process (it's running up to maybe 1.5-2 hrs at this point, and it's still not done yet). I left the cost function as the default (lpa+ZZ), so maybe that's adding processing time - but I didn't think it'd be this long... Once it's done, if the resulting .jpg files show good overlap, I'll try lpa to see if that reduces the processing time.

For reference, here's the sswarper code I'm trying out:
sswarper2
-input sub01018/anat/mprage_anonymized.nii.gz
-base MNI152_2009_template_SSW.nii.gz
-subid sub01018

Is it normal for sswarper to take 2+ hours to run for a single subject? Or is there something I'm missing?

Edit: It just finished!
Alignment looks quite good. Here's the QC_anatQQ.sub01018.jpg image for reference:

Would using lpa (instead of lpa+ZZ) be a good idea to compare processing time and sufficient alignment?

Oh, I see about the cerebellum edges. That is in the template dataset, not the anatomical. i hadn't noticed that. Where did that anatomical come from? (And what is your AFNI version: afni -ver?)

Nonlinear alignment is computationally intensive. It can take a long time. The alignment programs should make use of multiple CPUs, if available. Checking use of multiple CPUs is described here.

... and that alignment and skullstripping looks great, yes!

If the anatomical-template overlap is good to start with, yes, you can try making use of just lpa as default. If things go awry, then you switch over to lpa+ZZ for that subject. The end result should be basically the same--the "+ZZ" basically stabilizes the initial stages.

--pt

My AFNI ver is AFNI_25.0.11 'Severus Alexander'

In the abin folder that was created after installation, I only had MNI152_2009_template.nii.gz and MNI152_2009_template_SSW.nii.gz (when I viewed each in the AFNI GUI, there weren't any distinguishable visual differences between them - both were skullstripped, for instance). I was originally using the NIFTI file in my AP pipeline and didn't seem to have any issues related to that, but then I read that the -tlrc_base command requires the template/standard space to be in +tlrc format, not NIFTI. So, I used @auto_tlrc to create MNI152_2009_template+tlrc based on the MNI152_2009_template.nii.gz file. That's the template I'm using the AP pipeline - I'm no longer sure this is correct, especially since I'm using the SSW version of the MNI template in my sswarper2 code.

Just another quick question: In my sswarper2 code, if my -base is in a different folder than my set working directory, do I need to specify the path to the template file for it to work? And if so, are the results I received incorrect?

Thanks again for all your guidance! I am so incredibly appreciative of it. :)

Hi-

Essentially all volumetric-processing AFNI programs take BRIK/HEAD files or NIFTI files equivalently. NIFTI development and coding was actually led by Bob Cox, who started AFNI.

Indeed, the initial volumes of the MNI152_2009_template.nii.gz and MNI152_2009_template_SSW.nii.gz datasets are identical. The difference is that the latter has several other volumes concatenated to it, for processing with sswarper2 (and the older @SSwarper). The latter's contents are described more in detail here.

I'm not able to find that old MNI152_2009_template+tlrc.* dset. I guess it is just the cortext of the MNI152_2009_template.nii.gz and MNI152_2009_template_SSW.nii.gz ones. I don't think I would use that in processing, but instead use one of the whole brain ones. I think the affine alignment with @auto_tlrc won't be so "wrong" with the first one, because that is a global fit only, but it would be better to use the others for a whole brain fit even then; and when using nonlinear alignment, you would want/need a whole brain dataset to align to.

AFNI has the ability to look in some "known" locations for datasets, and the abin will be one of those. MNI152_2009_template_SSW.nii.gz lives in the abin directory we distribute, so it will be found there even without a path being specified to it. That is fine.

You can also have those datasets always be loaded in the GUI, without needing to copy them around. This is done using AFNI environment variables in your ~/.afnirc settings file, specifically the AFNI_GLOBAL_SESSION and AFNI_ATLAS_PATH env vars.
Please see this AFNI Academy tutorial video.

--pt

That all makes sense. I'll use the NIFTI version instead - running the template through @auto_tlrc was likely not the best idea!

I successfully ran sswarper2 on a subset of my data, but I'm now running into issues using the files created by sswarper2 in the AP pipeline. I created a new topic about that.

Thanks so much, again, for all your help. It's been hugely helpful!

Glad that has been useful---I have now replied in that other thread.

--pt