From 4ea9361322de2ec4d10791748a441713cb4a12a4 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Mon, 16 Feb 2026 12:39:13 -0500 Subject: [PATCH 1/6] Initial work. --- nibabies/utils/tests/full-derivatives.yml | 9 +++----- nibabies/workflows/bold/base.py | 27 +++++++++++++++++++++-- nibabies/workflows/bold/outputs.py | 3 --- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/nibabies/utils/tests/full-derivatives.yml b/nibabies/utils/tests/full-derivatives.yml index 81abdcd8..969daf18 100644 --- a/nibabies/utils/tests/full-derivatives.yml +++ b/nibabies/utils/tests/full-derivatives.yml @@ -102,15 +102,12 @@ dataset_description: mode: image desc: hmc - suffix: boldref - space: MNIInfant - cohort: 1 + space: MNIInfant+1 - suffix: mask - space: MNIInfant - cohort: 1 + space: MNIInfant+1 desc: brain - suffix: bold - space: MNIInfant - cohort: 1 + space: MNIInfant+1 desc: preproc - suffix: bold space: fsLR diff --git a/nibabies/workflows/bold/base.py b/nibabies/workflows/bold/base.py index b9f20d92..f125ae2e 100644 --- a/nibabies/workflows/bold/base.py +++ b/nibabies/workflows/bold/base.py @@ -454,6 +454,20 @@ def init_bold_wf( ]) # fmt:skip if spaces.cached.get_spaces(nonstandard=False, dim=(3,)): + combine_space = pe.Node( + niu.Function(function=_combine_space), + name='combine_space', + run_without_submitting=True, + input_names=['space', 'cohort'], + output_names=['space'], + ) + workflow.connect([ + (inputnode, combine_space, [ + ('std_space', 'space'), + ('std_cohort', 'cohort'), + ]), + ]) # fmt:skip + # Missing: # * Clipping BOLD after resampling # * Resampling parcellations @@ -496,10 +510,9 @@ def init_bold_wf( (inputnode, ds_bold_std_wf, [ ('anat2std_xfm', 'inputnode.anat2std_xfm'), ('std_t1w', 'inputnode.template'), - ('std_space', 'inputnode.space'), ('std_resolution', 'inputnode.resolution'), - ('std_cohort', 'inputnode.cohort'), ]), + (combine_space, ds_bold_std_wf, [('space', 'inputnode.space')]), (bold_fit_wf, ds_bold_std_wf, [ ('outputnode.bold_mask', 'inputnode.bold_mask'), ('outputnode.coreg_boldref', 'inputnode.bold_ref'), @@ -866,3 +879,13 @@ def get_MNIInfant_mask(spaces: 'SpatialReferences', res: str | int) -> str: ) raise FileNotFoundError(f'MNIInfant mask (resolution {res}) not found.') + + +def _combine_space(space, cohort) -> str: + """Combine space and cohort into a single string. + + If cohort is not defined, return the space as is. + """ + if cohort: + return f'{space}+{cohort}' + return space diff --git a/nibabies/workflows/bold/outputs.py b/nibabies/workflows/bold/outputs.py index 65e3bf8f..d5d356c0 100644 --- a/nibabies/workflows/bold/outputs.py +++ b/nibabies/workflows/bold/outputs.py @@ -728,7 +728,6 @@ def init_ds_volumes_wf( 'anat2std_xfm', # Entities 'space', - 'cohort', 'resolution', # Transforms previously used to generate the outputs 'motion_xfm', @@ -781,7 +780,6 @@ def init_ds_volumes_wf( ('source_files', 'source_file'), ('bold', 'in_file'), ('space', 'space'), - ('cohort', 'cohort'), ('resolution', 'resolution'), ]), (sources, ds_bold, [('out', 'Sources')]), @@ -872,7 +870,6 @@ def init_ds_volumes_wf( (inputnode, datasink, [ ('source_files', 'source_file'), ('space', 'space'), - ('cohort', 'cohort'), ('resolution', 'resolution'), ]) for datasink in datasinks From a3272eb59ab9ac08f36f441b02f895a1f6b26ef3 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Mon, 16 Feb 2026 12:58:38 -0500 Subject: [PATCH 2/6] Combine space and cohort. --- .circleci/bcp_anat_outputs.txt | 16 +++++++------- .circleci/bcp_anat_t2only_outputs.txt | 16 +++++++------- .circleci/bcp_full_outputs.txt | 28 ++++++++++++------------ nibabies/workflows/anatomical/apply.py | 17 ++++++++++++-- nibabies/workflows/anatomical/outputs.py | 24 +++++++++++++++----- 5 files changed, 64 insertions(+), 37 deletions(-) diff --git a/.circleci/bcp_anat_outputs.txt b/.circleci/bcp_anat_outputs.txt index afcc591c..8a7bed83 100644 --- a/.circleci/bcp_anat_outputs.txt +++ b/.circleci/bcp_anat_outputs.txt @@ -44,14 +44,14 @@ sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_sphere.surf.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_sulc.shape.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_thickness.shape.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_white.surf.gii -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-brain_mask.json -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-brain_mask.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-preproc_T1w.json -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-preproc_T1w.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_dseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-CSF_probseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-GM_probseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-WM_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-brain_mask.json +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-brain_mask.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-preproc_T1w.json +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-preproc_T1w.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_dseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-CSF_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-GM_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-WM_probseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T1w_desc-aparcaseg_dseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T1w_desc-aseg_dseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T1w_desc-ribbon_mask.json diff --git a/.circleci/bcp_anat_t2only_outputs.txt b/.circleci/bcp_anat_t2only_outputs.txt index 9aea211d..61aa9e55 100644 --- a/.circleci/bcp_anat_t2only_outputs.txt +++ b/.circleci/bcp_anat_t2only_outputs.txt @@ -48,14 +48,14 @@ sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_sphere.surf.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_sulc.shape.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_thickness.shape.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_white.surf.gii -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-brain_mask.json -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-brain_mask.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-preproc_T2w.json -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-preproc_T2w.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_dseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-CSF_probseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-GM_probseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-WM_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-brain_mask.json +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-brain_mask.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-preproc_T2w.json +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-preproc_T2w.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_dseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-CSF_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-GM_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-WM_probseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T2w_desc-aparcaseg_dseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T2w_desc-aseg_dseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T2w_desc-ribbon_mask.json diff --git a/.circleci/bcp_full_outputs.txt b/.circleci/bcp_full_outputs.txt index 9376cf50..f546c5f6 100644 --- a/.circleci/bcp_full_outputs.txt +++ b/.circleci/bcp_full_outputs.txt @@ -44,14 +44,14 @@ sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_sphere.surf.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_sulc.shape.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_thickness.shape.gii sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_hemi-R_white.surf.gii -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-brain_mask.json -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-brain_mask.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-preproc_T1w.json -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_desc-preproc_T1w.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_dseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-CSF_probseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-GM_probseg.nii.gz -sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant_cohort-1_label-WM_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-brain_mask.json +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-brain_mask.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-preproc_T1w.json +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_desc-preproc_T1w.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_dseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-CSF_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-GM_probseg.nii.gz +sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-MNIInfant+1_label-WM_probseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T1w_desc-aparcaseg_dseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T1w_desc-aseg_dseg.nii.gz sub-01/ses-1mo/anat/sub-01_ses-1mo_run-001_space-T1w_desc-ribbon_mask.json @@ -82,10 +82,10 @@ sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_from-boldref_to-auto sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_from-boldref_to-auto00000_mode-image_desc-fmap_xfm.txt sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_from-orig_to-boldref_mode-image_desc-hmc_xfm.json sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_from-orig_to-boldref_mode-image_desc-hmc_xfm.txt -sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant_cohort-1_boldref.json -sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant_cohort-1_boldref.nii.gz -sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant_cohort-1_desc-brain_mask.json -sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant_cohort-1_desc-brain_mask.nii.gz -sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant_cohort-1_desc-preproc_bold.json -sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant_cohort-1_desc-preproc_bold.nii.gz +sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant+1_boldref.json +sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant+1_boldref.nii.gz +sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant+1_desc-brain_mask.json +sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant+1_desc-brain_mask.nii.gz +sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant+1_desc-preproc_bold.json +sub-01/ses-1mo/func/sub-01_ses-1mo_task-rest_acq-PA_run-001_space-MNIInfant+1_desc-preproc_bold.nii.gz sub-01_ses-1mo.html diff --git a/nibabies/workflows/anatomical/apply.py b/nibabies/workflows/anatomical/apply.py index 41e3de4c..30159039 100644 --- a/nibabies/workflows/anatomical/apply.py +++ b/nibabies/workflows/anatomical/apply.py @@ -81,6 +81,16 @@ def init_infant_anat_apply_wf( ) if spaces.cached.get_spaces(nonstandard=False, dim=(3,)): + from nibabies.workflows.bold.base import _combine_space + + combine_space = pe.Node( + niu.Function(function=_combine_space), + name='combine_space', + run_without_submitting=True, + input_names=['space', 'cohort'], + output_names=['space'], + ) + ds_std_volumes_wf = init_ds_anat_volumes_wf( bids_root=bids_root, output_dir=output_dir, @@ -88,6 +98,10 @@ def init_infant_anat_apply_wf( ) workflow.connect([ + (inputnode, combine_space, [ + ('std_space', 'space'), + ('std_cohort', 'cohort'), + ]), (inputnode, ds_std_volumes_wf, [ ('anat_valid_list', 'inputnode.source_files'), ('anat_preproc', 'inputnode.anat_preproc'), @@ -98,10 +112,9 @@ def init_infant_anat_apply_wf( (inputnode, ds_std_volumes_wf, [ ('std_t1w', 'inputnode.ref_file'), ('anat2std_xfm', 'inputnode.anat2std_xfm'), - ('std_space', 'inputnode.space'), - ('std_cohort', 'inputnode.cohort'), ('std_resolution', 'inputnode.resolution'), ]), + (combine_space, ds_std_volumes_wf, [('space', 'inputnode.space')]), ]) # fmt:skip if recon_method is not None: diff --git a/nibabies/workflows/anatomical/outputs.py b/nibabies/workflows/anatomical/outputs.py index 4cf5df3f..88149f15 100644 --- a/nibabies/workflows/anatomical/outputs.py +++ b/nibabies/workflows/anatomical/outputs.py @@ -590,12 +590,22 @@ def init_anat_derivatives_wf( from niworkflows.interfaces.space import SpaceDataSource from smriprep.interfaces.templateflow import TemplateFlowSelect + from nibabies.workflows.bold.base import _combine_space + spacesource = pe.Node(SpaceDataSource(), name='spacesource', run_without_submitting=True) spacesource.iterables = ( 'in_tuple', [(s.fullname, s.spec) for s in spaces.cached.get_standard(dim=(3,))], ) + combine_space = pe.Node( + niu.Function(function=_combine_space), + name='combine_space', + run_without_submitting=True, + input_names=['space', 'cohort'], + output_names=['space'], + ) + gen_tplid = pe.Node( niu.Function(function=_fmt_cohort), name='gen_tplid', @@ -690,6 +700,10 @@ def init_anat_derivatives_wf( (inputnode, select_xfm, [ ('anat2std_xfm', 'anat2std_xfm'), ('template', 'keys')]), + (spacesource, combine_space, [ + ('space', 'space'), + ('cohort', 'cohort'), + ]), (spacesource, gen_tplid, [('space', 'template'), ('cohort', 'cohort')]), (gen_tplid, select_xfm, [('out', 'key')]), @@ -724,11 +738,11 @@ def init_anat_derivatives_wf( ] # Connect the space input of these datasinks + [ - ( - spacesource, - n, - [('space', 'space'), ('cohort', 'cohort'), ('resolution', 'resolution')], - ) + (combine_space, n, [('space', 'space')]) + for n in (ds_std_t1w, ds_std_mask, ds_std_dseg, ds_std_tpms) + ] + + [ + (spacesource, n, [('resolution', 'resolution')]) for n in (ds_std_t1w, ds_std_mask, ds_std_dseg, ds_std_tpms) ] ) From 9e9415906bed443625d5ca54f0ca743ef2a3b82e Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Mon, 16 Feb 2026 13:59:46 -0500 Subject: [PATCH 3/6] Update outputs.md --- docs/outputs.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/outputs.md b/docs/outputs.md index 6b1ab209..c242d3c1 100644 --- a/docs/outputs.md +++ b/docs/outputs.md @@ -240,8 +240,8 @@ these will be indicated with `[specifiers]` ``` sub-/[ses-/] func/ - sub-_[specifiers]_space-_desc-brain_mask.nii.gz - sub-_[specifiers]_space-_desc-preproc_bold.nii.gz + sub-_[specifiers]_space-+_desc-brain_mask.nii.gz + sub-_[specifiers]_space-+_desc-preproc_bold.nii.gz ``` :::{note} @@ -311,6 +311,8 @@ Fieldmap registration outputs are part of the *minimal* processing level. Volumetric output spaces labels (`` above, and in the following) include `T1w` and `MNI152NLin2009cAsym` (default). +For space labels that include a cohort, the cohort is included in the space label, +for example `MNIInfant+1`. #### Surfaces, segmentations and parcellations from FreeSurfer From c3165635d3f6c03bddeafa84a7415d0ce1e2eca2 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Tue, 17 Feb 2026 11:17:38 -0500 Subject: [PATCH 4/6] Work on using sMRIPrep master. --- nibabies/workflows/anatomical/apply.py | 17 +--------------- nibabies/workflows/anatomical/outputs.py | 4 ++-- nibabies/workflows/base.py | 6 ++---- nibabies/workflows/bold/base.py | 25 ++++++------------------ pyproject.toml | 2 +- 5 files changed, 12 insertions(+), 42 deletions(-) diff --git a/nibabies/workflows/anatomical/apply.py b/nibabies/workflows/anatomical/apply.py index 30159039..9c7a042f 100644 --- a/nibabies/workflows/anatomical/apply.py +++ b/nibabies/workflows/anatomical/apply.py @@ -68,7 +68,6 @@ def init_infant_anat_apply_wf( 'std_t1w', 'anat2std_xfm', 'std_space', - 'std_cohort', 'std_resolution', ] ), @@ -81,16 +80,6 @@ def init_infant_anat_apply_wf( ) if spaces.cached.get_spaces(nonstandard=False, dim=(3,)): - from nibabies.workflows.bold.base import _combine_space - - combine_space = pe.Node( - niu.Function(function=_combine_space), - name='combine_space', - run_without_submitting=True, - input_names=['space', 'cohort'], - output_names=['space'], - ) - ds_std_volumes_wf = init_ds_anat_volumes_wf( bids_root=bids_root, output_dir=output_dir, @@ -98,23 +87,19 @@ def init_infant_anat_apply_wf( ) workflow.connect([ - (inputnode, combine_space, [ - ('std_space', 'space'), - ('std_cohort', 'cohort'), - ]), (inputnode, ds_std_volumes_wf, [ ('anat_valid_list', 'inputnode.source_files'), ('anat_preproc', 'inputnode.anat_preproc'), ('anat_mask', 'inputnode.anat_mask'), ('anat_dseg', 'inputnode.anat_dseg'), ('anat_tpms', 'inputnode.anat_tpms'), + ('std_space', 'inputnode.space'), ]), (inputnode, ds_std_volumes_wf, [ ('std_t1w', 'inputnode.ref_file'), ('anat2std_xfm', 'inputnode.anat2std_xfm'), ('std_resolution', 'inputnode.resolution'), ]), - (combine_space, ds_std_volumes_wf, [('space', 'inputnode.space')]), ]) # fmt:skip if recon_method is not None: diff --git a/nibabies/workflows/anatomical/outputs.py b/nibabies/workflows/anatomical/outputs.py index 88149f15..0397d398 100644 --- a/nibabies/workflows/anatomical/outputs.py +++ b/nibabies/workflows/anatomical/outputs.py @@ -239,7 +239,7 @@ def init_anat_reports_wf( ('outputnode.anat2std_xfm', 'transforms'), ('outputnode.std_t1w', 'reference_image'), ]), - (template_iterator_wf, norm_rpt, [('outputnode.space', 'before_label')]), + (template_iterator_wf, norm_rpt, [('outputnode.space_entity', 'before_label')]), (t1w_std, norm_msk, [('output_image', 'after')]), (mask_std, norm_msk, [('output_image', 'after_mask')]), (template_iterator_wf, norm_msk, [ @@ -251,7 +251,7 @@ def init_anat_reports_wf( ('after', 'after'), ]), (inputnode, ds_std_t1w_report, [('source_file', 'source_file')]), - (template_iterator_wf, ds_std_t1w_report, [('outputnode.space', 'space')]), + (template_iterator_wf, ds_std_t1w_report, [('outputnode.space_entity', 'space')]), (norm_rpt, ds_std_t1w_report, [('out_report', 'in_file')]), ]) # fmt:skip diff --git a/nibabies/workflows/base.py b/nibabies/workflows/base.py index 6421b436..8cd9ff85 100644 --- a/nibabies/workflows/base.py +++ b/nibabies/workflows/base.py @@ -574,8 +574,7 @@ def init_single_subject_wf( (template_iterator_wf, anat_apply_wf, [ ('outputnode.std_t1w', 'inputnode.std_t1w',), ('outputnode.anat2std_xfm', 'inputnode.anat2std_xfm'), - ('outputnode.space', 'inputnode.std_space'), - ('outputnode.cohort', 'inputnode.std_cohort'), + ('outputnode.space_entity', 'inputnode.std_space'), ('outputnode.resolution', 'inputnode.std_resolution'), ]), ]) # fmt:skip @@ -791,9 +790,8 @@ def init_single_subject_wf( if template_iterator_wf is not None: workflow.connect([ (template_iterator_wf, bold_wf, [ - ('outputnode.space', 'inputnode.std_space'), + ('outputnode.space_entity', 'inputnode.std_space'), ('outputnode.resolution', 'inputnode.std_resolution'), - ('outputnode.cohort', 'inputnode.std_cohort'), ('outputnode.std_t1w', 'inputnode.std_t1w'), ('outputnode.std_mask', 'inputnode.std_mask'), ('outputnode.anat2std_xfm', 'inputnode.anat2std_xfm'), diff --git a/nibabies/workflows/bold/base.py b/nibabies/workflows/bold/base.py index f125ae2e..ca6251e2 100644 --- a/nibabies/workflows/bold/base.py +++ b/nibabies/workflows/bold/base.py @@ -144,8 +144,6 @@ def init_bold_wf( Value of space entity to be used in standard space output filenames std_resolution Value of resolution entity to be used in standard space output filenames - std_cohort - Value of cohort entity to be used in standard space output filenames anat2mni6_xfm Transform from anatomical space to MNI152NLin6Asym space mni6_mask @@ -154,7 +152,7 @@ def init_bold_wf( Transform from MNI152NLin2009cAsym to anatomical space Note that ``anat2std_xfm``, ``std_space``, ``std_resolution``, - ``std_cohort``, ``std_t1w`` and ``std_mask`` are treated as single + ``std_t1w`` and ``std_mask`` are treated as single inputs. In order to resample to multiple target spaces, connect these fields to an iterable. @@ -244,7 +242,6 @@ def init_bold_wf( 'std_mask', 'std_space', 'std_resolution', - 'std_cohort', # MNI152NLin6Asym warp, for CIFTI use # 'anat2mni6_xfm', # 'mni6_mask', @@ -454,20 +451,6 @@ def init_bold_wf( ]) # fmt:skip if spaces.cached.get_spaces(nonstandard=False, dim=(3,)): - combine_space = pe.Node( - niu.Function(function=_combine_space), - name='combine_space', - run_without_submitting=True, - input_names=['space', 'cohort'], - output_names=['space'], - ) - workflow.connect([ - (inputnode, combine_space, [ - ('std_space', 'space'), - ('std_cohort', 'cohort'), - ]), - ]) # fmt:skip - # Missing: # * Clipping BOLD after resampling # * Resampling parcellations @@ -511,8 +494,8 @@ def init_bold_wf( ('anat2std_xfm', 'inputnode.anat2std_xfm'), ('std_t1w', 'inputnode.template'), ('std_resolution', 'inputnode.resolution'), + ('std_space', 'inputnode.space'), ]), - (combine_space, ds_bold_std_wf, [('space', 'inputnode.space')]), (bold_fit_wf, ds_bold_std_wf, [ ('outputnode.bold_mask', 'inputnode.bold_mask'), ('outputnode.coreg_boldref', 'inputnode.bold_ref'), @@ -886,6 +869,10 @@ def _combine_space(space, cohort) -> str: If cohort is not defined, return the space as is. """ + if space.startswith('space-'): + space = space.split('-')[1] if cohort: + if cohort.startswith('cohort-'): + cohort = cohort.split('-')[1] return f'{space}+{cohort}' return space diff --git a/pyproject.toml b/pyproject.toml index 797560e0..2ab4aa73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ "pybids >= 0.15.0", "requests", "sdcflows >= 2.14.0", - "smriprep >= 0.19.1", + "smriprep @ git+https://github.com/nipreps/smriprep.git@master", "tedana >= 23.0.2", "templateflow >= 25.0.3", "toml", From adc0137cac266c12352c8a892268716dc25d24d1 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Wed, 18 Feb 2026 09:35:27 -0500 Subject: [PATCH 5/6] Whoops. I forgot it was just space, not space_entity. --- nibabies/workflows/anatomical/outputs.py | 4 ++-- nibabies/workflows/base.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nibabies/workflows/anatomical/outputs.py b/nibabies/workflows/anatomical/outputs.py index 0397d398..88149f15 100644 --- a/nibabies/workflows/anatomical/outputs.py +++ b/nibabies/workflows/anatomical/outputs.py @@ -239,7 +239,7 @@ def init_anat_reports_wf( ('outputnode.anat2std_xfm', 'transforms'), ('outputnode.std_t1w', 'reference_image'), ]), - (template_iterator_wf, norm_rpt, [('outputnode.space_entity', 'before_label')]), + (template_iterator_wf, norm_rpt, [('outputnode.space', 'before_label')]), (t1w_std, norm_msk, [('output_image', 'after')]), (mask_std, norm_msk, [('output_image', 'after_mask')]), (template_iterator_wf, norm_msk, [ @@ -251,7 +251,7 @@ def init_anat_reports_wf( ('after', 'after'), ]), (inputnode, ds_std_t1w_report, [('source_file', 'source_file')]), - (template_iterator_wf, ds_std_t1w_report, [('outputnode.space_entity', 'space')]), + (template_iterator_wf, ds_std_t1w_report, [('outputnode.space', 'space')]), (norm_rpt, ds_std_t1w_report, [('out_report', 'in_file')]), ]) # fmt:skip diff --git a/nibabies/workflows/base.py b/nibabies/workflows/base.py index 9d3ff86b..9cee2e6a 100644 --- a/nibabies/workflows/base.py +++ b/nibabies/workflows/base.py @@ -574,7 +574,7 @@ def init_single_subject_wf( (template_iterator_wf, anat_apply_wf, [ ('outputnode.std_t1w', 'inputnode.std_t1w',), ('outputnode.anat2std_xfm', 'inputnode.anat2std_xfm'), - ('outputnode.space_entity', 'inputnode.std_space'), + ('outputnode.space', 'inputnode.std_space'), ('outputnode.resolution', 'inputnode.std_resolution'), ]), ]) # fmt:skip @@ -789,7 +789,7 @@ def init_single_subject_wf( if template_iterator_wf is not None: workflow.connect([ (template_iterator_wf, bold_wf, [ - ('outputnode.space_entity', 'inputnode.std_space'), + ('outputnode.space', 'inputnode.std_space'), ('outputnode.resolution', 'inputnode.std_resolution'), ('outputnode.std_t1w', 'inputnode.std_t1w'), ('outputnode.std_mask', 'inputnode.std_mask'), From 9996fd47e47b8d6c0ba2e5a4f9fc2c0014a4a396 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Wed, 18 Feb 2026 10:19:23 -0500 Subject: [PATCH 6/6] Move combine_space to more appropriate loc. --- nibabies/utils/bids.py | 14 ++++++++++++++ nibabies/workflows/anatomical/outputs.py | 13 +++++++------ nibabies/workflows/bold/base.py | 16 +--------------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/nibabies/utils/bids.py b/nibabies/utils/bids.py index 06a3f404..55097e9d 100644 --- a/nibabies/utils/bids.py +++ b/nibabies/utils/bids.py @@ -360,3 +360,17 @@ def age_to_months(age: int | float, units: ty.Literal['weeks', 'months', 'years' elif units == 'years': age *= YEARS_TO_MONTH return round(age) + + +def combine_space(space, cohort) -> str: + """Combine space and cohort into a single string. + + If cohort is not defined, return the space as is. + """ + if space.startswith('space-'): + space = space.split('-')[1] + if cohort: + if cohort.startswith('cohort-'): + cohort = cohort.split('-')[1] + return f'{space}+{cohort}' + return space diff --git a/nibabies/workflows/anatomical/outputs.py b/nibabies/workflows/anatomical/outputs.py index 88149f15..03d47b6e 100644 --- a/nibabies/workflows/anatomical/outputs.py +++ b/nibabies/workflows/anatomical/outputs.py @@ -590,7 +590,7 @@ def init_anat_derivatives_wf( from niworkflows.interfaces.space import SpaceDataSource from smriprep.interfaces.templateflow import TemplateFlowSelect - from nibabies.workflows.bold.base import _combine_space + from nibabies.utils.bids import combine_space spacesource = pe.Node(SpaceDataSource(), name='spacesource', run_without_submitting=True) spacesource.iterables = ( @@ -598,9 +598,9 @@ def init_anat_derivatives_wf( [(s.fullname, s.spec) for s in spaces.cached.get_standard(dim=(3,))], ) - combine_space = pe.Node( - niu.Function(function=_combine_space), - name='combine_space', + combine_space_entity = pe.Node( + niu.Function(function=combine_space), + name='combine_space_entity', run_without_submitting=True, input_names=['space', 'cohort'], output_names=['space'], @@ -700,7 +700,7 @@ def init_anat_derivatives_wf( (inputnode, select_xfm, [ ('anat2std_xfm', 'anat2std_xfm'), ('template', 'keys')]), - (spacesource, combine_space, [ + (spacesource, combine_space_entity, [ ('space', 'space'), ('cohort', 'cohort'), ]), @@ -738,9 +738,10 @@ def init_anat_derivatives_wf( ] # Connect the space input of these datasinks + [ - (combine_space, n, [('space', 'space')]) + (combine_space_entity, n, [('space', 'space')]) for n in (ds_std_t1w, ds_std_mask, ds_std_dseg, ds_std_tpms) ] + # Connect the resolution input of these datasinks + [ (spacesource, n, [('resolution', 'resolution')]) for n in (ds_std_t1w, ds_std_mask, ds_std_dseg, ds_std_tpms) diff --git a/nibabies/workflows/bold/base.py b/nibabies/workflows/bold/base.py index ca6251e2..782f8277 100644 --- a/nibabies/workflows/bold/base.py +++ b/nibabies/workflows/bold/base.py @@ -493,8 +493,8 @@ def init_bold_wf( (inputnode, ds_bold_std_wf, [ ('anat2std_xfm', 'inputnode.anat2std_xfm'), ('std_t1w', 'inputnode.template'), - ('std_resolution', 'inputnode.resolution'), ('std_space', 'inputnode.space'), + ('std_resolution', 'inputnode.resolution'), ]), (bold_fit_wf, ds_bold_std_wf, [ ('outputnode.bold_mask', 'inputnode.bold_mask'), @@ -862,17 +862,3 @@ def get_MNIInfant_mask(spaces: 'SpatialReferences', res: str | int) -> str: ) raise FileNotFoundError(f'MNIInfant mask (resolution {res}) not found.') - - -def _combine_space(space, cohort) -> str: - """Combine space and cohort into a single string. - - If cohort is not defined, return the space as is. - """ - if space.startswith('space-'): - space = space.split('-')[1] - if cohort: - if cohort.startswith('cohort-'): - cohort = cohort.split('-')[1] - return f'{space}+{cohort}' - return space