[ENH]: Add support for native space #252

Merged
synchon merged 13 commits from feat/native-space-support into main 2023-10-27 09:49:49 +00:00
8 changed files with 133 additions and 17 deletions

View file

@ -0,0 +1 @@
Add ``native_t1w`` parameter to :class:`.DataladAOMICID1000`, :class:`.DataladAOMICPIOP1`, :class:`.DataladAOMICPIOP2`, enabling fetching of T1w data in subject-native space by `Synchon Mandal`_

View file

@ -0,0 +1 @@
Add support for subject-native space by `Synchon Mandal`_ and `Fede Raimondo`_

View file

@ -28,6 +28,8 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
"probseg_WM", "DWI"} or a list of the options, optional
AOMIC data types. If None, all available data types are selected.
(default None).
native_t1w : bool, optional
Whether to use T1w in native space (default False).
"""
@ -35,6 +37,7 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
self,
datadir: Union[str, Path, None] = None,
types: Union[str, List[str], None] = None,
native_t1w: bool = False,
) -> None:
# The patterns
patterns = {
@ -84,6 +87,27 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
"sub-{subject}_desc-preproc_dwi.nii.gz"
),
}
# Use native T1w assets
self.native_t1w = False
if native_t1w:
self.native_t1w = True
patterns.update(
{
"T1w": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_desc-preproc_T1w.nii.gz"
),
"T1w_mask": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_desc-brain_mask.nii.gz"
),
"Warp": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_from-MNI152NLin2009cAsym_to-T1w_"
"mode-image_xfm.h5"
),
}
)
# Set default types
if types is None:
types = list(patterns.keys())
@ -126,5 +150,8 @@ class DataladAOMICID1000(PatternDataladDataGrabber):
if out.get("T1w"):
out["T1w"]["mask_item"] = "T1w_mask"
# Add space information
if self.native_t1w:
out["T1w"].update({"space": "native"})
else:
out["T1w"].update({"space": "MNI152NLin2009cAsym"})
return out

View file

@ -34,6 +34,8 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
"gstroop", "workingmemory"} or list of the options, optional
AOMIC PIOP1 task sessions. If None, all available task sessions are
selected (default None).
native_t1w : bool, optional
Whether to use T1w in native space (default False).
"""
@ -42,6 +44,7 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
datadir: Union[str, Path, None] = None,
types: Union[str, List[str], None] = None,
tasks: Union[str, List[str], None] = None,
native_t1w: bool = False,
) -> None:
# Declare all tasks
all_tasks = [
@ -114,6 +117,27 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
"sub-{subject}_desc-preproc_dwi.nii.gz"
),
}
# Use native T1w assets
self.native_t1w = False
if native_t1w:
self.native_t1w = True
patterns.update(
{
"T1w": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_desc-preproc_T1w.nii.gz"
),
"T1w_mask": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_desc-brain_mask.nii.gz"
),
"Warp": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_from-MNI152NLin2009cAsym_to-T1w_"
"mode-image_xfm.h5"
),
}
)
# Set default types
if types is None:
types = list(patterns.keys())
@ -171,7 +195,10 @@ class DataladAOMICPIOP1(PatternDataladDataGrabber):
if out.get("T1w"):
out["T1w"]["mask_item"] = "T1w_mask"
# Add space information
if self.native_t1w:
out["T1w"].update({"space": "native"})
else:
out["T1w"].update({"space": "MNI152NLin2009cAsym"})
return out
def get_elements(self) -> List:

View file

