retroicor with multiband data

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

Hi all,
I am trying to use retroicor with multiband data. I have BIOPAC photoplethysmography HRV data and respiration data collected at 2KHz, but I am having problems getting afni_proc.py to run. The physiological recording is triggered by the magnet, though we shut it off manually. My multiband sequence (4 echoes) is 305 volumes, but the last three are noise scans for use with nordic.

I keep getting errors like:
ERROR: run 1 ricor NT != dset len (221, 302)
(check -ricor_regs_nfirst/-tcat_remove_first_trs)
** script creation failure for block 'ricor'

Any thoughts on what I might be doing wrong? Do I have to cut the time series for the physiology to match the MRI? If so, how do you suggest I do that given the different temporal resolution of the MRI and physiology? The TR for the images is 2.0 seconds.
Thanks,
Matt

# I am using this RetroTS.py command
RetroTS.py -c sub-2014_REST_HRV.txt -r sub-2014/2014_REST_RESP.txt -n 56 -v 2 -p 2000 -slice_order slicetiming -prefix sub-2014_ses-MRI1_rest_HRV2k.1D.slibase.1D

#The -ricor_regs flag I use in afni_proc.py is:
    -ricor_regs ${subject}_${session}_rest_HRV2k.1D.slibase.1D 

As a PS, I tried a different case (the physio for the case I listed was incomplete), but I get a similar message:
-- multi-echo data: have 4 echoes across 1 run(s)
++ updating polort to 5, from run len 604.0 s
** ERROR: run 1 ricor NT != dset len (314, 302)
(check -ricor_regs_nfirst/-tcat_remove_first_trs)
** script creation failure for block 'ricor'

Hello,

Yes, for RetroTS.py, you usually need to trim the physio data to match the MRI data. You can do that in a number of ways, but the easiest is to take the frequency of the physio, divide by number of TRs and then chop the extras off of your biopac output.

However, you can (and should) try out the new physio_calc.py! It has new fancy features that are explained on this poster.

-Pete

1 Like

Echoing @pmolfese , physio_calc.py is the much improved way to go. It should provide clearer messaging about not having enough physio data for a given FMRI/EPI volume. It also has a lot more QC help (including images) about the peak/trough detection that is central to many of the regressor-generating algorithms.

Note that if physio time series data doesn't cover your full FMRI duration (which hear appears to be 302*TR = 604 s), then you would have to chop your time series down to be able to use the physio data. Note that you can provide your FMRI time series as an input argument to physio_calc.py via -dset_epi DSET, which is the simplest way to let the program get what info it needs about the FMRI data (like TR, number of volumes, etc.).

We will be having some further updates to physio_calc.py coming, many of which are in an existing branch, for controlling the kinds of regressors you can ask for---RETROICOR ones, RVT, RVTRRF, HRCRF, etc. depending on what physio data you have. These will likely merge in sometime after the OHBM conference.

--pt

Hi Paul,
Strangely, I got an error the second time, but not the first time I tried it. I was able to use 3dretroicor (outside of the afni_proc.py framework). If that is ok, I'll just go that way for now.

But the message I got at the afni_proc.py stage was:
** ERROR: ricor nsliregs x nslices != nvec (2, 78, 224)
(0 ricor slices, 78 volume slices, 0 slice 0 labels)

That is odd because there are 56 slices.

Hi, Matthew-

I would definitely recommend the much newer physio_calc.py. It should have much better management of things, better peak/trough detection, QC imaging, and more.

And in either case, you would run physiological regressor estimation prior to afni_proc.py, and then hand the results over for it to use.

What was the physio_calc.py command you ran, and what was the output showing failure or inability to proceed?

--pt

Hi Paul,
The command I used was:

/home/software/abin/physio_calc.py                                           \
    -card_file       2016_REST_CARDtrunc.1D                                  \
    -freq            2000                                                    \
    -dset_epi        sub-2016_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold.nii.gz \
    -do_fix_nan                                                              \
    -extra_fix_list  5000                                                    \
    -out_dir         physio_calc                                             \
    -prefix          physio                                                  \
    -freq            2000                                                    \
    -dset_tr         2                                                       \
    -dset_nslice     56                                                      \

