Skip to content

Commit

Permalink
ENH: Resample BOLD series to volumetric templates
Browse files Browse the repository at this point in the history
  • Loading branch information
effigies committed Oct 26, 2023
1 parent 26d141f commit c99e368
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 87 deletions.
28 changes: 25 additions & 3 deletions fmriprep/workflows/base.py
Expand Up @@ -151,6 +151,7 @@ def init_single_subject_wf(subject_id: str):
from niworkflows.utils.misc import fix_multi_T1w_source_name
from niworkflows.utils.spaces import Reference
from smriprep.workflows.anatomical import init_anat_fit_wf
from smriprep.workflows.outputs import init_template_iterator_wf

Check warning on line 154 in fmriprep/workflows/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/base.py#L154

Added line #L154 was not covered by tests

from fmriprep.workflows.bold.base import init_bold_wf

Expand Down Expand Up @@ -310,7 +311,6 @@ def init_single_subject_wf(subject_id: str):
skull_strip_fixed_seed=config.workflow.skull_strip_fixed_seed,
)

# fmt:off
workflow.connect([
(inputnode, anat_fit_wf, [('subjects_dir', 'inputnode.subjects_dir')]),
(bidssrc, bids_info, [(('t1w', fix_multi_T1w_source_name), 'in_file')]),
Expand All @@ -329,8 +329,18 @@ def init_single_subject_wf(subject_id: str):
(bidssrc, ds_report_about, [(('t1w', fix_multi_T1w_source_name), 'source_file')]),
(summary, ds_report_summary, [('out_report', 'in_file')]),
(about, ds_report_about, [('out_report', 'in_file')]),
])
# fmt:on
]) # fmt:skip

# Set up the template iterator once, if used
if config.workflow.level == "full":
if spaces.get_spaces(nonstandard=False, dim=(3,)):
template_iterator_wf = init_template_iterator_wf(spaces=spaces)
workflow.connect([

Check warning on line 338 in fmriprep/workflows/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/base.py#L335-L338

Added lines #L335 - L338 were not covered by tests
(anat_fit_wf, template_iterator_wf, [
('outputnode.template', 'inputnode.template'),
('outputnode.anat2std_xfm', 'inputnode.anat2std_xfm'),
]),
]) # fmt:skip

if config.workflow.anat_only:
return clean_datasinks(workflow)
Expand Down Expand Up @@ -510,6 +520,18 @@ def init_single_subject_wf(subject_id: str):
]),
]) # fmt:skip

if config.workflow.level == "full":
workflow.connect([

Check warning on line 524 in fmriprep/workflows/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/base.py#L523-L524

Added lines #L523 - L524 were not covered by tests
(template_iterator_wf, bold_wf, [
("outputnode.anat2std_xfm", "inputnode.anat2std_xfm"),
("outputnode.space", "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"),
]),
]) # fmt:skip

return clean_datasinks(workflow)


Expand Down
144 changes: 60 additions & 84 deletions fmriprep/workflows/bold/base.py
Expand Up @@ -198,6 +198,13 @@ def init_bold_wf(
"fmap_mask",
"fmap_id",
"sdc_method",
# Volumetric templates
"anat2std_xfm",
"std_space",
"std_resolution",
"std_cohort",
"std_t1w",
"std_mask",
],
),
name="inputnode",
Expand Down Expand Up @@ -381,6 +388,59 @@ def init_bold_wf(
(bold_anat_wf, ds_bold_t1_wf, [('outputnode.bold_file', 'inputnode.bold')]),
]) # fmt:skip

if spaces.get_spaces(nonstandard=False, dim=(3,)):

Check warning on line 391 in fmriprep/workflows/bold/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/bold/base.py#L391

Added line #L391 was not covered by tests
# Missing:
# * Clipping BOLD after resampling
# * Resampling parcellations
bold_std_wf = init_bold_volumetric_resample_wf(

Check warning on line 395 in fmriprep/workflows/bold/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/bold/base.py#L395

Added line #L395 was not covered by tests
metadata=all_metadata[0],
fieldmap_id=fieldmap_id if not multiecho else None,
omp_nthreads=omp_nthreads,
name='bold_std_wf',
)
ds_bold_std_wf = init_ds_volumes_wf(

Check warning on line 401 in fmriprep/workflows/bold/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/bold/base.py#L401

Added line #L401 was not covered by tests
bids_root=str(config.execution.bids_dir),
output_dir=fmriprep_dir,
multiecho=multiecho,
metadata=all_metadata[0],
name='ds_bold_std_wf',
)
ds_bold_std_wf.inputs.inputnode.source_files = bold_series

Check warning on line 408 in fmriprep/workflows/bold/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/bold/base.py#L408

Added line #L408 was not covered by tests

