From 772daf1ef3c336e4bff618c67746a82ea32ecbb6 Mon Sep 17 00:00:00 2001 From: WillForan Date: Thu, 25 Sep 2025 13:37:29 -0400 Subject: [PATCH 1/3] feat(regress): add -custom_regression_prefix --- preproc_functions/nuisance_regression | 151 +++++++++++++++--------- preproc_functions/parse_args | 11 +- preprocessFunctional | 7 +- test/fmripp_parseargs.bats | 9 ++ test/fmripp_remove_autocorr_and_br.bats | 48 ++++++-- 5 files changed, 156 insertions(+), 70 deletions(-) diff --git a/preproc_functions/nuisance_regression b/preproc_functions/nuisance_regression index 2164bcd..85795aa 100644 --- a/preproc_functions/nuisance_regression +++ b/preproc_functions/nuisance_regression @@ -46,7 +46,7 @@ motionderiv() { COMPUTE_NUISANCE_REGRESSORS_GLOBALS=(nuisance_file nuisance_regressors no_warp \ postWarp postDespike postSS \ templateName mprageBet_base ext tr prefix bpLow bpHigh \ - gsr_in_prefix) + gsr_in_prefix custom_regprefix) # give # - a nifti get basis functions to remove autocorrelation @@ -529,6 +529,50 @@ function compute_nuisance_regressors { return 0 } +# look into regression options and build todo string +# A b g (r || custom_prefix) +function regression_todo { + local todo="" + [ $rmautocorr -eq 1 ] && todo="A" + [ $bandpass_filter -eq 1 ] && todo="${todo}b" + [ $gsr_in_prefix -eq 1 ] && todo="${todo}g" + [ $nuisance_regression -eq 1 ] && todo="${todo}${custom_regprefix:-r}" + echo "$todo" +} +function reg_already_done { + local todo="${1:?regression operations by prefix}" + local reg_prefix=${custom_regprefix:-r} + + [[ -f .nuisance_regression_complete && $todo=$reg_prefix ]] && return 0 + [[ -f .bandpass_filter_complete && $todo=b ]] && return 0 + [[ -f .bandpass_filter_complete && .remove_autocorr_complete && $todo=Ab ]] && return 0 + [[ -f .nuisance_regression_complete && -f .bandpass_filter_complete && $todo=b$reg_prefix ]] && return 0 + [[ -f .nuisance_regression_complete && -f .remove_autocorr_complete && $todo=A$reg_prefix ]] && return 0 + [[ -f .nuisance_regression_complete && -f .bandpass_filter_complete && -f .remove_autocorr_complete && $todo=Ab$reg_prefix ]] && return 0 + + # not already done + return 1 +} +function reg_todo_to_desc { + [[ $# -eq 0 || -z $1 ]] && echo "none" && return + + local todo="${1:?$FUNC_NAME first arg is regression operations by prefix/todo. eg. Abgr }" + #bandpass + prewhitening only + if [ "$todo" = "Ab" ]; then + echo "bandpass+prewhite" + #bandpass only + elif [[ "$todo" = "b" ]]; then + echo "bandpass" + # regress only (withour or without 'A'utocorrelation rm'ed (w/reml) + elif [[ $todo =~ "A?${custom_regprefix:-r}" ]]; then + echo "regressonly" + elif [[ "$todo" =~ A?bg?${custom_regprefix:-r} ]]; then + echo "bandpass+regress" + else + echo "none" + fi +} + function nuisance_regression { #handle nuisance regression and/or bandpass filtering @@ -547,77 +591,68 @@ function nuisance_regression { preNRBP="${prefix}${funcFile}${smoothing_suffix}${ext}" - local todo= - [ $rmautocorr -eq 1 ] && todo="${todo}A" - [ $bandpass_filter -eq 1 ] && todo="${todo}b" - [ $gsr_in_prefix -eq 1 ] && todo="${todo}g" - [ $nuisance_regression -eq 1 ] && todo="${todo}r" - + todo=$(regression_todo) # todo is # only: A b r # combined: Ab Abr br # 'A' alone is not allowed, will throw error -- checked by parseargs or preprocessFunctional # gsr_in_prefix (-gsr) must have gs in $nuisance_regressors, check by parseargs + #check whether requisite steps are complete + reg_already_done "$todo" && return 0 + prefix="${todo}${prefix}" postNRBP="${prefix}${funcFile}${smoothing_suffix}${ext}" - #check whether requisite steps are complete - [[ -f .nuisance_regression_complete && $todo=r ]] && return 0 - [[ -f .bandpass_filter_complete && $todo=b ]] && return 0 - [[ -f .bandpass_filter_complete && .remove_autocorr_complete && $todo=Ab ]] && return 0 - [[ -f .nuisance_regression_complete && -f .bandpass_filter_complete && $todo=br ]] && return 0 - [[ -f .nuisance_regression_complete && -f .remove_autocorr_complete && $todo=Ar ]] && return 0 - [[ -f .nuisance_regression_complete && -f .bandpass_filter_complete && -f .remove_autocorr_complete && $todo=Abr ]] && return 0 - if [[ ! -f "${nuisance_file}" && ( $nuisance_regression == 1 || $nuisance_compute == 1 ) ]]; then compute_nuisance_regressors fi #bandpass + prewhitening only - if [ "$todo" = "Ab" ]; then - run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} #function should pick up this circumstance - rel "date > .bandpass_filter_complete" - #bandpass only - elif [[ "$todo" = "b" ]]; then - rel "3dBandpass -input \"$preNRBP\" -mask \"${subjMask}${ext}\" -dt $tr \ - -prefix \"$postNRBP\" $bpLow $bpHigh" - - rel "date > .bandpass_filter_complete" - # regress only - elif [[ "$todo" = "r" || "$todo" = "Ar" ]]; then - #default to 3dREMLfit here - if [ $arma_nuisance_regression -eq 0 ]; then - rel "3dDetrend -overwrite -verb -polort 2 -vector ${nuisance_file} \ - -prefix \"$postNRBP\" \"$preNRBP\"" - #need to mask detrend by brain mask as with 3dBandpass (3dDetrend doesn't support -mask) - rel "fslmaths \"$postNRBP\" -mas \"$subjMask\" \"$postNRBP\"" - else - #use 3dREMLfit for regression (default) - run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} - fi - - rel "date > .nuisance_regression_complete" - # bandpass and regress - elif [[ "$todo" =~ A?bg?r ]]; then - if [ $arma_nuisance_regression -eq 0 ]; then - rel "3dTproject -overwrite -input \"$preNRBP\" -mask \"${subjMask}${ext}\" -dt $tr \ - -prefix \"$postNRBP\" -polort 2 -ort ${nuisance_file} -passband $bpLow $bpHigh" - - #Deprecated -- 3dTproject performs true simultaneous approach, not filter all -> bandpass - #rel "3dBandpass -overwrite -input \"$preNRBP\" -mask \"${subjMask}${ext}\" -dt $tr \ - # -prefix \"$postNRBP\" -ort ${nuisance_file} $bpLow $bpHigh" - else - #use 3dREMLfit for bandpass + regression (default) - run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} - fi - - rel "date > .bandpass_filter_complete" - rel "date > .nuisance_regression_complete" - else - # we were only computing things - rel "(Regressors computed but no bandpass or nuisance regression applied)" c - fi + case $(reg_todo_to_desc "$todo") in + bandpass+prewhite) + run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} #function should pick up this circumstance + rel "date > .bandpass_filter_complete" + ;; + bandpass) + rel "3dBandpass -input \"$preNRBP\" -mask \"${subjMask}${ext}\" -dt $tr \ + -prefix \"$postNRBP\" $bpLow $bpHigh" + rel "date > .bandpass_filter_complete" + ;; + regressonly) + if [ $arma_nuisance_regression -eq 0 ]; then + rel "3dDetrend -overwrite -verb -polort 2 -vector ${nuisance_file} \ + -prefix \"$postNRBP\" \"$preNRBP\"" + #need to mask detrend by brain mask as with 3dBandpass (3dDetrend doesn't support -mask) + rel "fslmaths \"$postNRBP\" -mas \"$subjMask\" \"$postNRBP\"" + else + #use 3dREMLfit for regression (default) + run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} + fi + rel "date > .nuisance_regression_complete" + ;; + bandpass+regress) + if [ $arma_nuisance_regression -eq 0 ]; then + rel "3dTproject -overwrite -input \"$preNRBP\" -mask \"${subjMask}${ext}\" -dt $tr \ + -prefix \"$postNRBP\" -polort 2 -ort ${nuisance_file} -passband $bpLow $bpHigh" + + #Deprecated -- 3dTproject performs true simultaneous approach, not filter all -> bandpass + #rel "3dBandpass -overwrite -input \"$preNRBP\" -mask \"${subjMask}${ext}\" -dt $tr \ + # -prefix \"$postNRBP\" -ort ${nuisance_file} $bpLow $bpHigh" + else + #use 3dREMLfit for bandpass + regression (default) + run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} + fi + rel "date > .bandpass_filter_complete" + rel "date > .nuisance_regression_complete" + ;; + none) rel "(Regressors computed but no bandpass or nuisance regression applied)" c ;; + *) + rel "ERROR: don't know what to do with $todo = '$(reg_todo_to_desc "$todo")'" c + return 1 + ;; + esac + #explicit return code needed to avoid implicit status of prior command return 0 diff --git a/preproc_functions/parse_args b/preproc_functions/parse_args index 863b252..ee5076c 100644 --- a/preproc_functions/parse_args +++ b/preproc_functions/parse_args @@ -14,6 +14,7 @@ function parse_args { cleanup_only=0 compute_warp=0 #used for -compute_warp_only. Specifies to compute warp to template without applying it to preprocessed data. constrainToTemplate="y" + custom_regprefix="" # added 20250925 - used instead of 'r' for regression prefix deoblique_all=0 despike=0 despikeThresh="2.5 4.0" @@ -251,6 +252,9 @@ function parse_args { sliceTimesFile="$2" sliceMotion4D=1 #for now, this option is only relevant for sliceMotion4d correction shift 2 + elif [ $1 = -custom_regression_prefix ]; then + custom_regprefix="$2" + shift 2 elif [ $1 = -constrain_to_template ]; then if [[ $2 = [NnYy] ]]; then constrainToTemplate="${2}" @@ -650,6 +654,11 @@ function parse_args { exit 1 fi + if [[ "$nuisance_regression" -eq 0 && -n $custom_regprefix ]]; then + echo "Cannot request -custom_regression_prefix without also specifying -nuisance_regression" + exit 1 + fi + # Not legal to use -rm_completefiles without warping if [[ -n "$rmgroup_component_1d" && $no_warp -ge 1 ]]; then echo "Cannot request -rmgroup_component and not preform a warp!" @@ -693,7 +702,7 @@ function parse_args { #if we have v6.0+, then incorporate fieldmap unwarping into BBR func2struct #and use resulting unwarping information for EPI -> unwarp -> struct -> MNI transform. #for older versions, need to use EPI-registered fieldmap for unwarping - flirtVersion=$( flirt | head -1 | perl -pe 's/^FLIRT version ([0-9\\.]+)$/\1/' ) + command -v flirt && flirtVersion=$( flirt | head -1 | perl -pe 's/^FLIRT version ([0-9\\.]+)$/\1/' ) || flirtVersion=0 bbrCapable=$( echo "${flirtVersion} >= 6" | bc ) #The smoothing kernel parameter is expected to be the full width at half diff --git a/preprocessFunctional b/preprocessFunctional index aeb5a07..90e234d 100755 --- a/preprocessFunctional +++ b/preprocessFunctional @@ -50,6 +50,9 @@ Command line options: -custom_slice_times: For use with 4d slice timing + motion correction. A csv file containing the times (in seconds summing to TR) of each slice (bottom to top). Example: -custom_slice_times "../SPECCMBSliceTimes.csv" + -custom_regression_prefix + Use a specified letter or letters instead of 'r' for regression. Also see -gsr + Approprate for tracking eg '-custom_regression_prefix M -nuisance_regression motion6' seperatly from default -delete_dicom: if converting dicom to nifti, whether delete or archive DICOM files. If not passed, user will be prompted for action. Options are: -delete_dicom no. (leaves DICOM untouched) @@ -204,7 +207,7 @@ The major steps in the processing pipeline are, in order: 10) ICA-AROMA (optional) - a 11) High-pass filtering - f 12) Intensity normalization - n - 13) Nuisance regression (optional) - r + 13) Nuisance regression (optional) - r (also see -custom_regression_prefix) 13.5) Global signal regression (optional, label optional) - g 14) Bandpass filtering (optional) - b 15) Auto Correlation removal (optional) - A @@ -235,6 +238,8 @@ EndOfHelp # #Changelog: # +# 09/25/2025 (WF) +# - add '-custom_regression_prefix' (refactor preproc_functions/nuisance_regression) #04/30/2024 (WF) # - added '-ignore_bids' option and handle slicetiming missing errors #08/26/2022 (WF) diff --git a/test/fmripp_parseargs.bats b/test/fmripp_parseargs.bats index 364a2f8..662fc4f 100755 --- a/test/fmripp_parseargs.bats +++ b/test/fmripp_parseargs.bats @@ -177,8 +177,17 @@ teardown() { parse_args -4d fake.nii.gz -gsr -nuisance_regression dwm,gs,wm [ $gsr_in_prefix -eq 1 ] [ $nuisance_regressors = "dwm,gs,wm" ] + } +@test "custom reg" { + run parse_args -4d fake.nii.gz -custom_regression_prefix R + [ $status -eq 1 ] + [[ $output =~ Cannot.*without ]] + + parse_args -4d fake.nii.gz -custom_regression_prefix Mr -nuisance_regression 6motion + [[ $custom_regprefix = "Mr" ]] +} @test "-rmgroup_component" { parse_args -4d fake.nii.gz -rmgroup_component test.1d -tr 1 diff --git a/test/fmripp_remove_autocorr_and_br.bats b/test/fmripp_remove_autocorr_and_br.bats index 2115604..8bd5c45 100755 --- a/test/fmripp_remove_autocorr_and_br.bats +++ b/test/fmripp_remove_autocorr_and_br.bats @@ -4,7 +4,6 @@ # test remove_autocorr_and_br # ############################### -testdir=batsautocorr mknii() { name=$1; shift @@ -13,13 +12,13 @@ mknii() { # go into a special temp dir setup() { - cd $BATS_TEST_DIRNAME - source ../preproc_functions/helper_functions - source ../preproc_functions/parse_args - source ../preproc_functions/nuisance_regression + THISTESTDIR=$(mktemp -d $BATS_TMPDIR/autocor-XXX) + cd ${THISTESTDIR} + MRI_STDDIR=$THISTESTDIR # to stop helper_functions from complaining about missing MNI + source $BATS_TEST_DIRNAME/../preproc_functions/helper_functions + source $BATS_TEST_DIRNAME/../preproc_functions/parse_args + source $BATS_TEST_DIRNAME/../preproc_functions/nuisance_regression # regression_todo reg_todo_to_desc nuisance_regression - mkdir $testdir - cd $testdir # for where to save log file funcdir=$(pwd) @@ -34,14 +33,12 @@ setup() { # COMPUTE_NUISANCE_REGRESSORS_GLOBALS=(nuisance_file nuisance_regressors no_warp postWarp postDespike postSS templateName mprageBet_base ext tr prefix) # compute_nuisance_regressors - - } # remove tempdir and contents teardown() { cd .. - rm -r $testdir + test -d "${THISTESTDIR}" && rm -r ${THISTESTDIR} || echo "WARNING: no tempdir $THISTESTDIR ?" >&2 return 0 } @@ -150,3 +147,34 @@ teardown() { #cp -r . ../batsautocorr_sav } + +@test "regression todo: bp+reg" { + parse_args -4d fake.nii.gz -4d test.nii.gz -rmautocorr -bandpass_filter 0.009 .08 -log "" -nuisance_regression 6motion,csf,wm,dcsf,dwm + todo=$(regression_todo) + echo "$todo" >&2 + [[ $todo = Abr ]] + [[ $(reg_todo_to_desc $todo) == bandpass+regress ]] +} +@test "regression todo: bp+reg (custom)" { + parse_args -4d fake.nii.gz -custom_regression_prefix R -4d test.nii.gz -rmautocorr -bandpass_filter 0.009 .08 -log "" -nuisance_regression 6motion + todo=$(regression_todo) + echo "$todo" >&2 + [[ $todo = AbR ]] + [[ $(reg_todo_to_desc $todo) == bandpass+regress ]] +} + +@test "regression todo: bp" { + parse_args -4d fake.nii.gz -4d test.nii.gz -bandpass_filter 0.009 .08 -log "" + todo=$(regression_todo) + echo "$todo" >&2 + [[ $todo = b ]] + [[ $(reg_todo_to_desc $todo) == bandpass ]] +} + +@test "regression todo: none" { + parse_args -4d fake.nii.gz -4d test.nii.gz -log "" + todo=$(regression_todo) + echo "$todo" >&2 + [[ $todo = "" ]] + [[ $(reg_todo_to_desc $todo) == none ]] +} From ffe0d67e95f6023faf875eebdc7f0fcd578c8dc1 Mon Sep 17 00:00:00 2001 From: WillForan Date: Thu, 25 Sep 2025 14:06:19 -0400 Subject: [PATCH 2/3] feat(regression): must specify file if custom; custom complete flag file --- preproc_functions/nuisance_regression | 21 +++++++++++---------- preproc_functions/parse_args | 4 ++++ preprocessFunctional | 2 +- test/fmripp_parseargs.bats | 8 ++++++-- test/fmripp_remove_autocorr_and_br.bats | 17 ++++++++++++++++- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/preproc_functions/nuisance_regression b/preproc_functions/nuisance_regression index 85795aa..048700a 100644 --- a/preproc_functions/nuisance_regression +++ b/preproc_functions/nuisance_regression @@ -122,7 +122,7 @@ function run_3dremlfit(){ function compute_nuisance_regressors { # 20170421WF: skipping might be a problem if we change what regressors we want - if [ -r .nuisance_compute_complete ]; then + if [ -r .nuisance_compute_complete${custom_regprefix:-} ]; then rel "already computed nuisance regression" c return 0 fi @@ -522,9 +522,9 @@ function compute_nuisance_regressors { fi # TODO: do multiple passes to build nuisancecols so we can check that would should be redoing? - rel "echo '${nuisancecols[*]}' > .regressors_in_use" + rel "echo '${nuisancecols[*]}' > .regressors_in_use${custom_regprefix:-}" - rel "date > .nuisance_compute_complete" + rel "date > .nuisance_compute_complete${custom_regprefix:-}" return 0 } @@ -540,15 +540,16 @@ function regression_todo { echo "$todo" } function reg_already_done { - local todo="${1:?regression operations by prefix}" + local todo="${1:?$FUNC_NAME needs regression operations by prefix, eg Abr}" local reg_prefix=${custom_regprefix:-r} + local complete_file=.nuisance_regression${custom_regprefix:-}_complete # default .nuisance_regression_complete - [[ -f .nuisance_regression_complete && $todo=$reg_prefix ]] && return 0 + [[ -f $complete_file && $todo=$reg_prefix ]] && return 0 [[ -f .bandpass_filter_complete && $todo=b ]] && return 0 [[ -f .bandpass_filter_complete && .remove_autocorr_complete && $todo=Ab ]] && return 0 - [[ -f .nuisance_regression_complete && -f .bandpass_filter_complete && $todo=b$reg_prefix ]] && return 0 - [[ -f .nuisance_regression_complete && -f .remove_autocorr_complete && $todo=A$reg_prefix ]] && return 0 - [[ -f .nuisance_regression_complete && -f .bandpass_filter_complete && -f .remove_autocorr_complete && $todo=Ab$reg_prefix ]] && return 0 + [[ -f $complete_file && -f .bandpass_filter_complete && $todo=b$reg_prefix ]] && return 0 + [[ -f $complete_file && -f .remove_autocorr_complete && $todo=A$reg_prefix ]] && return 0 + [[ -f $complete_file && -f .bandpass_filter_complete && -f .remove_autocorr_complete && $todo=Ab$reg_prefix ]] && return 0 # not already done return 1 @@ -629,7 +630,7 @@ function nuisance_regression { #use 3dREMLfit for regression (default) run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} fi - rel "date > .nuisance_regression_complete" + rel "date > .nuisance_regression${custom_regprefix:-}_complete" ;; bandpass+regress) if [ $arma_nuisance_regression -eq 0 ]; then @@ -644,7 +645,7 @@ function nuisance_regression { run_3dremlfit $preNRBP $postNRBP ${subjMask}${ext} fi rel "date > .bandpass_filter_complete" - rel "date > .nuisance_regression_complete" + rel "date > .nuisance_regression${custom_regprefix:-}_complete" ;; none) rel "(Regressors computed but no bandpass or nuisance regression applied)" c ;; *) diff --git a/preproc_functions/parse_args b/preproc_functions/parse_args index ee5076c..805a74e 100644 --- a/preproc_functions/parse_args +++ b/preproc_functions/parse_args @@ -658,6 +658,10 @@ function parse_args { echo "Cannot request -custom_regression_prefix without also specifying -nuisance_regression" exit 1 fi + if [[ -n $custom_regprefix && "$nuisance_file" == .nuisance_regressors ]]; then + echo "Cannot request -custom_regression_prefix without also changing default -nuisance_file" + exit 1 + fi # Not legal to use -rm_completefiles without warping if [[ -n "$rmgroup_component_1d" && $no_warp -ge 1 ]]; then diff --git a/preprocessFunctional b/preprocessFunctional index 90e234d..d5abf56 100755 --- a/preprocessFunctional +++ b/preprocessFunctional @@ -52,7 +52,7 @@ Command line options: Example: -custom_slice_times "../SPECCMBSliceTimes.csv" -custom_regression_prefix Use a specified letter or letters instead of 'r' for regression. Also see -gsr - Approprate for tracking eg '-custom_regression_prefix M -nuisance_regression motion6' seperatly from default + Approprate for tracking eg '-custom_regression_prefix M -nuisance_regression motion6 -nuisance_file motion_reg.txt' seperatly from default -delete_dicom: if converting dicom to nifti, whether delete or archive DICOM files. If not passed, user will be prompted for action. Options are: -delete_dicom no. (leaves DICOM untouched) diff --git a/test/fmripp_parseargs.bats b/test/fmripp_parseargs.bats index 662fc4f..4aef55d 100755 --- a/test/fmripp_parseargs.bats +++ b/test/fmripp_parseargs.bats @@ -183,9 +183,13 @@ teardown() { @test "custom reg" { run parse_args -4d fake.nii.gz -custom_regression_prefix R [ $status -eq 1 ] - [[ $output =~ Cannot.*without ]] + [[ $output =~ Cannot.*without.*nuisance_reg ]] - parse_args -4d fake.nii.gz -custom_regression_prefix Mr -nuisance_regression 6motion + run parse_args -4d fake.nii.gz -custom_regression_prefix R -nuisance_regression 6motion + [ $status -eq 1 ] + [[ $output =~ Cannot.*without.*nuisance_file ]] + + parse_args -4d fake.nii.gz -custom_regression_prefix Mr -nuisance_regression 6motion -nuisance_file reg_motion.txt [[ $custom_regprefix = "Mr" ]] } diff --git a/test/fmripp_remove_autocorr_and_br.bats b/test/fmripp_remove_autocorr_and_br.bats index 8bd5c45..7692225 100755 --- a/test/fmripp_remove_autocorr_and_br.bats +++ b/test/fmripp_remove_autocorr_and_br.bats @@ -156,7 +156,7 @@ teardown() { [[ $(reg_todo_to_desc $todo) == bandpass+regress ]] } @test "regression todo: bp+reg (custom)" { - parse_args -4d fake.nii.gz -custom_regression_prefix R -4d test.nii.gz -rmautocorr -bandpass_filter 0.009 .08 -log "" -nuisance_regression 6motion + parse_args -4d fake.nii.gz -custom_regression_prefix R -4d test.nii.gz -rmautocorr -bandpass_filter 0.009 .08 -log "" -nuisance_regression 6motion -nuisance_file reg_motion.txt todo=$(regression_todo) echo "$todo" >&2 [[ $todo = AbR ]] @@ -178,3 +178,18 @@ teardown() { [[ $todo = "" ]] [[ $(reg_todo_to_desc $todo) == none ]] } + +@test "regression test complete" { + parse_args -4d fake.nii.gz -4d test.nii.gz -bandpass_filter 0.009 .08 -log "" -nuisance_regression 6motion -nuisance_file reg_motion.txt + touch .nuisance_regression_complete .bandpass_filter_complete + reg_already_done $(regression_todo) +} + +@test "regression test complete (custom)" { + parse_args -4d fake.nii.gz -custom_regression_prefix R -4d test.nii.gz -bandpass_filter 0.009 .08 -log "" -nuisance_regression 6motion -nuisance_file reg_motion.txt + touch .nuisance_regression_complete .bandpass_filter_complete + # not done b/c missing 'R' version of complete + ! reg_already_done $todo + touch .nuisance_regressionR_complete + reg_already_done $todo +} From 06d7784111a87ee89f096f125bbc51f62faaf826 Mon Sep 17 00:00:00 2001 From: WillForan Date: Thu, 25 Sep 2025 18:05:43 -0400 Subject: [PATCH 3/3] test: skip missing pcorr and missing py2 --- test/ROI_TempCorr.R.bats | 3 +++ test/slicemotion4d.bats | 1 + 2 files changed, 4 insertions(+) diff --git a/test/ROI_TempCorr.R.bats b/test/ROI_TempCorr.R.bats index c9ae6d0..234f45e 100755 --- a/test/ROI_TempCorr.R.bats +++ b/test/ROI_TempCorr.R.bats @@ -129,10 +129,13 @@ teardown() { ## Semi @test "semi cor" { + + Rscript -e "installed.packages()['ppcor','Version']" || skip "R missing ppcor" ROI_TempCorr.R -ts $shortrestfile -brainmask $mask -rois $roi -njobs 1 -pcorr_method semi:pearson last_rowcol corr_rois_pearson_semipartial.txt "33 102" } @test "semi+partial+full cor" { + Rscript -e "installed.packages()['ppcor','Version']" || skip "R missing ppcor" ROI_TempCorr.R -ts $shortrestfile -brainmask $mask -rois $roi -njobs 1 -pcorr_method semi:pearson,pearson -corr_method pearson last_rowcol corr_rois_pearson.txt "33 33" last_rowcol corr_rois_pearson_semipartial.txt "33 102" diff --git a/test/slicemotion4d.bats b/test/slicemotion4d.bats index af29bb6..e987332 100755 --- a/test/slicemotion4d.bats +++ b/test/slicemotion4d.bats @@ -41,6 +41,7 @@ teardown() { # only run if we dont have matlab and do have octave @test "py2 and py3 have same results" { [ ! -r ../../sliceMotion4d_py2 ] && skip + [[ "$(python --version 2>&1)" =~ Python\ 2 ]] || skip "python is not py2" ../../sliceMotion4d -i example.nii.gz --siemens --slice_times interleaved --prefix mt_ -t 1.5 ../../sliceMotion4d_py2 -i example.nii.gz --siemens --slice_times interleaved --prefix mt2_ -t 1.5 results=$(3dBrickStat -non-zero -mean -slow "3dcalc( -a mt_example.nii.gz -b mt2_example.nii.gz -expr a-b )")