@ -34,6 +34,8 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
or list of the options, optional
AOMIC PIOP2 task sessions. If None, all available task sessions are
selected (default None).
native_t1w : bool, optional
Whether to use T1w in native space (default False).
"""
@ -42,6 +44,7 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
datadir: Union[str, Path, None] = None,
types: Union[str, List[str], None] = None,
tasks: Union[str, List[str], None] = None,
native_t1w: bool = False,
) -> None:
# Declare all tasks
all_tasks = [
@ -111,6 +114,27 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
"sub-{subject}_desc-preproc_dwi.nii.gz"
),
}
# Use native T1w assets
self.native_t1w = False
if native_t1w:
self.native_t1w = True
patterns.update(
{
"T1w": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_desc-preproc_T1w.nii.gz"
),
"T1w_mask": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_desc-brain_mask.nii.gz"
),
"Warp": (
"derivatives/fmriprep/sub-{subject}/anat/"
"sub-{subject}_from-MNI152NLin2009cAsym_to-T1w_"
"mode-image_xfm.h5"
),
}
)
# Set default types
if types is None:
types = list(patterns.keys())
@ -171,5 +195,8 @@ class DataladAOMICPIOP2(PatternDataladDataGrabber):
if out.get("T1w"):
out["T1w"]["mask_item"] = "T1w_mask"
# Add space information
if self.native_t1w:
out["T1w"].update({"space": "native"})
else:
out["T1w"].update({"space": "MNI152NLin2009cAsym"})
return out

View file

@ -98,7 +98,7 @@ class HCP1200(PatternDataGrabber):
)
suffix = "_hp2000_clean" if ica_fix else ""
# The types of data
types = ["BOLD"]
types = ["BOLD", "T1w", "Warp"]
# The patterns
patterns = {
"BOLD": (
@ -106,7 +106,9 @@ class HCP1200(PatternDataGrabber):
"{task}_{phase_encoding}/"
"{task}_{phase_encoding}"
f"{suffix}.nii.gz"
)
),
"T1w": "{subject}/T1w/T1w_acpc_dc_restore.nii.gz",
"Warp": "{subject}/MNINonLinear/xfms/standard2acpc_dc.nii.gz",
}
# The replacements
replacements = ["subject", "task", "phase_encoding"]
@ -147,6 +149,12 @@ class HCP1200(PatternDataGrabber):
out = super().get_item(
subject=subject, task=new_task, phase_encoding=phase_encoding
)
# Add space for BOLD data type
if "BOLD" in out:
out["BOLD"].update({"space": "MNI152NLin6Asym"})
# Add space for T1w data type
if "T1w" in out:
out["T1w"].update({"space": "native"})
return out
def get_elements(self) -> List:

View file

@ -104,6 +104,10 @@ class DefaultDataReader(PipelineStepMixin, UpdateMetaMixin):
params = {}
# For each type of data, try to read it
for type_ in input.keys():
# Skip Warp data type
if type_ == "Warp":
continue
# Check for malformed datagrabber specification
if "path" not in input[type_]:
warn_with_log(

View file

@ -4,8 +4,8 @@
# License: AGPL
from itertools import product
from tempfile import TemporaryDirectory
from pathlib import Path
from tempfile import TemporaryDirectory
import datalad.api as dl
@ -15,7 +15,6 @@ DST = "git@gin.g-node.org:/juaml/datalad-example-hcp1200.git"
if __name__ == "__main__":
with TemporaryDirectory() as tmpdir:
# Convert str to Path
tmpdir_path = Path(tmpdir)
@ -29,7 +28,30 @@ if __name__ == "__main__":
# Create subject directory
subdir.mkdir()
for (task, phase_encoding) in product(
# T1w data
# Set subject data directory
sub_t1w_datadir = subdir / "T1w"
# Create subject data directory
sub_t1w_datadir.mkdir(parents=True)
# Set subject data file
sub_t1w_datafile = sub_t1w_datadir / "T1w_acpc_dc_restore.nii.gz"
# Write subject data file
with open(sub_t1w_datafile, "w") as f:
f.write("placeholder")
# Warp data
# Set subject data directory
sub_warp_datadir = subdir / "MNINonLinear" / "xfms"
# Create subject data directory
sub_warp_datadir.mkdir(parents=True)
# Set subject data file
sub_warp_datafile = sub_warp_datadir / "standard2acpc_dc.nii.gz"
# Write subject data file
with open(sub_warp_datafile, "w") as f:
f.write("placeholder")
# BOLD data
for task, phase_encoding in product(
[
"REST1",
"REST2",
@ -49,32 +71,31 @@ if __name__ == "__main__":
else:
new_task = f"tfMRI_{task}"
# Set subject data directory
sub_datadir = (
sub_bold_datadir = (
subdir
/ "MNINonLinear"
/ "Results"
/ f"{new_task}_{phase_encoding}"
)
# Create subject data directory
sub_datadir.mkdir(parents=True)
sub_bold_datadir.mkdir(parents=True)
# Set subject data file
sub_datafile = (
sub_datadir
/ f"{new_task}_{phase_encoding}.nii.gz"
sub_bold_datafile = (
sub_bold_datadir / f"{new_task}_{phase_encoding}.nii.gz"
)
# Create subject data file
with open(sub_datafile, "w") as f:
with open(sub_bold_datafile, "w") as f:
f.write("placeholder")
if "REST" in task:
# Set subject data file with ICA+FIX
sub_datafile = (
sub_datadir
sub_bold_datafile = (
sub_bold_datadir
/ f"{new_task}_{phase_encoding}_hp2000_clean.nii.gz"
)
# Create subject data file with ICA+FIX
with open(sub_datafile, "w") as f:
with open(sub_bold_datafile, "w") as f:
f.write("placeholder")
# Save datalad dataset