Skip to content

Commit 523d852

Browse files
Swap out fsl_regfilt and R wrapper for internal lmfit functions; add aroma tests
1 parent 6ee4dc0 commit 523d852

12 files changed

Lines changed: 640 additions & 183 deletions

‎NAMESPACE‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ importFrom(checkmate,test_character)
6868
importFrom(checkmate,test_class)
6969
importFrom(checkmate,test_directory_exists)
7070
importFrom(checkmate,test_file_exists)
71+
importFrom(checkmate,test_integerish)
7172
importFrom(checkmate,test_list)
7273
importFrom(checkmate,test_null)
7374
importFrom(checkmate,test_number)

‎NEWS.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# BrainGnomes 0.7-3
22

33
* bugfix: correctly handle unsigned integer data types in NIfTIs
4-
* lmfit_residuals_4d now handles partial (ala fsl_regfilt) and full regression
4+
* lmfit_residuals_4d now handles partial (ala fsl_regfilt) and full regression and is used for applying AROMA
5+
* Nonaggressive and aggressive AROMA now supported
6+
* fsl_regfilt.R wrapper script removed from pipeline -- all regression now happens with lmfit_residuals_4d
57

68
# BrainGnomes 0.7-2
79

‎R/postprocess_confounds.R‎

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,50 @@ postprocess_confounds <- function(proc_files, cfg, processing_sequence,
110110
# TODO: consider whether to worry about notch filtering AROMA components if motion parameters or FD are in confound regressors
111111
# Regress out AROMA components, if requested (overwrites file in place)
112112
if ("apply_aroma" %in% processing_sequence) {
113-
lg$info("Removing AROMA noise components from confounds")
114-
confound_nii <- apply_aroma(confound_nii, out_file = confound_nii,
115-
mixing_file = proc_files$melodic_mix, noise_ics = proc_files$noise_ics,
116-
overwrite = TRUE, lg = lg, use_R = TRUE, fsl_img = fsl_img
117-
)
113+
if (is.null(proc_files$melodic_mix) || !checkmate::test_file_exists(proc_files$melodic_mix)) {
114+
to_log(lg, "warn", "Cannot locate melodic mixing file; skipping AROMA regression for confounds.")
115+
} else if (is.null(proc_files$noise_ics) || length(proc_files$noise_ics) == 0) {
116+
to_log(lg, "info", "No AROMA noise components provided; skipping regression for confounds.")
117+
} else if (!checkmate::test_integerish(proc_files$noise_ics, lower = 1, any.missing = FALSE)) {
118+
to_log(lg, "warn", "noise_ics must be a vector of positive integers; skipping AROMA regression for confounds.")
119+
} else {
120+
nonaggressive_val <- cfg$apply_aroma$nonaggressive
121+
nonaggressive_flag <- if (is.null(nonaggressive_val) || is.na(nonaggressive_val)) TRUE else isTRUE(nonaggressive_val)
122+
exclusive_flag <- !nonaggressive_flag
123+
mode_label <- if (exclusive_flag) "aggressive" else "non-aggressive"
124+
125+
mixing_mat <- as.matrix(data.table::fread(proc_files$melodic_mix, header = FALSE, data.table = FALSE))
126+
storage.mode(mixing_mat) <- "double"
127+
if (nrow(mixing_mat) != nrow(confounds_to_filt)) {
128+
to_log(lg, "warn", "Mixing matrix has {nrow(mixing_mat)} rows but confounds have {nrow(confounds_to_filt)} timepoints; skipping AROMA regression for confounds.")
129+
} else if (ncol(mixing_mat) == 0) {
130+
to_log(lg, "warn", "Mixing matrix {proc_files$melodic_mix} has no components; skipping AROMA regression for confounds.")
131+
} else {
132+
comp_idx <- sort(unique(as.integer(proc_files$noise_ics)))
133+
invalid_idx <- comp_idx[comp_idx < 1 | comp_idx > ncol(mixing_mat)]
134+
if (length(invalid_idx) > 0) {
135+
to_log(lg, "warn", "Dropping invalid AROMA component indices for confounds: {paste(invalid_idx, collapse = ', ')}")
136+
comp_idx <- setdiff(comp_idx, invalid_idx)
137+
}
138+
if (length(comp_idx) == 0) {
139+
lg$info("No valid AROMA noise components remain after filtering; skipping regression for confounds.")
140+
} else {
141+
to_log(lg, "info", "Regressing {length(comp_idx)} AROMA noise components from confounds using {mode_label} mode.")
142+
confound_names <- colnames(confounds_to_filt)
143+
resid_mat <- lmfit_residuals_mat(
144+
Y = as.matrix(confounds_to_filt),
145+
X = mixing_mat,
146+
include_rows = rep(TRUE, nrow(mixing_mat)),
147+
add_intercept = FALSE,
148+
regress_cols = comp_idx,
149+
exclusive = exclusive_flag
150+
)
151+
colnames(resid_mat) <- confound_names
152+
confounds_to_filt <- resid_mat
153+
confound_nii <- mat_to_nii(confounds_to_filt, ni_out = confound_nii)
154+
}
155+
}
156+
}
118157
}
119158

120159
# Temporally filter confounds, if requested (overwrites file in place)

0 commit comments

Comments
 (0)