Skip to content

Commit 93732b0

Browse files
committed
WIP: Integration
1 parent 9c4c1fb commit 93732b0

File tree

6 files changed

+130
-105
lines changed

6 files changed

+130
-105
lines changed

nibabies/interfaces/utils.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import os
2+
import re
3+
4+
from nipype.interfaces.base import (
5+
BaseInterfaceInputSpec,
6+
File,
7+
InputMultiObject,
8+
OutputMultiObject,
9+
SimpleInterface,
10+
TraitedSpec,
11+
traits,
12+
)
13+
14+
15+
class CiftiSelectInputSpec(BaseInterfaceInputSpec):
16+
hemi = traits.Enum("L", "R", desc="Hemisphere")
17+
surfaces = InputMultiObject(File(exists=True), desc="Surfaces")
18+
morphometrics = InputMultiObject(File(exists=True), desc="Surface morphometrics")
19+
spherical_registrations = InputMultiObject(
20+
File(exists=True), desc="Spherical registration to fsLR"
21+
)
22+
template_spheres = InputMultiObject(File(exists=True), desc="fsLR sphere")
23+
template_surfaces = InputMultiObject(File(exists=True), desc="fsLR midthickness")
24+
template_rois = InputMultiObject(File(exists=True), desc="fsLR ROIs")
25+
26+
27+
class CiftiSelectOutputSpec(TraitedSpec):
28+
white = OutputMultiObject(File, desc="white surface")
29+
pial = OutputMultiObject(File, desc="pial surface")
30+
midthickness = OutputMultiObject(File, desc="midthickness surface")
31+
thickness = OutputMultiObject(File, desc="thickness surface")
32+
sphere_reg = OutputMultiObject(File, desc="fsLR spherical regisration")
33+
template_sphere = OutputMultiObject(File, desc="fsLR sphere")
34+
template_surface = OutputMultiObject(File, desc="fsLR surface (midthickness)")
35+
template_roi = OutputMultiObject(File, desc="fsLR ROIs")
36+
37+
38+
class CiftiSelect(SimpleInterface):
39+
input_spec = CiftiSelectInputSpec
40+
output_spec = CiftiSelectOutputSpec
41+
42+
def _run_interface(self, runtime):
43+
idx = 0 if self.inputs.hemi == "L" else 1
44+
all_surfaces = (self.inputs.surfaces or []) + (self.inputs.morphometrics or [])
45+
container = {
46+
'white': [],
47+
'pial': [],
48+
'midthickness': [],
49+
'thickness': [],
50+
'sphere_reg': self.inputs.spherical_registrations or [],
51+
'template_sphere': self.inputs.template_spheres or [],
52+
'template_surface': self.inputs.template_surfaces or [],
53+
'template_roi': self.inputs.template_rois or [],
54+
}
55+
find_name = re.compile(r'(?:^|[^d])(?P<name>white|pial|midthickness|thickness)')
56+
for surface in all_surfaces:
57+
match = find_name.search(os.path.basename(surface))
58+
if match:
59+
container[match.group('name')].append(surface)
60+
61+
for name, vals in container.items():
62+
if vals:
63+
self._results[name] = sorted(vals, key=os.path.basename)[idx]
64+
return runtime

