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

Disable SCORE/SCRUB for GE/short runs and get GE workflow working #248

Merged
merged 44 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
17ced31
Prepare for new tests.
tsalo Mar 31, 2023
0b42bca
Fix.
tsalo Mar 31, 2023
37f849f
Update config.yml
tsalo Mar 31, 2023
8416c10
Fix again.
tsalo Mar 31, 2023
61f67cc
Update config.yml
tsalo Mar 31, 2023
c5f799e
Update cbf.py
tsalo Mar 31, 2023
d6c7d42
Update pyproject.toml
tsalo Mar 31, 2023
26bf7d1
Try that.
tsalo Mar 31, 2023
4944118
Merge remote-tracking branch 'upstream/main' into more-test-data
tsalo Mar 31, 2023
2499b99
Update gecbf.py
tsalo Mar 31, 2023
d8ee95b
Update cbf_computation.py
tsalo Apr 1, 2023
ac7c1da
Update bids.py
tsalo Apr 1, 2023
8a54b59
Update bids.py
tsalo Apr 1, 2023
be76e3f
Update unit tests.
tsalo Apr 1, 2023
e6b4f97
Extract m0tr for GE data.
tsalo Apr 1, 2023
8b918c4
Remove undefined connection.
tsalo Apr 1, 2023
6b2aab3
Update config.yml
tsalo Apr 1, 2023
0baf10b
Patch in aslcontext.
tsalo Apr 1, 2023
add4356
Save M0 file.
tsalo Apr 1, 2023
05617d3
Fix test.
tsalo Apr 1, 2023
ec7bb6e
Okay, maybe fix that now.
tsalo Apr 1, 2023
68be1fc
Enable debug mode.
tsalo Apr 1, 2023
d9dc89a
Connect things better.
tsalo Apr 1, 2023
2d6518a
Update qc.py
tsalo Apr 1, 2023
71d53ee
Update cbf_computation.py
tsalo Apr 1, 2023
707512d
Update stuff.
tsalo Apr 2, 2023
7aae24b
Update test_cli.py
tsalo Apr 2, 2023
7fc18f4
Expect errors.
tsalo Apr 2, 2023
3905c7d
Update expected outputs.
tsalo Apr 2, 2023
cd0571a
Update test_cli.py
tsalo Apr 2, 2023
ec8718b
Document tests.
tsalo Apr 3, 2023
a76d71d
Disable SCORE/SCRUB for GE data.
tsalo Apr 3, 2023
6e40471
Update expected outputs for GE scans.
tsalo Apr 3, 2023
ebd46b3
Remove unused import.
tsalo Apr 3, 2023
220963c
Update gecbf.py
tsalo Apr 3, 2023
b1de1d7
I had the workflows swapped.
tsalo Apr 3, 2023
a9d40c0
Update expected_outputs_examples_pcasl_singlepld_ge.txt
tsalo Apr 3, 2023
a51216b
I guess we don't get confound regressors with GE?
tsalo Apr 3, 2023
d73c642
Split up pcasl singlepld test.
tsalo Apr 3, 2023
9d72646
Streamline test code.
tsalo Apr 3, 2023
1fa5bb5
Update test_cli.py
tsalo Apr 3, 2023
5c430b6
Update test_cli.py
tsalo Apr 3, 2023
28766fe
Expect the report.
tsalo Apr 3, 2023
6b0e74c
Expect the boilerplates.
tsalo Apr 3, 2023
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
458 changes: 425 additions & 33 deletions .circleci/config.yml

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions .circleci/get_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python3
"""Download test data."""
import sys

from aslprep.tests.utils import download_test_data

if __name__ == "__main__":
data_dir = sys.argv[1]
dset = sys.argv[2]
download_test_data(dset, data_dir)
90 changes: 0 additions & 90 deletions .circleci/get_data.sh

This file was deleted.

181 changes: 91 additions & 90 deletions aslprep/interfaces/cbf_computation.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ def _run_interface(self, runtime):
# extract m0 file and register it to ASL if separate
if metadata["M0Type"] == "Separate":
m0file = self.inputs.m0scan
m0file_metadata = self.inputs.m0scan_metadata

m0_in_asl = fname_presuffix(self.inputs.asl_file, suffix="_m0file")
m0_in_asl = regmotoasl(asl=self.inputs.asl_file, m0file=m0file, m02asl=m0_in_asl)
Expand All @@ -162,7 +161,7 @@ def _run_interface(self, runtime):
else:
m0data = mask_data * m0data_smooth

m0tr = m0file_metadata["RepetitionTimePreparation"]
m0tr = self.inputs.m0scan_metadata["RepetitionTimePreparation"]
if np.array(m0tr).size > 1 and np.std(m0tr) > 0:
raise ValueError("M0 scans have variable TR. ASLPrep does not support this.")

Expand Down Expand Up @@ -193,8 +192,6 @@ def _run_interface(self, runtime):
control_img = smooth_image(control_img, fwhm=self.inputs.fwhm).get_fdata()
m0data = mask_data * np.mean(control_img, axis=3)