workflow.connect([

Check warning on line 410 in fmriprep/workflows/bold/base.py

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/bold/base.py#L410

Added line #L410 was not covered by tests
(inputnode, bold_std_wf, [
("std_t1w", "inputnode.target_ref_file"),
("std_mask", "inputnode.target_mask"),
("anat2std_xfm", "inputnode.anat2std_xfm"),
("fmap_ref", "inputnode.fmap_ref"),
("fmap_coeff", "inputnode.fmap_coeff"),
("fmap_id", "inputnode.fmap_id"),
]),
(bold_fit_wf, bold_std_wf, [
("outputnode.coreg_boldref", "inputnode.bold_ref_file"),
("outputnode.boldref2fmap_xfm", "inputnode.boldref2fmap_xfm"),
("outputnode.boldref2anat_xfm", "inputnode.boldref2anat_xfm"),
]),
(bold_native_wf, bold_std_wf, [
("outputnode.bold_minimal", "inputnode.bold_file"),
("outputnode.motion_xfm", "inputnode.motion_xfm"),
]),
(inputnode, ds_bold_std_wf, [
('std_t1w', 'inputnode.ref_file'),
('anat2std_xfm', 'inputnode.anat2std_xfm'),
('std_space', 'inputnode.space'),
('std_resolution', 'inputnode.resolution'),
('std_cohort', 'inputnode.cohort'),
]),
(bold_fit_wf, ds_bold_std_wf, [
('outputnode.bold_mask', 'inputnode.bold_mask'),
('outputnode.coreg_boldref', 'inputnode.bold_ref'),
('outputnode.boldref2anat_xfm', 'inputnode.boldref2anat_xfm'),
]),
(bold_native_wf, ds_bold_std_wf, [('outputnode.t2star_map', 'inputnode.t2star')]),
(bold_anat_wf, ds_bold_std_wf, [('outputnode.bold_file', 'inputnode.bold')]),
]) # fmt:skip

# Fill-in datasinks of reportlets seen so far
for node in workflow.list_node_names():
if node.split(".")[-1].startswith("ds_report"):
Expand Down Expand Up @@ -629,90 +689,6 @@ def init_func_preproc_wf(bold_file, has_fieldmap=False):
)
bold_confounds_wf.get_node("inputnode").inputs.t1_transform_flags = [False]

if spaces.get_spaces(nonstandard=False, dim=(3,)):
# Apply transforms in 1 shot
bold_std_trans_wf = init_bold_std_trans_wf(
freesurfer=freesurfer,
mem_gb=mem_gb["resampled"],
omp_nthreads=omp_nthreads,
spaces=spaces,
multiecho=multiecho,
name="bold_std_trans_wf",
use_compression=not config.execution.low_mem,
)
bold_std_trans_wf.inputs.inputnode.fieldwarp = "identity"

# fmt:off
workflow.connect([
(inputnode, bold_std_trans_wf, [
("template", "inputnode.templates"),
("anat2std_xfm", "inputnode.anat2std_xfm"),
("bold_file", "inputnode.name_source"),
("t1w_aseg", "inputnode.bold_aseg"),
("t1w_aparc", "inputnode.bold_aparc"),
]),
(bold_final, bold_std_trans_wf, [
("mask", "inputnode.bold_mask"),
("t2star", "inputnode.t2star"),
]),
(bold_reg_wf, bold_std_trans_wf, [
("outputnode.itk_bold_to_t1", "inputnode.itk_bold_to_t1"),
]),
(bold_std_trans_wf, outputnode, [
("outputnode.bold_std", "bold_std"),
("outputnode.bold_std_ref", "bold_std_ref"),
("outputnode.bold_mask_std", "bold_mask_std"),
]),
])
# fmt:on

if freesurfer:
# fmt:off
workflow.connect([
(bold_std_trans_wf, func_derivatives_wf, [
("outputnode.bold_aseg_std", "inputnode.bold_aseg_std"),
("outputnode.bold_aparc_std", "inputnode.bold_aparc_std"),
]),
(bold_std_trans_wf, outputnode, [
("outputnode.bold_aseg_std", "bold_aseg_std"),
("outputnode.bold_aparc_std", "bold_aparc_std"),
]),
])
# fmt:on

if not multiecho:
# fmt:off
workflow.connect([
(bold_split, bold_std_trans_wf, [("out_files", "inputnode.bold_split")]),
(bold_hmc_wf, bold_std_trans_wf, [
("outputnode.xforms", "inputnode.hmc_xforms"),
]),
])
# fmt:on
else:
# fmt:off
workflow.connect([
(split_opt_comb, bold_std_trans_wf, [("out_files", "inputnode.bold_split")]),
(bold_std_trans_wf, outputnode, [("outputnode.t2star_std", "t2star_std")]),
])
# fmt:on

# Already applied in bold_bold_trans_wf, which inputs to bold_t2s_wf
bold_std_trans_wf.inputs.inputnode.hmc_xforms = "identity"

# fmt:off
# func_derivatives_wf internally parametrizes over snapshotted spaces.
workflow.connect([
(bold_std_trans_wf, func_derivatives_wf, [
("outputnode.template", "inputnode.template"),
("outputnode.spatial_reference", "inputnode.spatial_reference"),
("outputnode.bold_std_ref", "inputnode.bold_std_ref"),
("outputnode.bold_std", "inputnode.bold_std"),
("outputnode.bold_mask_std", "inputnode.bold_mask_std"),
]),
])
# fmt:on

# SURFACES ##################################################################################
# Freesurfer
if freesurfer and freesurfer_spaces:
Expand Down

0 comments on commit c99e368

Please sign in to comment.