nibabies/workflows/anatomical/base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,13 @@ def init_infant_anat_wf(
522522
anat_derivatives_wf.get_node('inputnode').inputs.cifti_density = cifti_output
523523
# fmt:off
524524
wf.connect([
525+
(sphere_reg_wf, anat_fsLR_resampling_wf, [
526+
('outputnode.sphere_reg_fsLR', 'inputnode.sphere_reg_fsLR')]),
525527
(surface_recon_wf, anat_fsLR_resampling_wf, [
526528
('outputnode.subject_id', 'inputnode.subject_id'),
527-
('outputnode.subjects_dir', 'inputnode.subjects_dir')]),
529+
('outputnode.subjects_dir', 'inputnode.subjects_dir'),
530+
('outputnode.surfaces', 'inputnode.surfaces'),
531+
('outputnode.morphometrics', 'inputnode.morphometrics')]),
528532
(anat_fsLR_resampling_wf, anat_derivatives_wf, [
529533
("outputnode.cifti_morph", "inputnode.cifti_morph"),
530534
("outputnode.cifti_metadata", "inputnode.cifti_metadata")]),

nibabies/workflows/anatomical/resampling.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
import typing as ty
22

3-
import nipype.interfaces.utils as niu
3+
import nipype.interfaces.utility as niu
44
import nipype.pipeline.engine as pe
55
import templateflow.api as tf
66
from niworkflows.engine.workflows import LiterateWorkflow
77
from smriprep.interfaces.workbench import SurfaceResample
8-
from smriprep.workflows.surfaces import (
9-
_collate,
10-
_sorted_by_basename,
11-
init_morph_grayords_wf,
12-
)
8+
from smriprep.workflows.surfaces import _collate, init_morph_grayords_wf
139

1410
from nibabies.config import DEFAULT_MEMORY_MIN_GB
1511
from nibabies.data import load_resource
@@ -96,12 +92,15 @@ def init_anat_fsLR_resampling_wf(
9692
# resample surfaces / morphometrics to 32k
9793
if mcribs:
9894
morph_grayords_wf = init_mcribs_morph_grayords_wf(grayord_density)
99-
workflow.connect(
100-
joinnode,
101-
"fsLR_midthickness",
102-
morph_grayords_wf,
103-
"inputnode.fsLR_midthickness",
104-
)
95+
# fmt:off
96+
workflow.connect([
97+
(inputnode, morph_grayords_wf, [
98+
("morphometrics", "inputnode.morphometrics"),
99+
("surfaces", "inputnode.surfaces")]),
100+
(joinnode, morph_grayords_wf, [
101+
("midthickness_fsLR", "inputnode.midthickness_fsLR")]),
102+
])
103+
# fmt:on
105104
else:
106105
morph_grayords_wf = init_morph_grayords_wf(grayord_density)
107106

@@ -117,7 +116,7 @@ def init_anat_fsLR_resampling_wf(
117116
("sphere_reg", "current_sphere"),
118117
("template_sphere", "new_sphere")]),
119118
(downsampled_midthickness, joinnode, [("surface_out", "midthickness_fsLR")]),
120-
(joinnode, outputnode, [("surface_out", "midthickness_fsLR")]),
119+
(joinnode, outputnode, [("midthickness_fsLR", "midthickness_fsLR")]),
121120
# resample morphometrics to fsLR 32k
122121
(inputnode, morph_grayords_wf, [
123122
("subject_id", "inputnode.subject_id"),
@@ -190,7 +189,7 @@ def init_mcribs_morph_grayords_wf(
190189
"subjects_dir",
191190
"surfaces",
192191
"morphometrics",
193-
"fsLR_midthickness",
192+
"midthickness_fsLR",
194193
]
195194
),
196195
name="inputnode",
@@ -207,6 +206,16 @@ def init_mcribs_morph_grayords_wf(
207206
run_without_submitting=True,
208207
)
209208

209+
get_current_midthickness = pe.Node(
210+
niu.Function(function=_get_surf),
211+
name="get_midthickness",
212+
run_without_submitting=True,
213+
)
214+
get_current_midthickness.inputs.name = "midthickness"
215+
get_current_midthickness.inputs.mult = 3
216+
217+
get_new_midthickness = get_current_midthickness.clone("get_new_midthickness")
218+
210219
# Setup Workbench command. LR ordering for hemi can be assumed, as it is imposed
211220
# by the iterfield of the MapNode in the surface sampling workflow above.
212221
resample = pe.MapNode(
@@ -249,14 +258,16 @@ def init_mcribs_morph_grayords_wf(
249258

250259
# fmt: off
251260
workflow.connect([
252-
(inputnode, resample, [
253-
("fsLR_midthickness", "new_area"),
254-
(('surfaces', _get_surf, "midthickness", 3), "current_area")]),
261+
(inputnode, get_current_midthickness, [("surfaces", "surfaces")]),
262+
(inputnode, get_new_midthickness, [("midthickness_fsLR", "surfaces")]),
263+
(get_current_midthickness, resample, [("out", "current_area")]),
264+
(get_new_midthickness, resample, [("out", "new_area")]),
255265
(inputnode, surfmorph_list, [
256266
(('morphometrics', _get_surf, "curv"), "in1"),
257267
(('morphometrics', _get_surf, "sulc"), "in2"),
258268
(('morphometrics', _get_surf, "thickness"), "in3"),
259269
]),
270+
(surfmorph_list, resample, [('out', 'in_file')]),
260271
(resample, gen_cifti, [
261272
(("out_file", _collate), "scalar_surfs")]),
262273
(gen_cifti, outputnode, [("out_file", "cifti_morph"),
@@ -267,5 +278,9 @@ def init_mcribs_morph_grayords_wf(
267278

268279

269280
def _get_surf(surfaces, name, mult=1):
281+
from smriprep.workflows.surfaces import _sorted_by_basename
282+
270283
"Select a specific surface by name, and optionally multiple it."
284+
if not surfaces:
285+
return surfaces
271286
return [surf for surf in _sorted_by_basename(surfaces) if name in surf] * mult

nibabies/workflows/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ def init_single_subject_wf(
473473
('outputnode.surfaces', 'inputnode.surfaces'),
474474
('outputnode.morphometrics', 'inputnode.morphometrics'),
475475
('outputnode.sphere_reg_fsLR', 'inputnode.sphere_reg_fsLR'),
476+
('outputnode.midthickness_fsLR', 'inputnode.midthickness_fsLR'),
476477
]),
477478
])
478479
# fmt:on

nibabies/workflows/bold/base.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ def init_func_preproc_wf(bold_file, spaces, has_fieldmap=False, existing_derivat
340340
"surfaces",
341341
"morphometrics",
342342
"sphere_reg_fsLR",
343+
"midthickness_fsLR",
343344
]
344345
),
345346
name="inputnode",
@@ -950,12 +951,13 @@ def init_func_preproc_wf(bold_file, spaces, has_fieldmap=False, existing_derivat
950951
from .resampling import init_bold_fsLR_resampling_wf, init_bold_grayords_wf
951952

952953
# Anatomical -> fsLR surfaces
954+
953955
bold_fsLR_resampling_wf = init_bold_fsLR_resampling_wf(
954956
estimate_goodvoxels=project_goodvoxels,
955957
grayord_density=config.workflow.cifti_output,
956958
omp_nthreads=omp_nthreads,
959+
mcribs=config.workflow.surface_recon_method == "mcribs",
957960
mem_gb=mem_gb["resampled"],
958-
mcribs=config.workflow.surface_recon_method == 'mcribs',
959961
)
960962

961963
subcortical_rois_wf = init_subcortical_rois_wf()
@@ -976,11 +978,8 @@ def init_func_preproc_wf(bold_file, spaces, has_fieldmap=False, existing_derivat
976978

977979
# fmt:off
978980
workflow.connect([
979-
(inputnode, bold_fsLR_resampling_wf, [
980-
("surfaces", "inputnode.surfaces"),
981-
("morphometrics", "inputnode.morphometrics"),
982-
("sphere_reg_fsLR", "inputnode.sphere_reg_fsLR"),
983-
("anat_ribbon", "inputnode.anat_ribbon")]),
981+
# select the MNIInfant standard
982+
# CIFTI subcortical volumetric re
984983
(bold_std_trans_wf, cifti_select_std, [
985984
("outputnode.bold_std", "bold_std"),
986985
("outputnode.bold_aseg_std", "bold_aseg_std"),
@@ -992,28 +991,31 @@ def init_func_preproc_wf(bold_file, spaces, has_fieldmap=False, existing_derivat
992991
(subcortical_rois_wf, subcortical_mni_alignment_wf, [
993992
("outputnode.MNIInfant_rois", "inputnode.MNIInfant_rois"),
994993
("outputnode.MNI152_rois", "inputnode.MNI152_rois")]),
995-
(subcortical_mni_alignment_wf, bold_grayords_wf, [
996-
("outputnode.subcortical_volume", "inputnode.subcortical_volume"),
997-
("outputnode.subcortical_labels", "inputnode.subcortical_labels")]),
994+
995+
# CIFTI surface sampling
996+
(inputnode, bold_fsLR_resampling_wf, [
997+
("surfaces", "inputnode.surfaces"),
998+
("morphometrics", "inputnode.morphometrics"),
999+
("sphere_reg_fsLR", "inputnode.sphere_reg_fsLR"),
1000+
("midthickness_fsLR", "inputnode.midthickness_fsLR"),
1001+
("anat_ribbon", "inputnode.anat_ribbon")]),
9981002
(bold_t1_trans_wf, bold_fsLR_resampling_wf, [
9991003
("outputnode.bold_t1", "inputnode.bold_file")]),
1000-
(bold_std_trans_wf, bold_grayords_wf, [
1001-
("outputnode.bold_std", "inputnode.bold_std"),
1002-
("outputnode.spatial_reference", "inputnode.spatial_reference"),
1004+
(bold_fsLR_resampling_wf, func_derivatives_wf, [
1005+
("outputnode.goodvoxels_mask", "inputnode.goodvoxels_mask"),
10031006
]),
1007+
1008+
# combine surface + volume into dtseries
1009+
(subcortical_mni_alignment_wf, bold_grayords_wf, [
1010+
("outputnode.subcortical_volume", "inputnode.subcortical_volume"),
1011+
("outputnode.subcortical_labels", "inputnode.subcortical_labels")]),
10041012
(bold_fsLR_resampling_wf, bold_grayords_wf, [
10051013
("outputnode.bold_fsLR", "inputnode.bold_fsLR"),
10061014
]),
1007-
(bold_fsLR_resampling_wf, func_derivatives_wf, [
1008-
("outputnode.goodvoxels_mask", "inputnode.goodvoxels_mask"),
1009-
]),
10101015
(bold_grayords_wf, outputnode, [
10111016
("outputnode.cifti_bold", "bold_cifti"),
10121017
("outputnode.cifti_metadata", "cifti_metadata"),
10131018
]),
1014-
(bold_grayords_wf, outputnode, [
1015-
('outputnode.cifti_bold', 'bold_cifti'),
1016-
('outputnode.cifti_metadata', 'cifti_metadata')]),
10171019
])
10181020
# fmt:on
10191021

0 commit comments

Comments
 (0)