Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement general kinetic model for multi-PLD data #381

Draft
wants to merge 77 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
4df67f3
Draft model fitting code for GKM.
tsalo Dec 14, 2023
3ea0617
Merge remote-tracking branch 'upstream/main' into gkm
tsalo Dec 21, 2023
1b5357d
Keep drafting the fitting code.
tsalo Dec 21, 2023
8fdb90d
It's CBF, not CSF.
tsalo Dec 21, 2023
462d76e
Move the functions.
tsalo Dec 21, 2023
77d4f1b
Try using the new method.
tsalo Dec 21, 2023
2988985
Update boilerplate.bib
tsalo Dec 21, 2023
2f038ef
Update cbf.py
tsalo Dec 21, 2023
c4046f1
Improve shape checks.
tsalo Dec 21, 2023
42125b9
Update cbf.py
tsalo Dec 21, 2023
45a6213
Update cbf.py
tsalo Dec 21, 2023
23b48ca
Try adding equations to docs.
tsalo Dec 21, 2023
1cb0706
Make tau an array.
tsalo Dec 21, 2023
7c9905a
Update workflows.rst
tsalo Dec 21, 2023
59a9e78
Update workflows.rst
tsalo Dec 21, 2023
a551dd4
Update workflows.rst
tsalo Dec 21, 2023
d2566ed
Update workflows.rst
tsalo Dec 21, 2023
15b8c45
Update.
tsalo Dec 21, 2023
96095ae
Try that.
tsalo Dec 22, 2023
9f77294
Update cbf.py
tsalo Dec 22, 2023
2d49598
More work.
tsalo Dec 22, 2023
4cd4d89
Update cbf.py
tsalo Dec 22, 2023
b5b2d9f
Give the new outputs a try.
tsalo Dec 22, 2023
6b00c32
Update plotting.py
tsalo Dec 22, 2023
2e07bfc
reorg
tsalo Dec 22, 2023
2dcb394
Update test_cli.py
tsalo Dec 22, 2023
0b60bed
Update expected_outputs_examples_pcasl_multipld.txt
tsalo Dec 22, 2023
5d76dc2
Update test_cli.py
tsalo Dec 22, 2023
02b999d
Update tests.
tsalo Dec 22, 2023
117aab6
Update cbf.py
tsalo Dec 22, 2023
7dfe3d9
Plot the other metrics.
tsalo Jan 2, 2024
4e76b3f
Update plotting.py
tsalo Jan 2, 2024
1cdf6ba
Update figures.
tsalo Jan 2, 2024
ada7e47
Fix connection.
tsalo Jan 2, 2024
93c2a75
Drop upper limits for check.
tsalo Jan 3, 2024
db98997
Update formulae and add bounds back in.
tsalo Jan 3, 2024
d29b4eb
Remove unused functions and citations.
tsalo Jan 3, 2024
ffe80e1
Update workflows.rst
tsalo Jan 3, 2024
2c6ac42
Update workflows.rst
tsalo Jan 3, 2024
f3e9b58
Update workflows.rst
tsalo Jan 3, 2024
b16730c
Update workflows.rst
tsalo Jan 3, 2024
21098ab
Update workflows.rst
tsalo Jan 3, 2024
fa2f726
Update workflows.rst
tsalo Jan 3, 2024
b344acd
Update workflows.rst
tsalo Jan 3, 2024
bd03dff
Fix tests.
tsalo Jan 3, 2024
e069608
Update again.
tsalo Jan 3, 2024
7d7f3ea
Update workflows.rst
tsalo Jan 3, 2024
0401a1b
Fix documentation issues.
tsalo Jan 3, 2024
2f7b30a
Update outputs.py
tsalo Jan 3, 2024
3d5efbd
Update resampling.py
tsalo Jan 3, 2024
beb5ca4
Resample M0 scan before motion correction.
tsalo Jan 4, 2024
f10908c
Whoops!
tsalo Jan 4, 2024
dc9079f
Fix more.
tsalo Jan 4, 2024
80d715a
Use try/except for model fit.
tsalo Jan 4, 2024
70ecc2f
Update expected_outputs_examples_pasl_multipld.txt
tsalo Jan 4, 2024
69eb31a
Fix citations.
tsalo Jan 4, 2024
e4de393
Improve boilerplate.
tsalo Jan 9, 2024
fccf828
Improve boilerplate.
tsalo Jan 10, 2024
b9135c5
Improve boilerplate.
tsalo Jan 10, 2024
39e721c
Update equations.
tsalo Jan 10, 2024
67ee660
Try making a glossary.
tsalo Jan 10, 2024
71d244c
Drop glossary.
tsalo Jan 10, 2024
8e50938
Update figures.
tsalo Jan 10, 2024
19376a9
Update plotting.py
tsalo Jan 10, 2024
aae2246
Update plotting.py
tsalo Jan 10, 2024
e48062b
Update plotting.py
tsalo Jan 10, 2024
50da3fc
Update plotting.py
tsalo Jan 10, 2024
076d9db
Merge remote-tracking branch 'upstream/main' into gkm
tsalo Jan 10, 2024
1b7ca72
Change limits.
tsalo Jan 11, 2024
cbf56c1
Improve documentation.
tsalo Jan 12, 2024
eedcea5
Fix input type.
tsalo Jan 12, 2024
1f03e36
Use large resource class for PASL multi-PLD.
tsalo Jan 12, 2024
c9a8c80
Update HTML report captions.
tsalo Jan 12, 2024
5c2c0ed
Update test_cli.py
tsalo Jan 12, 2024
4ce2d58
Update reports-spec.yml
tsalo Jan 12, 2024
89ea5c8
Merge remote-tracking branch 'upstream/main' into gkm
tsalo Apr 14, 2024
0383057
Merge branch 'main' into gkm
tsalo Apr 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions aslprep/data/aslprep_bids_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
"sub-{subject}[/ses-{session}]/[{datatype<func|beh>|func}/]sub-{subject}[_ses-{session}]_task-{task}[_acq-{acquisition}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_recording-{recording}]_{suffix<physio|stim>}{extension<.tsv.gz|.json>|.tsv.gz}",
"sub-{subject}[/ses-{session}]/{datatype<func|perf>|func}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_space-{space}][_atlas-{atlas}][_cohort-{cohort}][_desc-{desc}]_{suffix<regressors|timeseries>|timeseries}{extension<.json|.tsv|.csv|>|.tsv}",
"sub-{subject}[/ses-{session}]/{datatype<perf>|perf}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_desc-{desc}]_{suffix<confounds>}{extension<.tsv|.json>|.tsv}",
"sub-{subject}[/ses-{session}]/{datatype<perf>|perf}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_space-{space}][_res-{res}][_atlas-{atlas}][_cohort-{cohort}][_desc-{desc}]_{suffix<asl|aslref|att|cbf|coverage|mask>}{extension<.nii|.nii.gz|.json|.csv|.tsv>|.nii.gz}",
"sub-{subject}[/ses-{session}]/{datatype<perf>|perf}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_space-{space}][_res-{res}][_den-{den}][_cohort-{cohort}][_desc-{desc}]_{suffix<asl|att|cbf>}{extension<.dtseries.nii|.dscalar.nii|.json|.dscalar.json|.dtseries.json|.func.gii|.func.json>|.dtseries.nii}",
"sub-{subject}[/ses-{session}]/{datatype<figures>|figures}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_space-{space}][_res-{res}][_den-{den}][_cohort-{cohort}][_desc-{desc}]_{suffix<asl|aslref|att|cbf|basil|score|scrub|pvc|mask>}{extension<.svg|.png|.html>|.svg}",
"sub-{subject}[/ses-{session}]/{datatype<perf>|perf}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_space-{space}][_res-{res}][_atlas-{atlas}][_cohort-{cohort}][_desc-{desc}]_{suffix<asl|aslref|abat|abv|att|cbf|coverage|mask>}{extension<.nii|.nii.gz|.json|.csv|.tsv>|.nii.gz}",
"sub-{subject}[/ses-{session}]/{datatype<perf>|perf}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_space-{space}][_res-{res}][_den-{den}][_cohort-{cohort}][_desc-{desc}]_{suffix<asl|abat|abv|att|cbf>}{extension<.dtseries.nii|.dscalar.nii|.json|.dscalar.json|.dtseries.json|.func.gii|.func.json>|.dtseries.nii}",
"sub-{subject}[/ses-{session}]/{datatype<figures>|figures}/sub-{subject}[_ses-{session}][_task-{task}][_acq-{acquisition}][_ce-{ceagent}][_dir-{direction}][_rec-{reconstruction}][_run-{run}][_echo-{echo}][_space-{space}][_res-{res}][_den-{den}][_cohort-{cohort}][_desc-{desc}]_{suffix<asl|aslref|abat|abv|att|cbf|basil|score|scrub|pvc|mask>}{extension<.svg|.png|.html>|.svg}",
"sub-{subject}/{datatype<figures>}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_space-{space}][_atlas-{atlas}][_cohort-{cohort}][_desc-{desc}]_{suffix<T1w|T2w|T1rho|T1map|T2map|T2star|FLAIR|FLASH|PDmap|PD|PDT2|inplaneT[12]|angio|dseg|mask|dwi|epiref|fieldmap>}{extension<.html|.svg|.png>}",
"sub-{subject}/{datatype<figures>}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}][_space-{space}][_atlas-{atlas}][_cohort-{cohort}][_desc-{desc}]_{suffix<dseg|mask|dwi|epiref|fieldmap>}{extension<.html|.svg|.png>}",
"sub-{subject}[/ses-{session}]/{datatype<anat>|anat}/sub-{subject}[_ses-{session}][_acq-{acquisition}][_ce-{ceagent}][_rec-{reconstruction}][_run-{run}]_from-{from}_to-{to}_mode-{mode<image|points>|image}_{suffix<xfm>|xfm}{extension<.txt|.h5|.json>}",
Expand Down
10 changes: 10 additions & 0 deletions aslprep/data/boilerplate.bib
Original file line number Diff line number Diff line change
Expand Up @@ -852,3 +852,13 @@ @article{topup
doi = {10.1016/S1053-8119(03)00336-7},
url = {https://www.sciencedirect.com/science/article/pii/S1053811903003367}
}

@article{woods2023recommendations,
title={Recommendations for quantitative cerebral perfusion MRI using multi-timepoint arterial spin labeling: Acquisition, quantification, and clinical applications},
author={Woods, Joseph G and Achten, Eric and Asllani, Iris and Bolar, Divya S and Dai, Weiying and Detre, John A and Fan, Audrey P and Fern{\'a}ndez-Seara, Maria and Golay, Xavier and G{\"u}nther, Matthias and Guo, Jia and Hernandez-Garcia, Luis and Ho, Mai-Lan and Juttukonda, Meher R. and Lu, Hanzhang and MacIntosh, Bradley J. and Madhuranthakam, Ananth J. and Mutsaerts, Henk J.M.M. and Okell, Thomas W. and Parkes, Laura M. and Pinter, Nandor and Pinto, Joana and Qin, Qin and Smits, Marion and Suzuki, Yuriko and Thomas, David L. and van Osch, Matthias J.P. and Wang, Danny J.J. and Warnert, Esther A.H. and Zaharchuk, Greg and Zelaya, Fernando and Zhao, Moss and Chappell, Michael A.},
year={2023},
journal={OSF Preprints},
publisher={OSF Preprints},
doi={10.31219/osf.io/4tskr},
url={https://doi.org/10.31219/osf.io/4tskr},
}
84 changes: 59 additions & 25 deletions aslprep/interfaces/cbf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,7 @@
estimate_labeling_efficiency,
pcasl_or_pasl,
)
from aslprep.utils.cbf import (
_getcbfscore,
_scrubcbf,
estimate_cbf_pcasl_multipld,
estimate_t1,
)
from aslprep.utils.cbf import _getcbfscore, _scrubcbf, estimate_t1, fit_deltam_multipld


class _RefineMaskInputSpec(BaseInterfaceInputSpec):
Expand Down Expand Up @@ -342,6 +337,16 @@ class _ComputeCBFOutputSpec(TraitedSpec):
None,
desc="Arterial transit time map, in seconds. Only generated for multi-delay data.",
)
abat = traits.Either(
File(exists=True),
None,
desc="Arterial bolus arrival time map, in seconds. Only generated for multi-delay data.",
)
abv = traits.Either(
File(exists=True),
None,
desc="Arterial blood volume map. Only generated for multi-delay data.",
)
plds = traits.Either(
File(exists=True),
None,
Expand Down Expand Up @@ -503,31 +508,47 @@ def _run_interface(self, runtime):
# Broadcast PLDs to voxels by PLDs
plds = np.dot(plds[:, None], np.ones((1, deltam_arr.shape[0]))).T

if is_casl:
tau = np.array(metadata["LabelingDuration"])

if is_multi_pld:
ti1 = None
tau = None
if is_casl:
att, mean_cbf = estimate_cbf_pcasl_multipld(
deltam_arr,
scaled_m0data,
plds,
tau,
labeleff,
t1blood=t1blood,
t1tissue=t1tissue,
unit_conversion=UNIT_CONV,
partition_coefficient=PARTITION_COEF,
)
tau = metadata["LabelingDuration"]

else:
# Dai's approach can't be used on PASL data, so we'll need another method.
raise ValueError(
"Multi-delay data are not supported for PASL sequences at the moment."
)
if metadata["BolusCutOffTechnique"] == "QUIPSSII":
# PASL + QUIPSSII
# Only one BolusCutOffDelayTime allowed.
assert isinstance(metadata["BolusCutOffDelayTime"], Number)
ti1 = metadata["BolusCutOffDelayTime"]

elif metadata["BolusCutOffTechnique"] == "Q2TIPS":
# PASL + Q2TIPS
# Q2TIPS should have two BolusCutOffDelayTimes.
assert len(metadata["BolusCutOffDelayTime"]) == 2
ti1 = metadata["BolusCutOffDelayTime"][0]

mean_cbf_img = masker.inverse_transform(mean_cbf)
else:
raise ValueError(
f"Unsupported BolusCutOffTechnique ({metadata['BolusCutOffTechnique']}) "
"for multi-PLD data."
)

cbf, att, abat, abv = fit_deltam_multipld(
deltam_arr,
scaled_m0data,
plds,
labeleff,
t1blood=t1blood,
partition_coefficient=PARTITION_COEF,
is_casl=is_casl,
tau=tau, # defined for (P)CASL
ti1=ti1, # defined for PASL
)

mean_cbf_img = masker.inverse_transform(cbf)
att_img = masker.inverse_transform(att)
abat_img = masker.inverse_transform(abat)
abv_img = masker.inverse_transform(abv)

# Multi-delay data won't produce a CBF time series
self._results["cbf_ts"] = None
Expand All @@ -537,9 +558,22 @@ def _run_interface(self, runtime):
newpath=runtime.cwd,
)
att_img.to_filename(self._results["att"])
self._results["abat"] = fname_presuffix(
self.inputs.deltam,
suffix="_abat",
newpath=runtime.cwd,
)
abat_img.to_filename(self._results["abat"])
self._results["abv"] = fname_presuffix(
self.inputs.deltam,
suffix="_abv",
newpath=runtime.cwd,
)
abv_img.to_filename(self._results["abv"])

else: # Single-delay
if is_casl:
tau = metadata["LabelingDuration"]
denom_factor = t1blood * (1 - np.exp(-(tau / t1blood)))

elif not metadata["BolusCutOffFlag"]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ sub-01/perf/sub-01_atlas-Tian_desc-basil_cbf.tsv
sub-01/perf/sub-01_atlas-Tian_desc-basil_coverage.tsv
sub-01/perf/sub-01_att.json
sub-01/perf/sub-01_att.nii.gz
sub-01/perf/sub-01_abat.json
sub-01/perf/sub-01_abat.nii.gz
sub-01/perf/sub-01_abv.json
sub-01/perf/sub-01_abv.nii.gz
sub-01/perf/sub-01_cbf.json
sub-01/perf/sub-01_cbf.nii.gz
sub-01/perf/sub-01_desc-basilGM_cbf.json
Expand Down
1 change: 1 addition & 0 deletions aslprep/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def test_examples_pasl_multipld(data_dir, output_dir, working_dir):
f"{os.path.join(data_dir, 'anatomical/smriprep')}",
]

# _run_and_generate(TEST_NAME, PARTICIPANT_LABEL, parameters, out_dir)
_run_and_fail(parameters)


Expand Down
Loading