m0tr = None

elif cbf_volume_idx:
# If we have precalculated CBF data, we don't need M0, so we'll just use the mask.
m0data = mask_data
Expand All @@ -205,6 +202,8 @@ def _run_interface(self, runtime):
"and there are no control volumes that can be used as a substitute"
)

m0tr = None

else:
raise RuntimeError("no pathway to m0scan")

Expand Down Expand Up @@ -279,6 +278,92 @@ def _run_interface(self, runtime):
return runtime


class _ExtractCBForDeltaMInputSpec(BaseInterfaceInputSpec):
asl_file = File(exists=True, mandatory=True, desc="raw asl file")
aslcontext = File(exists=True, mandatory=True, desc="aslcontext TSV file for run.")
in_aslmask = 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")


class ExtractCBForDeltaM(SimpleInterface):
"""Load an ASL file and grab the CBF or DeltaM volumes from it."""

input_spec = _ExtractCBForDeltaMInputSpec
output_spec = _ExtractCBForDeltaMOutputSpec

def _run_interface(self, runtime):
self._results["out_file"] = fname_presuffix(
self.inputs.in_aslmask,
suffix="_cbfdeltam",
newpath=runtime.cwd,
)
asl_img = nb.load(self.inputs.asl_file)
asl_data = asl_img.get_fdata()

aslcontext = pd.read_table(self.inputs.aslcontext)
vol_types = aslcontext["volume_type"].tolist()
control_volume_idx = [i for i, vol_type in enumerate(vol_types) if vol_type == "control"]
label_volume_idx = [i for i, vol_type in enumerate(vol_types) if vol_type == "label"]
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":
if len(control_volume_idx) > 0:
# Grab control and label volumes from ASL file,
# then calculate deltaM by subtracting label volumes from control volumes.
deltam_data = (
asl_data[:, :, :, control_volume_idx] - asl_data[:, :, :, label_volume_idx]
)
out_img = nb.Nifti1Image(
dataobj=deltam_data,
affine=asl_img.affine,
header=asl_img.header,
)
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]
out_img = nb.Nifti1Image(
dataobj=cbf_data,
affine=asl_img.affine,
header=asl_img.header,
)

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

return runtime


class _ComputeCBFInputSpec(BaseInterfaceInputSpec):
deltam = File(
exists=True,
Expand Down Expand Up @@ -1071,6 +1156,7 @@ def _run_interface(self, runtime):
dict1 = {
"FD": 0,
"relRMS": 0,
"rmsd": np.nan,
"coregDC": [regDC],
"coregJC": [regJC],
"coregCC": [regCC],
Expand All @@ -1097,6 +1183,7 @@ def _run_interface(self, runtime):
dict1 = {
"FD": 0,
"relRMS": 0,
"rmsd": np.nan,
"coregDC": [regDC],
"coregJC": [regJC],
"coregCC": [regCC],
Expand Down Expand Up @@ -1172,92 +1259,6 @@ def _run_interface(self, runtime):
return runtime


class _ExtractCBForDeltaMInputSpec(BaseInterfaceInputSpec):
asl_file = File(exists=True, mandatory=True, desc="raw asl file")
aslcontext = File(exists=True, mandatory=True, desc="aslcontext TSV file for run.")
in_aslmask = 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")


class ExtractCBForDeltaM(SimpleInterface):
"""Load an ASL file and grab the CBF or DeltaM volumes from it."""

input_spec = _ExtractCBForDeltaMInputSpec
output_spec = _ExtractCBForDeltaMOutputSpec

def _run_interface(self, runtime):
self._results["out_file"] = fname_presuffix(
self.inputs.in_aslmask,
suffix="_cbfdeltam",
newpath=runtime.cwd,
)
asl_img = nb.load(self.inputs.asl_file)
asl_data = asl_img.get_fdata()

aslcontext = pd.read_table(self.inputs.aslcontext)
vol_types = aslcontext["volume_type"].tolist()
control_volume_idx = [i for i, vol_type in enumerate(vol_types) if vol_type == "control"]
label_volume_idx = [i for i, vol_type in enumerate(vol_types) if vol_type == "label"]
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":
if len(control_volume_idx) > 0:
# Grab control and label volumes from ASL file,
# then calculate deltaM by subtracting label volumes from control volumes.
deltam_data = (
asl_data[:, :, :, control_volume_idx] - asl_data[:, :, :, label_volume_idx]
)
out_img = nb.Nifti1Image(
dataobj=deltam_data,
affine=asl_img.affine,
header=asl_img.header,
)
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]
out_img = nb.Nifti1Image(
dataobj=cbf_data,
affine=asl_img.affine,
header=asl_img.header,
)

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

return runtime


def regmotoasl(asl, m0file, m02asl):
"""Calculate mean M0 image and mean ASL image, then FLIRT M0 image to ASL space.

Expand Down
Loading