Skip to content

Commit

Permalink
Remove M0 metadata from multi-PLD GE metadata dictionary (#315)
Browse files Browse the repository at this point in the history
* Reduce volume-wise multi-PLD GE metadata.

* Connect the metadata.

* Add fMRIPrep citations.
  • Loading branch information
tsalo committed Jul 5, 2023
1 parent 3e7f09c commit e4faea1
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 52 deletions.
26 changes: 26 additions & 0 deletions aslprep/data/boilerplate.bib
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@ @article{buxton1998general
pages = {383--396},
}

@article{esteban2019fmriprep,
title={fMRIPrep: a robust preprocessing pipeline for functional MRI},
author={Esteban, Oscar and Markiewicz, Christopher J and Blair, Ross W and Moodie, Craig A and Isik, A Ilkay and Erramuzpe, Asier and Kent, James D and Goncalves, Mathias and DuPre, Elizabeth and Snyder, Madeleine and others},
journal={Nature methods},
volume={16},
number={1},
pages={111--116},
year={2019},
publisher={Nature Publishing Group},
url={https://www.nature.com/articles/s41592-018-0235-4},
doi={10.1038/s41592-018-0235-4},
}

@article{esteban2020analysis,
title={Analysis of task-based functional MRI data preprocessed with fMRIPrep},
author={Esteban, Oscar and Ciric, Rastko and Finc, Karolina and Blair, Ross W and Markiewicz, Christopher J and Moodie, Craig A and Kent, James D and Goncalves, Mathias and DuPre, Elizabeth and Gomez, Daniel EP and others},
journal={Nature protocols},
volume={15},
number={7},
pages={2186--2202},
year={2020},
publisher={Nature Publishing Group},
url={https://doi.org/10.1038/s41596-020-0327-3},
doi={10.1038/s41596-020-0327-3}
}

@article{mcflirt,
title = {Improved optimization for the robust and accurate linear registration and motion correction of brain images},
volume = {17},
Expand Down
68 changes: 37 additions & 31 deletions aslprep/interfaces/cbf.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
determine_multi_pld,
estimate_labeling_efficiency,
pcasl_or_pasl,
reduce_metadata_lists,
)
from aslprep.utils.cbf import (
_getcbfscore,
Expand Down Expand Up @@ -230,7 +231,7 @@ def _run_interface(self, runtime):
else:
raise RuntimeError("No valid ASL or CBF image.")

# Update the metadata as necessary
# Remove volume-wise metadata for M0 scans as necessary
VOLUME_WISE_FIELDS = [
"PostLabelingDelay",
"VascularCrushingVENC",
Expand Down Expand Up @@ -284,13 +285,21 @@ def _run_interface(self, runtime):

class _ExtractCBForDeltaMInputSpec(BaseInterfaceInputSpec):
asl_file = File(exists=True, mandatory=True, desc="raw asl file")
metadata = traits.Dict(mandatory=True, desc="metadata for ASL file")
aslcontext = File(exists=True, mandatory=True, desc="aslcontext TSV file for run.")
asl_mask = File(exists=True, mandatory=True, desct="asl mask")
file_type = traits.Str(desc="file type, c for cbf, d for deltam", mandatory=True)


class _ExtractCBForDeltaMOutputSpec(TraitedSpec):
out_file = File(exists=False, desc="cbf or deltam")
metadata = traits.Dict(
desc=(
"Metadata for the ASL run. "
"The dictionary may be modified to only include metadata associated with the selected "
"volumes."
),
)


class ExtractCBForDeltaM(SimpleInterface):
Expand All @@ -315,7 +324,18 @@ def _run_interface(self, runtime):
deltam_volume_idx = [i for i, vol_type in enumerate(vol_types) if vol_type == "deltam"]
cbf_volume_idx = [i for i, vol_type in enumerate(vol_types) if vol_type == "cbf"]

if self.inputs.file_type == "d":
metadata = self.inputs.metadata.copy()

if len(asl_data.shape) < 4:
# 3D volume is written out without any changes.
# NOTE: Why not return the original file then?
out_img = nb.Nifti1Image(
dataobj=asl_data,
affine=asl_img.affine,
header=asl_img.header,
)

elif self.inputs.file_type == "d":
if len(control_volume_idx) > 0:
# Grab control and label volumes from ASL file,
# then calculate deltaM by subtracting label volumes from control volumes.
Expand All @@ -327,43 +347,29 @@ def _run_interface(self, runtime):
affine=asl_img.affine,
header=asl_img.header,
)
metadata = reduce_metadata_lists(metadata, control_volume_idx)
else:
# Grab deltaM volumes from ASL file.
if len(asl_data.shape) < 4:
# 3D volume is written out without any changes.
# NOTE: Why not return the original file then?
out_img = nb.Nifti1Image(
dataobj=asl_data,
affine=asl_img.affine,
header=asl_img.header,
)
else:
deltam_data = asl_data[:, :, :, deltam_volume_idx]
out_img = nb.Nifti1Image(
dataobj=deltam_data,
affine=asl_img.affine,
header=asl_img.header,
)

elif self.inputs.file_type == "c":
if len(asl_data.shape) < 4:
# 3D volume is written out without any changes.
# NOTE: Why not return the original file then?
out_img = nb.Nifti1Image(
dataobj=asl_data,
affine=asl_img.affine,
header=asl_img.header,
)
else:
# Grab CBF volumes from ASL file.
cbf_data = asl_data[:, :, :, cbf_volume_idx]
deltam_data = asl_data[:, :, :, deltam_volume_idx]
out_img = nb.Nifti1Image(
dataobj=cbf_data,
dataobj=deltam_data,
affine=asl_img.affine,
header=asl_img.header,
)
metadata = reduce_metadata_lists(metadata, deltam_volume_idx)

elif self.inputs.file_type == "c":
# Grab CBF volumes from ASL file.
cbf_data = asl_data[:, :, :, cbf_volume_idx]
out_img = nb.Nifti1Image(
dataobj=cbf_data,
affine=asl_img.affine,
header=asl_img.header,
)
metadata = reduce_metadata_lists(metadata, cbf_volume_idx)

out_img.to_filename(self._results["out_file"])
self._results["metadata"] = metadata

return runtime

Expand Down
29 changes: 13 additions & 16 deletions aslprep/workflows/asl/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def init_asl_preproc_wf(asl_file):
mean_cbf_scrub_std, mean_cbf_gm_basil_std, mean_cbf_basil_std
scrub, parital volume corrected and basil cbf in template space
qc_file
quality control meausres
quality control measures
Notes
-----
Expand All @@ -124,26 +124,23 @@ def init_asl_preproc_wf(asl_file):
4. Susceptibility distortion correction.
- Outputs the SDC transform.
- Not in GE workflow.
5. If data are multi-echo (which they can't be), skullstrip the ASL data and perform optimal
combination.
- Not in GE workflow.
6. Register ASL to T1w.
7. Apply the ASL-to-T1w transforms to get T1w-space outputs
5. Register ASL to T1w.
6. Apply the ASL-to-T1w transforms to get T1w-space outputs
(passed along to derivatives workflow).
8. Apply the ASL-to-ASLref transforms to get native-space outputs.
7. Apply the ASL-to-ASLref transforms to get native-space outputs.
- Not in GE workflow.
9. Calculate confounds.
8. Calculate confounds.
- Not in GE workflow.
10. Calculate CBF.
11. Refine the brain mask.
12. Generate distortion correction report.
9. Calculate CBF.
10. Refine the brain mask.
11. Generate distortion correction report.
- Not in GE workflow.
13. Apply ASL-to-template transforms to get template-space outputs.
14. CBF QC workflow.
15. CBF plotting workflow.
16. Generate carpet plots.
12. Apply ASL-to-template transforms to get template-space outputs.
13. CBF QC workflow.
14. CBF plotting workflow.
15. Generate carpet plots.
- Not in GE workflow.
17. Parcellate CBF results.
16. Parcellate CBF results.
"""
mem_gb = {"filesize": 1, "resampled": 1, "largemem": 1}
asl_tlen = 10
Expand Down
18 changes: 14 additions & 4 deletions aslprep/workflows/asl/cbf.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,11 @@ def _getfiledir(file):
if deltam_volume_idx or control_volume_idx:
# If deltaM or label-control pairs are available, then calculate CBF.
extract_deltam = pe.Node(
ExtractCBForDeltaM(file_type="d", aslcontext=aslcontext),
ExtractCBForDeltaM(
file_type="d",
aslcontext=aslcontext,
metadata=metadata,
),
mem_gb=1,
run_without_submitting=True,
name="extract_deltam",
Expand All @@ -694,7 +698,6 @@ def _getfiledir(file):

compute_cbf = pe.Node(
ComputeCBF(
metadata=metadata,
m0_scale=m0_scale,
cbf_only=cbf_only,
),
Expand All @@ -706,7 +709,10 @@ def _getfiledir(file):
# fmt:off
workflow.connect([
(inputnode, compute_cbf, [("m0_file", "m0_file")]),
(extract_deltam, compute_cbf, [("out_file", "deltam")]),
(extract_deltam, compute_cbf, [
("metadata", "metadata"),
("out_file", "deltam"),
]),
(extract_deltam, collect_cbf, [("out_file", "deltam")]),
(refine_mask, compute_cbf, [("out_mask", "mask")]),
(compute_cbf, collect_cbf, [("cbf_ts", "cbf")]),
Expand All @@ -720,7 +726,11 @@ def _getfiledir(file):

elif cbf_volume_idx:
extract_cbf = pe.Node(
ExtractCBForDeltaM(file_type="c"),
ExtractCBForDeltaM(
file_type="c",
aslcontext=aslcontext,
metadata=metadata,
),
mem_gb=1,
run_without_submitting=True,
name="extract_cbf",
Expand Down
2 changes: 1 addition & 1 deletion aslprep/workflows/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def init_single_subject_wf(subject_id):
Arterial spin-labeled MRI images were preprocessed using *ASLPrep* {config.environment.version}
[@aslprep_nature_methods;@aslprep_zenodo],
which is based on *fMRIPrep* (@fmriprep1; @fmriprep2; RRID:SCR_016216) and
which is based on *fMRIPrep* (@esteban2019fmriprep; @esteban2020analysis; RRID:SCR_016216) and
*Nipype* {config.environment.nipype_version} [@nipype].
"""
Expand Down

0 comments on commit e4faea1

Please sign in to comment.