Skip to content

Commit

Permalink
Keep working.
Browse files Browse the repository at this point in the history
  • Loading branch information
tsalo committed May 5, 2024
1 parent 020818d commit 69c0b54
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 34 deletions.
5 changes: 3 additions & 2 deletions src/fmripost_aroma/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,9 @@ def _bids_filter(value, parser):
g_aroma.add_argument(
"--denoising-method",
action="store",
choices=["aggr", "nonaggr", "both", "none"],
default="nonaggr",
nargs="+",
choices=["aggr", "nonaggr", "orthaggr"],
default=None,
help="Denoising method to apply, if any.",
)
g_aroma.add_argument(
Expand Down
2 changes: 1 addition & 1 deletion src/fmripost_aroma/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ class workflow(_Config):
melodic_dim = None
"""Number of ICA components to be estimated by MELODIC
(positive = exact, negative = maximum)."""
denoising_method = "nonaggr"
denoising_method = None
"""Denoising strategy to be used."""
orthogonalize = False
"""Orthogonalize the AROMA-flagged components w.r.t. the non-flagged components."""
Expand Down
42 changes: 16 additions & 26 deletions src/fmripost_aroma/interfaces/confounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def _get_ica_confounds(ica_out_dir, skip_vols, newpath=None):
class _ICADenoiseInputSpec(BaseInterfaceInputSpec):
method = traits.Enum("aggr", "nonaggr", "orthaggr", mandatory=True, desc="denoising method")
bold_file = File(exists=True, mandatory=True, desc="input file to denoise")
mask_file = File(exists=True, mandatory=True, desc="mask file")
confounds = File(exists=True, mandatory=True, desc="confounds file")


Expand All @@ -144,17 +145,16 @@ class ICADenoise(SimpleInterface):
output_spec = _ICADenoiseOutputSpec

def _run_interface(self, runtime):
import nibabel as nb
import numpy as np
import pandas as pd
from nilearn.maskers import NiftiMasker
from nilearn.masking import apply_mask, unmask

method = self.inputs.method
bold_file = self.inputs.bold_file
confounds_file = self.inputs.confounds
metrics_file = self.inputs.metrics_file

bold_img = nb.load(bold_file)
bold_data = bold_img.get_fdata()
confounds_df = pd.read_table(confounds_file)

# Split up component time series into accepted and rejected components
Expand All @@ -167,7 +167,7 @@ def _run_interface(self, runtime):
if method == "aggr":
# Denoise the data with the motion components
masker = NiftiMasker(
mask_img=mask_file,
mask_img=self.inputs.mask_file,
standardize_confounds=True,
standardize=False,
smoothing_fwhm=None,
Expand All @@ -179,15 +179,10 @@ def _run_interface(self, runtime):
)

# Denoise the data by fitting and transforming the data file using the masker
denoised_img_2d = masker.fit_transform(data_file, confounds=rejected_components)
denoised_img_2d = masker.fit_transform(bold_file, confounds=rejected_components)

# Transform denoised data back into 4D space
denoised_img_4d = masker.inverse_transform(denoised_img_2d)

# Save to file
denoised_img_4d.to_filename(
"sub-01_task-rest_space-MNI152NLin2009cAsym_desc-aggrDenoised_bold.nii.gz"
)
denoised_img = masker.inverse_transform(denoised_img_2d)
elif method == "orthaggr":
# Regress the good components out of the bad time series to get "pure evil" regressors
betas = np.linalg.lstsq(accepted_components, rejected_components, rcond=None)[0]
Expand All @@ -196,7 +191,7 @@ def _run_interface(self, runtime):

# Once you have these "pure evil" components, you can denoise the data
masker = NiftiMasker(
mask_img=mask_file,
mask_img=self.inputs.mask_file,
standardize_confounds=True,
standardize=False,
smoothing_fwhm=None,
Expand All @@ -208,26 +203,21 @@ def _run_interface(self, runtime):
)

# Denoise the data by fitting and transforming the data file using the masker
denoised_img_2d = masker.fit_transform(data_file, confounds=orth_bad_timeseries)
denoised_img_2d = masker.fit_transform(bold_file, confounds=orth_bad_timeseries)

# Transform denoised data back into 4D space
denoised_img_4d = masker.inverse_transform(denoised_img_2d)

# Save to file
denoised_img_4d.to_filename(
"sub-01_task-rest_space-MNI152NLin2009cAsym_desc-orthAggrDenoised_bold.nii.gz"
)
denoised_img = masker.inverse_transform(denoised_img_2d)
else:
# Apply the mask to the data image to get a 2d array
data = apply_mask(data_file, mask_file)
data = apply_mask(bold_file, self.inputs.mask_file)

# Fit GLM to accepted components, rejected components and nuisance regressors
# Fit GLM to accepted components and rejected components
# (after adding a constant term)
regressors = np.hstack(
(
rejected_components,
accepted_components,
np.ones((mixing_df.shape[0], 1)),
np.ones((confounds_df.shape[0], 1)),
),
)
betas = np.linalg.lstsq(regressors, data, rcond=None)[0][:-1]
Expand All @@ -238,9 +228,9 @@ def _run_interface(self, runtime):
data_denoised = data - pred_data

# Save to file
denoised_img = unmask(data_denoised, mask_file)
denoised_img.to_filename(
"sub-01_task-rest_space-MNI152NLin2009cAsym_desc-nonaggrDenoised_bold.nii.gz"
)
denoised_img = unmask(data_denoised, self.inputs.mask_file)

self._results["denoised_file"] = os.path.abspath("denoised.nii.gz")
denoised_img.to_filename(self._results["denoised_file"])

return runtime
10 changes: 5 additions & 5 deletions src/fmripost_aroma/workflows/aroma.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,20 +313,19 @@ def init_denoise_wf(bold_file):
"""Build a workflow that denoises a BOLD series using AROMA confounds.
This workflow performs the denoising in the requested output space(s).
It doesn't currently work on CIFTIs.
"""
from niworkflows.engine.workflows import LiterateWorkflow as Workflow

if config.workflow.denoise_method == "all":
denoise_methods = ["nonaggr", "aggr", "orthaggr"]
else:
denoise_methods = [config.workflow.denoise_method]
from fmripost_aroma.interfaces.confounds import ICADenoise

workflow = Workflow(name=_get_wf_name(bold_file, "denoise"))

inputnode = pe.Node(
niu.IdentityInterface(
fields=[
"bold_file",
"bold_mask_std",
"confounds",
"name_source",
"skip_vols",
Expand All @@ -347,7 +346,7 @@ def init_denoise_wf(bold_file):
]),
]) # fmt:skip

for denoise_method in denoise_methods:
for denoise_method in config.workflow.denoise_method:
denoise = pe.Node(
ICADenoise(method=denoise_method),
name=f"denoise_{denoise_method}",
Expand All @@ -356,6 +355,7 @@ def init_denoise_wf(bold_file):
(inputnode, denoise, [
("confounds", "confounds_file"),
("skip_vols", "skip_vols"),
("bold_mask_std", "mask_file"),
]),
(rm_non_steady_state, denoise, [("bold_cut", "bold_file")]),
]) # fmt:skip
Expand Down

0 comments on commit 69c0b54

Please sign in to comment.