I then feed the resulting "slibase" file linto my afni_proc.py file, specifying the ricor flag in the blocks and feed the slibase file into the -ricor_regs flag. When I ran that command, it failed with the message I sent initially.

I do note that I had to truncate the physio time series at 604 sec (as we'd discussed), but the
final MRI slice time is 602.00000. I assume that is the onset time of the last MRI volume?

In terms of preprocessing, I converted the acq file from Biopac to a text file, extracted the appropriate columns, and truncated them at the appropriate length based on the sampling rate and scan duration.

Thanks,
Matt

Hi Matt,

If it's okay, please run the same afni_proc.py command, but adding "-verb 3" and post the output.

Thanks,

-rick

Hi Rick,
Here's the output. I removed the subject number, but the rest is unchanged.
Thanks,
Matt

------------------------------------------------------------------------------------------------
-- applying input view as +orig
-- template = 'MNI152_2009_template_SSW.nii.gz', exists = 1
-- have APQC atlas APQC_atlas_MNI_2009c_asym.nii.gz
-- will use min outlier volume as motion base
-- including default: -find_var_line_blocks tcat
-- tcat: reps is now 302
-- multi-echo data: have 4 echoes across 1 run(s)
++ updating polort to 5, from run len 604.0 s
** ERROR: ricor nsliregs x nslices != nvec (9, 78, 728)
   (0 ricor slices, 78 volume slices, 0 slice 0 labels)

** script creation failure for block 'ricor'
----------------------------------------------------------------------
** failed command (create_script):

  afni_proc.py -subj_id sub-xxxx_ses-MRI1 -blocks despike ricor align tlrc                                                                                                 \
      volreg mask combine blur scale regress -radial_correlate_blocks tcat                                                                                                 \
      volreg -blip_forward_dset                                                                                                                                            \
      '/home/hoptman/neurodesktop-storage/TSIB/subjects/sub-xxxx/AP_prescan_rest_009/TSIB_xxxx_AP_prescan_rest_9_ph_deob.nii.gz[0]'                                        \
      -blip_reverse_dset                                                                                                                                                   \
      '/home/hoptman/neurodesktop-storage/TSIB/subjects/sub-xxxx/PA_prescan_rest_012/TSIB_xxxx_PA_prescan_rest_12_ph_deob.nii.gz[0]'                                       \
      -copy_anat                                                                                                                                                           \
      /home/hoptman/neurodesktop-storage/TSIB/MultiEcho/TSIB/derivatives/sub-xxxx/ses-MRI1/anat/sub-xxxx_ses-MRI1_acq-MEMPRAGEnoRemeas4ep21mmisoRMS_T1w.nii.gz             \
      -anat_has_skull yes -dsets_me_run                                                                                                                                    \
      /home/hoptman/neurodesktop-storage/TSIB/MultiEcho/TSIB/derivatives/sub-xxxx/ses-MRI1/func/sub-xxxx_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold_deob.nii.gz \
      /home/hoptman/neurodesktop-storage/TSIB/MultiEcho/TSIB/derivatives/sub-xxxx/ses-MRI1/func/sub-xxxx_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold_deob.nii.gz \
      /home/hoptman/neurodesktop-storage/TSIB/MultiEcho/TSIB/derivatives/sub-xxxx/ses-MRI1/func/sub-xxxx_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold_deob.nii.gz \
      /home/hoptman/neurodesktop-storage/TSIB/MultiEcho/TSIB/derivatives/sub-xxxx/ses-MRI1/func/sub-xxxx_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold_deob.nii.gz \
      -echo_times 12.8 32.87 52.94 73.01 -reg_echo 2 -align_unifize_epi local                                                                                              \
      -volreg_align_e2a -volreg_tlrc_warp -align_opts_aea -cost lpc+ZZ                                                                                                     \
      -giant_move -check_flip -volreg_align_to MIN_OUTLIER -tlrc_base                                                                                                      \
      MNI152_2009_template_SSW.nii.gz -tlrc_NL_warp -anat_follower_ROI FSvent                                                                                              \
      epi                                                                                                                                                                  \
      /home/hoptman/neurodesktop-storage//TSIB/MultiEcho/TSIB/derivatives/fmriprep_out/sourcedata/freesurfer/sub-xxxx/SUMA/fs_ap_latvent.nii.gz                            \
      -anat_follower_ROI FSWe epi                                                                                                                                          \
      /home/hoptman/neurodesktop-storage//TSIB/MultiEcho/TSIB/derivatives/fmriprep_out/sourcedata/freesurfer/sub-xxxx/SUMA/fs_ap_wm.nii.gz                                 \
      -anat_follower_ROI aaseg anat                                                                                                                                        \
      /home/hoptman/neurodesktop-storage//TSIB/MultiEcho/TSIB/derivatives/fmriprep_out/sourcedata/freesurfer/sub-xxxx/SUMA/aparc+aseg_REN_all.nii.gz                       \
      -anat_follower_ROI aseg epi                                                                                                                                          \
      /home/hoptman/neurodesktop-storage//TSIB/MultiEcho/TSIB/derivatives/fmriprep_out/sourcedata/freesurfer/sub-xxxx/SUMA/aparc+aseg_REN_all.nii.gz                       \
      -anat_follower_erode FSvent FSWe -combine_method OC                                                                                                                  \
      -combine_opts_tedana --tedpca aic -volreg_compute_tsnr yes                                                                                                           \
      -mask_epi_anat yes -blur_size 4 -blur_in_mask yes -blip_forward_dset                                                                                                 \
      '/home/hoptman/neurodesktop/storage/TSIB/sub-xxxx/AP_prescan_rest_009/TSIB_xxxx_AP_prescan_9_ph_deob.nii.gz[0]'                                                      \
      -blip_reverse_dset                                                                                                                                                   \
      '/home/hoptman/neurodesktop-storage/TSIB/sub-xxxx/PA_prescan_rest_012/TSIB_xxxx_PA_prescan_rest_12_ph_deob.nii.gz[0]'                                                \
      -regress_3dD_stop -blur_in_mask yes -ricor_regs                                                                                                                      \
      /home/hoptman/neurodesktop-storage/TSIB/MultiEcho/TSIB/derivatives/sub-xxxx/ses-MRI1/func/physio_calc2/physio_slibase.1D                                             \
      -regress_3dD_stop -regress_reml_exec -regress_compute_fitts                                                                                                          \
      -regress_est_blur_epits -regress_est_blur_errts -regress_anaticor_fast                                                                                               \
      -regress_opts_3dD -jobs 8 -regress_motion_per_run                                                                                                                    \
      -regress_censor_outliers 0.05 -regress_apply_mot_types demean deriv                                                                                                  \
      -regress_anaticor_label FSWe -regress_ROI_PC FSvent 3                                                                                                                \
      -regress_ROI_PC_per_run FSvent -regress_run_clustsim no                                                                                                              \
      -html_review_style pythonic -script ./17.sub-xxxx_ses-MRI1_rest
----------------------------------------------------------------------

Hi Matt,
I'm not sure if the -verb 3 option made it into the command, but either way, it is possible that there are header labels that are not quite as expected.
Would you mind posting the first ~30 lines from the output of:

1d_tool.py -infile physio_slibase.1D -show_group_labels

Thanks,
-rick

Hi, Matthew-

Thanks for posting the AP command. I have a few comments on the options there.

I think you might have a small bug in the file paths. Most paths in your command contain something like:

/home/hoptman/neurodesktop-storage/TSIB

... but your blip-forward dataset has:

/home/hoptman/neurodesktop/storage/TSIB

Note the "-" after neurodesktop in the first case, and a "/" after it in the second.

Note you also seem to include -blip_forward_dset .. and -blip_reverse_dset .. twice. One of those has the buggy path.

You also have -blur_in_mask yes twice, as well as -regress_3dD_stop twice.

It also appears like the same FMRI dataset is input 4 times after -dsets_me_run:

/home/hoptman/neurodesktop-storage/TSIB/MultiEcho/TSIB/derivatives/sub-xxxx/ses-MRI1/func/sub-xxxx_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold_deob.nii.gz

I assume the number after "echo-" should change each time?

Also, we typically recommend running sswarper2 prior to afni_proc.py, for both nonlinear alignment and anatomical skullstripping. Then the results are passed to afni_proc.py. This saves time during any re-runs, and the skullstripping tends to be better than what 3dSkullStrip alone will do (which is what AP will use), as well as better anatomical-to-template alignment. Your command could be adjusted to do that.

Because the command is so large and file paths are long, I did run it through a script to vertically align opts, and then also tried to pull out common file path pieces to make it easier to scan. This is the result, with reductions of duplicate options listed above and a guess at some file path correction, as noted above (I guessed at replacing the echo-? number, too in the ME-FMRI dset inputs). I also bunched options by processing block---it isn't necessary, but it was a bit easier for me to read. Please check this for correctness.

#!/bin/tcsh

set subj = sub-xxxx
set p1 = /home/hoptman/neurodesktop-storage/TSIB
set p2 = ${p1}/MultiEcho/TSIB/derivatives
set p3 = ${p2}/${subj}/ses-MRI1
set p4 = ${p2}/fmriprep_out/sourcedata/freesurfer

afni_proc.py                                                                 \
    -subj_id                  ${subj}_ses-MRI1                              \
    -blocks                   despike ricor align tlrc volreg mask combine   \
                              blur scale regress                             \
    -radial_correlate_blocks  tcat volreg                                    \
    -blip_forward_dset        "${p1}/subjects/${subj}/AP_prescan_rest_009/TSIB_xxxx_AP_prescan_rest_9_ph_deob.nii.gz[0]" \
    -blip_reverse_dset        "${p1}/subjects/${subj}/PA_prescan_rest_012/TSIB_xxxx_PA_prescan_rest_12_ph_deob.nii.gz[0]" \
    -copy_anat                ${p3}/anat/${subj}_ses-MRI1_acq-MEMPRAGEnoRemeas4ep21mmisoRMS_T1w.nii.gz \
    -anat_has_skull           yes                                            \
    -dsets_me_run             ${p3}/func/${subj}_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold_deob.nii.gz \
                              ${p3}/func/${subj}_ses-MRI1_task-rest_echo-2_part-mag_nordicNoNoise_bold_deob.nii.gz \
                              ${p3}/func/${subj}_ses-MRI1_task-rest_echo-3_part-mag_nordicNoNoise_bold_deob.nii.gz \
                              ${p3}/func/${subj}_ses-MRI1_task-rest_echo-4_part-mag_nordicNoNoise_bold_deob.nii.gz \
    -echo_times               12.8 32.87 52.94 73.01                         \
    -reg_echo                 2                                              \
    -anat_follower_ROI        FSvent epi                                     \
                              ${p4}/${subj}/SUMA/fs_ap_latvent.nii.gz        \
    -anat_follower_ROI        FSWe epi                                       \
                              ${p4}/${subj}/SUMA/fs_ap_wm.nii.gz             \
    -anat_follower_ROI        aaseg anat                                     \
                              ${p4}/${subj}/SUMA/aparc+aseg_REN_all.nii.gz   \
    -anat_follower_ROI        aseg epi                                       \
                              ${p4}/${subj}/SUMA/aparc+aseg_REN_all.nii.gz   \
    -anat_follower_erode      FSvent FSWe                                    \
    -align_unifize_epi        local                                          \
    -align_opts_aea           -cost lpc+ZZ                                   \
                              -giant_move                                    \
                              -check_flip                                    \
    -volreg_align_e2a                                                        \
    -volreg_tlrc_warp                                                        \
    -volreg_align_to          MIN_OUTLIER                                    \
    -volreg_compute_tsnr      yes                                            \
    -tlrc_base                MNI152_2009_template_SSW.nii.gz                \
    -tlrc_NL_warp                                                            \
    -ricor_regs               ${p3}/func/physio_calc2/physio_slibase.1D      \
    -combine_method           OC                                             \
    -combine_opts_tedana      --tedpca aic                                   \
    -mask_epi_anat            yes                                            \
    -blur_size                4                                              \
    -blur_in_mask             yes                                            \
    -regress_3dD_stop                                                        \
    -regress_reml_exec                                                       \
    -regress_compute_fitts                                                   \
    -regress_est_blur_epits                                                  \
    -regress_est_blur_errts                                                  \
    -regress_anaticor_fast                                                   \
    -regress_opts_3dD         -jobs 8                                        \
    -regress_motion_per_run                                                  \
    -regress_censor_outliers  0.05                                           \
    -regress_apply_mot_types  demean deriv                                   \
    -regress_anaticor_label   FSWe                                           \
    -regress_ROI_PC           FSvent 3                                       \
    -regress_ROI_PC_per_run   FSvent                                         \
    -regress_run_clustsim     no                                             \
    -html_review_style        pythonic                                       \
    -script                   ./17.${subj}_ses-MRI1_rest

--pt

Here you go:
index 0, label s000.card.c1
index 1, label s000.card.s1
index 2, label s000.card.c2
index 3, label s000.card.s2
index 4, label s001.card.c1
index 5, label s001.card.s1
index 6, label s001.card.c2
index 7, label s001.card.s2
index 8, label s002.card.c1
index 9, label s002.card.s1
index 10, label s002.card.c2
index 11, label s002.card.s2
index 12, label s003.card.c1
index 13, label s003.card.s1
index 14, label s003.card.c2
index 15, label s003.card.s2
index 16, label s004.card.c1
index 17, label s004.card.s1
index 18, label s004.card.c2
index 19, label s004.card.s2
index 20, label s005.card.c1
index 21, label s005.card.s1
index 22, label s005.card.c2
index 23, label s005.card.s2
index 24, label s006.card.c1
index 25, label s006.card.s1
index 26, label s006.card.c2
index 27, label s006.card.s2
index 28, label s007.card.c1

Thanks,
Matt

Yes, these labels are a little different from what afni_proc.py expects, I believe. For now, why don't you just 1dcat the file to remove the header.

1dcat physio_slibase.1D > physio_slibase_nohead.1D

and use the 'nohead' version with afni_proc.py (so it won't know enough to complain). We will ponder those labels later.
-rick

Hi Paul,
Thanks for the corrections. I'll check your version against what I want the run to do. And yes, the echos should have incremented, though I don't think that's what caused the error, at least.
Best wishes,
Matt

Hi Rick,
I noticed that I had not included the -resp flag in the command I showed above. However, the command I used in fact had the resp flag, sorry. As a result, the labels from the 1d_tool.py on physio_slibase.1D look different from those above. Nevertheless, I still get the same error even when I use the "nohead" version and Paul's tidied script. So maybe it's not the labels?

What should the labels look like? On this "correct" file, they look like:
index 0, label s000.rvt00
index 1, label s000.rvt01
index 2, label s000.rvt02
index 3, label s000.rvt03
index 4, label s000.rvt04
index 5, label s000.card.c1
index 6, label s000.card.s1
index 7, label s000.card.c2
index 8, label s000.card.s2
index 9, label s000.resp.c1
index 10, label s000.resp.s1
index 11, label s000.resp.c2
index 12, label s000.resp.s2
index 13, label s001.rvt00
index 14, label s001.rvt01
index 15, label s001.rvt02
index 16, label s001.rvt03
index 17, label s001.rvt04
index 18, label s001.card.c1
index 19, label s001.card.s1
index 20, label s001.card.c2
index 21, label s001.card.s2
index 22, label s001.resp.c1
index 23, label s001.resp.s1
index 24, label s001.resp.c2
index 25, label s001.resp.s2
index 26, label s002.rvt00
index 27, label s002.rvt01
index 28, label s002.rvt02
index 29, label s002.rvt03

Thanks,
Matt

Oh wait, maybe this has to do with deoblique of the EPI. What is the output from

3dinfo -n4 ${subj}_ses-MRI1_task-rest_echo-1_part-mag_nordicNoNoise_bold_deob.nii.gz

-rick

However, when I use the non-deobliqued images, I get an error at the blip step:
** error: reverse blip obliquity (0) does not match EPI (1)
** invalid block : blip

I thought this had posted but the output of the 3dinfo result was:
90 102 78 302

Many of us are out of town now, so we are slow.

Given that there are 78 slices at the original resolution, that is what should be in the slibase file. It should also match the reverse blip data. Is that the case?

-rick

Hi Rick,
So, the deobliqued reverse blip matches the 78 slices of the forward blip scan, but the original scans had 56 slices, whereas the deobliqued ones have 78. Maybe this is a problem?
Thanks,
Matt