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

Track proximal sources of functional GIFTIs #3263

Merged
merged 5 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
31 changes: 31 additions & 0 deletions fmriprep/workflows/bold/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,37 @@
(bold_anat_wf, bold_surf_wf, [('outputnode.bold_file', 'inputnode.bold_t1w')]),
]) # fmt:skip

if nonstd_spaces.intersection(('anat', 'T1w')):
# Source file should be output T1w-space volumetric file and fsnative2t1w_xfm
tsalo marked this conversation as resolved.
Show resolved Hide resolved
merge_surface_sources = pe.Node(

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

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/bold/base.py#L519

Added line #L519 was not covered by tests
niu.Merge(2),
name='merge_surface_sources',
run_without_submitting=True,
)
workflow.connect([

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

View check run for this annotation

Codecov / codecov/patch

fmriprep/workflows/bold/base.py#L524

Added line #L524 was not covered by tests
(ds_bold_t1_wf, merge_surface_sources, [('outputnode.bold', 'in1')]),
(inputnode, merge_surface_sources, [('fsnative2t1w_xfm', 'in2')]),
]) # fmt:skip
else:
# sources are bold_file, motion_xfm, boldref2anat_xfm, fsnative2t1w_xfm
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would include the white-matter and pial surfaces for each hemisphere, since those determine the coordinates at which the BOLD is sampled. If that's difficult to do at the moment, I'm fine with postponing it to another PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hemisphere loop happens within init_bold_surf_wf, so I need to add those sources there, but I can't pin down where exactly those two files are grabbed in the workflow. I think it'll have to wait for another PR.

merge_surface_sources = pe.Node(
niu.Merge(4),
name='merge_surface_sources',
run_without_submitting=True,
)
merge_surface_sources.inputs.in1 = bold_file
workflow.connect([
(bold_fit_wf, merge_surface_sources, [
('outputnode.motion_xfm', 'in2'),
('outputnode.boldref2anat_xfm', 'in3'),
]),
(inputnode, merge_surface_sources, [
('fsnative2t1w_xfm', 'in4'),
]),
]) # fmt:skip

workflow.connect([(merge_surface_sources, bold_surf_wf, [('out', 'inputnode.sources')])])

if config.workflow.cifti_output:
from .resampling import (
init_bold_fsLR_resampling_wf,
Expand Down
9 changes: 9 additions & 0 deletions fmriprep/workflows/bold/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,14 @@ def init_ds_volumes_wf(
),
name='inputnode',
)
outputnode = pe.Node(
niu.IdentityInterface(
fields=[
'bold',
],
),
name='outputnode',
)
tsalo marked this conversation as resolved.
Show resolved Hide resolved

sources = pe.Node(
BIDSURI(
Expand Down Expand Up @@ -791,6 +799,7 @@ def init_ds_volumes_wf(
('resolution', 'resolution'),
]),
(sources, ds_bold, [('out', 'Sources')]),
(ds_bold, outputnode, [('out_file', 'bold')]),
]) # fmt:skip

resample_ref = pe.Node(
Expand Down
30 changes: 22 additions & 8 deletions fmriprep/workflows/bold/resampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
from niworkflows.interfaces.fixes import FixHeaderApplyTransforms as ApplyTransforms
from niworkflows.interfaces.freesurfer import MedialNaNs

from ... import config
from ...config import DEFAULT_MEMORY_MIN_GB
from ...interfaces.bids import BIDSURI
from ...interfaces.workbench import MetricDilate, MetricMask, MetricResample
from ...utils.bids import dismiss_echo
from .outputs import prepare_timing_parameters
Expand Down Expand Up @@ -93,6 +95,8 @@ def init_bold_surf_wf(
------
source_file
Original BOLD series
sources
List of files used to create the output files.
bold_t1w
Motion-corrected BOLD series in T1 space
subjects_dir
Expand Down Expand Up @@ -128,6 +132,7 @@ def init_bold_surf_wf(
niu.IdentityInterface(
fields=[
'source_file',
'sources',
'bold_t1w',
'subject_id',
'subjects_dir',
Expand All @@ -139,6 +144,15 @@ def init_bold_surf_wf(
itersource = pe.Node(niu.IdentityInterface(fields=['target']), name='itersource')
itersource.iterables = [('target', surface_spaces)]

surfs_sources = pe.Node(
BIDSURI(
numinputs=1,
dataset_links=config.execution.dataset_links,
out_dir=str(config.execution.fmriprep_dir.absolute()),
),
name='surfs_sources',
)

get_fsnative = pe.Node(FreeSurferSource(), name='get_fsnative', run_without_submitting=True)

def select_target(subject_id, space):
Expand Down Expand Up @@ -212,6 +226,8 @@ def select_target(subject_id, space):
(itk2lta, sampler, [('out_inv', 'reg_file')]),
(targets, sampler, [('out', 'target_subject')]),
(inputnode, ds_bold_surfs, [('source_file', 'source_file')]),
(inputnode, surfs_sources, [('sources', 'in1')]),
(surfs_sources, ds_bold_surfs, [('out', 'Sources')]),
(itersource, ds_bold_surfs, [('target', 'space')]),
(update_metadata, ds_bold_surfs, [('out_file', 'in_file')]),
]) # fmt:skip
Expand Down Expand Up @@ -488,14 +504,12 @@ def _calc_lower_thr(in_stats):
)

# apply goodvoxels ribbon mask to bold
workflow.connect(
[
(goodvoxels_mask, goodvoxels_ribbon_mask, [('out_file', 'in_file')]),
(ribbon_boldsrc_xfm, goodvoxels_ribbon_mask, [('output_image', 'mask_file')]),
(goodvoxels_mask, outputnode, [('out_file', 'goodvoxels_mask')]),
(goodvoxels_ribbon_mask, outputnode, [('out_file', 'goodvoxels_ribbon')]),
]
)
workflow.connect([
(goodvoxels_mask, goodvoxels_ribbon_mask, [('out_file', 'in_file')]),
(ribbon_boldsrc_xfm, goodvoxels_ribbon_mask, [('output_image', 'mask_file')]),
(goodvoxels_mask, outputnode, [('out_file', 'goodvoxels_mask')]),
(goodvoxels_ribbon_mask, outputnode, [('out_file', 'goodvoxels_ribbon')]),
]) # fmt:skip

return workflow

Expand Down