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

ENH: Add sphere registration to fit workflow, check for precomputed #370

Merged
merged 15 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 6 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ _machine_defaults: &machine_defaults
_python_defaults: &python_defaults
docker:
- image: cimg/python:3.10.9
auth:
username: $DOCKER_USER
password: $DOCKER_PAT
working_directory: /tmp/src/smriprep

_docker_auth: &docker_auth
Expand Down Expand Up @@ -43,6 +46,9 @@ _pull_from_registry: &pull_from_registry
docs_deploy: &docs
docker:
- image: node:8.10.0
auth:
username: $DOCKER_USER
password: $DOCKER_PAT
working_directory: /tmp/gh-pages
steps:
- run:
Expand Down
3 changes: 3 additions & 0 deletions .circleci/ds005_outputs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ smriprep/sub-01/anat/sub-01_desc-brain_mask.json
smriprep/sub-01/anat/sub-01_desc-brain_mask.nii.gz
smriprep/sub-01/anat/sub-01_desc-preproc_T1w.json
smriprep/sub-01/anat/sub-01_desc-preproc_T1w.nii.gz
smriprep/sub-01/anat/sub-01_desc-ribbon_mask.json
smriprep/sub-01/anat/sub-01_desc-ribbon_mask.nii.gz
smriprep/sub-01/anat/sub-01_dseg.nii.gz
smriprep/sub-01/anat/sub-01_from-fsnative_to-T1w_mode-image_xfm.txt
Expand All @@ -27,6 +28,7 @@ smriprep/sub-01/anat/sub-01_hemi-L_midthickness.surf.gii
smriprep/sub-01/anat/sub-01_hemi-L_pial.surf.gii
smriprep/sub-01/anat/sub-01_hemi-L_space-fsLR_desc-msmsulc_sphere.surf.gii
smriprep/sub-01/anat/sub-01_hemi-L_space-fsLR_desc-reg_sphere.surf.gii
smriprep/sub-01/anat/sub-01_hemi-L_sphere.surf.gii
smriprep/sub-01/anat/sub-01_hemi-L_sulc.shape.gii
smriprep/sub-01/anat/sub-01_hemi-L_thickness.shape.gii
smriprep/sub-01/anat/sub-01_hemi-L_white.surf.gii
Expand All @@ -37,6 +39,7 @@ smriprep/sub-01/anat/sub-01_hemi-R_midthickness.surf.gii
smriprep/sub-01/anat/sub-01_hemi-R_pial.surf.gii
smriprep/sub-01/anat/sub-01_hemi-R_space-fsLR_desc-msmsulc_sphere.surf.gii
smriprep/sub-01/anat/sub-01_hemi-R_space-fsLR_desc-reg_sphere.surf.gii
smriprep/sub-01/anat/sub-01_hemi-R_sphere.surf.gii
smriprep/sub-01/anat/sub-01_hemi-R_sulc.shape.gii
smriprep/sub-01/anat/sub-01_hemi-R_thickness.shape.gii
smriprep/sub-01/anat/sub-01_hemi-R_white.surf.gii
Expand Down
105 changes: 64 additions & 41 deletions smriprep/data/io_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,68 +70,91 @@
"mode": "image"
}
},
"std_xfms": {
"anat2std_xfm": {
"surfaces": {
"white": {
"datatype": "anat",
"extension": "h5",
"from": "T1w",
"to": [],
"suffix": "xfm",
"mode": "image"
"hemi": ["L", "R"],
"space": null,
"suffix": "white",
"extension": ".surf.gii"
},
"std2anat_xfm": {
"pial": {
"datatype": "anat",
"extension": "h5",
"from": [],
"to": "T1w",
"suffix": "xfm",
"mode": "image"
}
},
"surfaces": {
"t1w_aseg": {
"hemi": ["L", "R"],
"space": null,
"suffix": "pial",
"extension": ".surf.gii"
},
"midthickness": {
"datatype": "anat",
"desc": "aseg",
"suffix": "dseg"
"hemi": ["L", "R"],
"space": null,
"suffix": "midthickness",
"extension": ".surf.gii"
},
"t1w_aparc": {
"sphere": {
"datatype": "anat",
"desc": "aparcaseg",
"suffix": "dseg"
"hemi": ["L", "R"],
"space": null,
"desc": null,
"suffix": "sphere",
"extension": ".surf.gii"
},
"t1w2fsnative_xfm": {
"thickness": {
"datatype": "anat",
"from": "T1w",
"to": "fsnative",
"extension": "txt",
"suffix": "xfm",
"mode": "image"
"hemi": ["L", "R"],
"space": null,
"suffix": "thickness",
"extension": ".shape.gii"
},
"fsnative2t1w_xfm": {
"sulc": {
"datatype": "anat",
"from": "fsnative",
"to": "T1w",
"extension": "txt",
"suffix": "xfm",
"mode": "image"
"hemi": ["L", "R"],
"space": null,
"suffix": "sulc",
"extension": ".shape.gii"
},
"surfaces": {
"curv": {
"datatype": "anat",
"hemi": ["L", "R"],
"extension": "surf.gii",
"suffix": [ "inflated", "midthickness", "pial", "white"]
"space": null,
"suffix": "curv",
"extension": ".shape.gii"
},
"morphometrics": {
"sphere_reg": {
"datatype": "anat",
"hemi": ["L", "R"],
"extension": "shape.gii",
"suffix": ["thickness", "sulc", "curv"]
"space": null,
"desc": "reg",
"suffix": "sphere",
"extension": ".surf.gii"
},
"sphere_reg_fsLR": {
"datatype": "anat",
"hemi": ["L", "R"],
"space": "fsLR",
"desc": "reg",
"suffix": "sphere",
"extension": ".surf.gii"
},
"sphere_reg_msm": {
"datatype": "anat",
"hemi": ["L", "R"],
"space": "fsLR",
"desc": "msmsulc",
"suffix": "sphere",
"extension": ".surf.gii"
}
},
"masks": {
"anat_ribbon": {
"datatype": "anat",
"desc": "ribbon",
"suffix": "mask",
"extension": "nii.gz"
"extension": [
".nii.gz",
".nii"
]
}
}
},
Expand Down
76 changes: 8 additions & 68 deletions smriprep/utils/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,39 +21,13 @@
# https://www.nipreps.org/community/licensing/
#
"""Utilities to handle BIDS inputs."""
from collections import defaultdict
from pathlib import Path
from json import loads
from pkg_resources import resource_filename as pkgrf
from bids.layout import BIDSLayout
from bids.layout.writing import build_path


def get_outputnode_spec():
"""
Generate outputnode's fields from I/O spec file.

Examples
--------
>>> get_outputnode_spec() # doctest: +NORMALIZE_WHITESPACE
['t1w_preproc', 't1w_mask', 't1w_dseg', 't1w_tpms',
'std_preproc', 'std_mask', 'std_dseg', 'std_tpms',
'anat2std_xfm', 'std2anat_xfm',
't1w_aseg', 't1w_aparc',
't1w2fsnative_xfm', 'fsnative2t1w_xfm',
'surfaces', 'morphometrics', 'anat_ribbon']

"""
spec = loads(Path(pkgrf("smriprep", "data/io_spec.json")).read_text())["queries"]
fields = ["_".join((m, s)) for m in ("t1w", "std") for s in spec["baseline"].keys()]
fields += [s for s in spec["std_xfms"].keys()]
fields += [s for s in spec["surfaces"].keys()]
return fields


def collect_derivatives(
derivatives_dir, subject_id, std_spaces, freesurfer, spec=None, patterns=None
):
def collect_derivatives(derivatives_dir, subject_id, std_spaces, spec=None, patterns=None):
"""Gather existing derivatives and compose a cache."""
if spec is None or patterns is None:
_spec, _patterns = tuple(
Expand All @@ -65,27 +39,9 @@
if patterns is None:
patterns = _patterns

derivs_cache = defaultdict(list, {})
layout = BIDSLayout(derivatives_dir, config=["bids", "derivatives"], validate=False)
derivatives_dir = Path(derivatives_dir)

def _check_item(item):
if not item:
return None

if isinstance(item, str):
item = [item]

result = []
for i in item:
if not (derivatives_dir / i).exists():
i = i.rstrip(".gz")
if not (derivatives_dir / i).exists():
return None
result.append(str(derivatives_dir / i))

return result

derivs_cache = {}

Check warning on line 44 in smriprep/utils/bids.py

View check run for this annotation

Codecov / codecov/patch

smriprep/utils/bids.py#L44

Added line #L44 was not covered by tests
for k, q in spec["baseline"].items():
q["subject"] = subject_id
item = layout.get(return_type='filename', **q)
Expand All @@ -94,18 +50,6 @@

derivs_cache["t1w_%s" % k] = item[0] if len(item) == 1 else item

for space in std_spaces:
for k, q in spec["std_xfms"].items():
q["subject"] = subject_id
q["from"] = q["from"] or space
q["to"] = q["to"] or space
item = layout.get(return_type='filename', **q)
if not item:
continue
derivs_cache[k] += item

derivs_cache = dict(derivs_cache) # Back to a standard dictionary

transforms = derivs_cache.setdefault('transforms', {})
for space in std_spaces:
for k, q in spec["transforms"].items():
Expand All @@ -118,18 +62,14 @@
continue
transforms.setdefault(space, {})[k] = item[0] if len(item) == 1 else item

if freesurfer:
for k, q in spec["surfaces"].items():
q["subject"] = subject_id
item = _check_item(build_path(q, patterns))
if not item:
continue
for k, q in spec["surfaces"].items():
q["subject"] = subject_id
item = layout.get(return_type='filename', **q)

Check warning on line 67 in smriprep/utils/bids.py

View check run for this annotation

Codecov / codecov/patch

smriprep/utils/bids.py#L66-L67

Added lines #L66 - L67 were not covered by tests
if not item or len(item) != 2:
continue

Check warning on line 69 in smriprep/utils/bids.py

View check run for this annotation

Codecov / codecov/patch

smriprep/utils/bids.py#L69

Added line #L69 was not covered by tests

if len(item) == 1:
item = item[0]
derivs_cache[k] = item
derivs_cache[k] = sorted(item)

Check warning on line 71 in smriprep/utils/bids.py

View check run for this annotation

Codecov / codecov/patch

smriprep/utils/bids.py#L71

Added line #L71 was not covered by tests

derivs_cache["template"] = std_spaces
return derivs_cache


Expand Down
Loading
Loading