Skip to content

Commit 2355035

Browse files
mgxdeffigies
andauthored
FIX: Re-add cohort identifier to template name (#416)
* FIX: Re-add cohort identifier to template name * FIX: XFM io * FIX: Query data with nipreps config Also rename variables to play nice with pdb * TST: Add test for derivatives ingestion * PIN: niworkflows latest * MAINT: Update ruff settings * STY: ruff fixes * TST: Ensure config is string * Apply suggestions from code review Co-authored-by: Chris Markiewicz <[email protected]> --------- Co-authored-by: Chris Markiewicz <[email protected]>
1 parent 51da19b commit 2355035

File tree

7 files changed

+183
-25
lines changed

7 files changed

+183
-25
lines changed

pyproject.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ dependencies = [
2525
"matplotlib >= 2.2.0",
2626
"nibabel >= 4.0.1",
2727
"nipype >= 1.7.0",
28-
"niworkflows >= 1.8.0",
28+
"niworkflows @ git+https://github.com/nipreps/niworkflows.git@master",
2929
"numpy",
3030
"packaging",
3131
"pybids >= 0.11.1",
@@ -138,6 +138,8 @@ source = [
138138

139139
[tool.ruff]
140140
line-length = 99
141+
142+
[tool.ruff.lint]
141143
extend-select = [
142144
"F",
143145
"E",
@@ -162,10 +164,10 @@ extend-select = [
162164
"Q",
163165
]
164166

165-
[tool.ruff.flake8-quotes]
167+
[tool.ruff.lint.flake8-quotes]
166168
inline-quotes = "single"
167169

168-
[tool.ruff.extend-per-file-ignores]
170+
[tool.ruff.lint.extend-per-file-ignores]
169171
"*/test_*.py" = ["S101"]
170172

171173
[tool.ruff.format]

smriprep/data/io_spec.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@
5050
"forward": {
5151
"datatype": "anat",
5252
"extension": [
53-
"h5",
54-
"txt"
53+
".h5",
54+
".txt"
5555
],
5656
"from": "T1w",
5757
"to": null,
@@ -61,8 +61,8 @@
6161
"reverse": {
6262
"datatype": "anat",
6363
"extension": [
64-
"h5",
65-
"txt"
64+
".h5",
65+
".txt"
6666
],
6767
"from": null,
6868
"to": "T1w",

smriprep/utils/bids.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from pathlib import Path
2626

2727
from bids.layout import BIDSLayout
28+
from niworkflows.data import load as nwf_load
2829

2930
from ..data import load_resource
3031

@@ -39,36 +40,38 @@ def collect_derivatives(derivatives_dir, subject_id, std_spaces, spec=None, patt
3940
if patterns is None:
4041
patterns = _patterns
4142

42-
layout = BIDSLayout(derivatives_dir, config=['bids', 'derivatives'], validate=False)
43+
deriv_config = nwf_load('nipreps.json')
44+
layout = BIDSLayout(derivatives_dir, config=deriv_config, validate=False)
4345

4446
derivs_cache = {}
45-
for k, q in spec['baseline'].items():
46-
q['subject'] = subject_id
47-
item = layout.get(return_type='filename', **q)
47+
for key, qry in spec['baseline'].items():
48+
qry['subject'] = subject_id
49+
item = layout.get(return_type='filename', **qry)
4850
if not item:
4951
continue
5052

51-
derivs_cache['t1w_%s' % k] = item[0] if len(item) == 1 else item
53+
derivs_cache[f't1w_{key}'] = item[0] if len(item) == 1 else item
5254

5355
transforms = derivs_cache.setdefault('transforms', {})
54-
for space in std_spaces:
55-
for k, q in spec['transforms'].items():
56-
q = q.copy()
57-
q['subject'] = subject_id
58-
q['from'] = q['from'] or space
59-
q['to'] = q['to'] or space
60-
item = layout.get(return_type='filename', **q)
56+
for _space in std_spaces:
57+
space = _space.replace(':cohort-', '+')
58+
for key, qry in spec['transforms'].items():
59+
qry = qry.copy()
60+
qry['subject'] = subject_id
61+
qry['from'] = qry['from'] or space
62+
qry['to'] = qry['to'] or space
63+
item = layout.get(return_type='filename', **qry)
6164
if not item:
6265
continue
63-
transforms.setdefault(space, {})[k] = item[0] if len(item) == 1 else item
66+
transforms.setdefault(_space, {})[key] = item[0] if len(item) == 1 else item
6467

65-
for k, q in spec['surfaces'].items():
66-
q['subject'] = subject_id
67-
item = layout.get(return_type='filename', **q)
68+
for key, qry in spec['surfaces'].items():
69+
qry['subject'] = subject_id
70+
item = layout.get(return_type='filename', **qry)
6871
if not item or len(item) != 2:
6972
continue
7073

71-
derivs_cache[k] = sorted(item)
74+
derivs_cache[key] = sorted(item)
7275

7376
return derivs_cache
7477

smriprep/utils/tests/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from niworkflows.data import Loader
2+
3+
load_data = Loader(__package__)
4+
5+
DERIV_SKELETON = load_data('derivatives.yml')

smriprep/utils/tests/derivatives.yml

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
dataset_description:
2+
Name: smriprep-outputs
3+
BIDSVersion: 1.9.0
4+
DatasetType: derivative
5+
'01':
6+
anat:
7+
- suffix: mask
8+
desc: brain
9+
- suffix: T1w
10+
desc: preproc
11+
- suffix: dseg
12+
- suffix: probseg
13+
label: CSF
14+
- suffix: probseg
15+
label: GM
16+
- suffix: probseg
17+
label: WM
18+
- suffix: xfm
19+
from: MNI152NLin2009cAsym
20+
to: T1w
21+
mode: image
22+
extension: .h5
23+
- suffix: xfm
24+
from: T1w
25+
to: MNI152NLin2009cAsym
26+
mode: image
27+
extension: .h5
28+
- suffix: xfm
29+
from: T1w
30+
to: MNIPediatricAsym+3
31+
mode: image
32+
extension: .h5
33+
- suffix: xfm
34+
from: MNIPediatricAsym+3
35+
to: T1w
36+
mode: image
37+
extension: .h5
38+
- suffix: white
39+
hemi: L
40+
extension: .surf.gii
41+
- suffix: white
42+
hemi: R
43+
extension: .surf.gii
44+
- suffix: pial
45+
hemi: L
46+
extension: .surf.gii
47+
- suffix: pial
48+
hemi: R
49+
extension: .surf.gii
50+
- suffix: midthickness
51+
hemi: L
52+
extension: .surf.gii
53+
- suffix: midthickness
54+
hemi: R
55+
extension: .surf.gii
56+
- suffix: sphere
57+
hemi: L
58+
extension: .surf.gii
59+
- suffix: sphere
60+
hemi: R
61+
extension: .surf.gii
62+
- suffix: sphere
63+
hemi: L
64+
desc: reg
65+
extension: .surf.gii
66+
- suffix: sphere
67+
hemi: R
68+
desc: reg
69+
extension: .surf.gii
70+
- suffix: sphere
71+
hemi: L
72+
space: fsLR
73+
desc: reg
74+
extension: .surf.gii
75+
- suffix: sphere
76+
hemi: R
77+
space: fsLR
78+
desc: reg
79+
extension: .surf.gii
80+
- suffix: sphere
81+
hemi: L
82+
space: fsLR
83+
desc: msmsulc
84+
extension: .surf.gii
85+
- suffix: sphere
86+
hemi: R
87+
space: fsLR
88+
desc: msmsulc
89+
extension: .surf.gii
90+
- suffix: thickness
91+
hemi: L
92+
extension: .shape.gii
93+
- suffix: thickness
94+
hemi: R
95+
extension: .shape.gii
96+
- suffix: sulc
97+
hemi: L
98+
extension: .shape.gii
99+
- suffix: sulc
100+
hemi: R
101+
extension: .shape.gii

smriprep/utils/tests/test_bids.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from niworkflows.utils.testing import generate_bids_skeleton
2+
3+
from ..bids import collect_derivatives
4+
from . import DERIV_SKELETON
5+
6+
7+
def test_collect_derivatives(tmp_path):
8+
deriv_dir = tmp_path / 'derivatives'
9+
generate_bids_skeleton(deriv_dir, str(DERIV_SKELETON))
10+
output_spaces = ['MNI152NLin2009cAsym', 'MNIPediatricAsym:cohort-3']
11+
collected = collect_derivatives(deriv_dir, '01', output_spaces)
12+
for suffix in ('preproc', 'mask', 'dseg'):
13+
assert collected[f't1w_{suffix}']
14+
assert len(collected['t1w_tpms']) == 3
15+
xfms = collected['transforms']
16+
for space in output_spaces:
17+
assert xfms[space]['reverse']
18+
assert xfms[space]['forward']
19+
for surface in (
20+
'white',
21+
'pial',
22+
'midthickness',
23+
'sphere',
24+
'thickness',
25+
'sulc',
26+
'sphere_reg',
27+
'sphere_reg_fsLR',
28+
'sphere_reg_msm',
29+
):
30+
assert len(collected[surface]) == 2

smriprep/workflows/fit/registration.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ def init_register_template_wf(
185185
mem_gb=2,
186186
)
187187

188+
fmt_cohort = pe.Node(
189+
niu.Function(function=_fmt_cohort, output_names=['template', 'spec']),
190+
name='fmt_cohort',
191+
run_without_submitting=True,
192+
)
193+
188194
# fmt:off
189195
workflow.connect([
190196
(inputnode, split_desc, [('template', 'template')]),
@@ -202,8 +208,12 @@ def init_register_template_wf(
202208
]),
203209
(trunc_mov, registration, [
204210
('output_image', 'moving_image')]),
205-
(split_desc, outputnode, [
211+
(split_desc, fmt_cohort, [
206212
('name', 'template'),
213+
('spec', 'spec'),
214+
]),
215+
(fmt_cohort, outputnode, [
216+
('template', 'template'),
207217
('spec', 'template_spec'),
208218
]),
209219
(registration, outputnode, [
@@ -225,3 +235,10 @@ def _make_outputnode(workflow, out_fields, joinsource):
225235
workflow.connect([(pout, out, [(f, f) for f in out_fields])])
226236
return pout
227237
return pe.Node(niu.IdentityInterface(fields=out_fields), name='outputnode')
238+
239+
240+
def _fmt_cohort(template, spec):
241+
cohort = spec.pop('cohort', None)
242+
if cohort is not None:
243+
template = f'{template}:cohort-{cohort}'
244+
return template, spec

0 commit comments

Comments
 (0)