Skip to content

Commit 726584d

Browse files
tsaloeffigies
andauthored
REF: Split final boldref generation from BOLD-BOLD resampling, eliminate extra per-echo computation (#2181)
* Join bold masks and select first echo's mask for multi-echo data. * Fix and consolidate multi-echo-toggled connections. * Replace select_first with pop_file. * Add freesurfer check back in. * Fix up merge. * Apply suggestions from code review Co-authored-by: Chris Markiewicz <[email protected]> * Move final boldref wf to init_func_preproc_wf. * Fix the bugs. * Fix links. * Fix reference image link. * Update fmriprep/workflows/bold/base.py Co-authored-by: Chris Markiewicz <[email protected]> * Update fmriprep/workflows/bold/base.py Co-authored-by: Chris Markiewicz <[email protected]> * Apply suggestions from code review Thanks @effigies. Co-authored-by: Chris Markiewicz <[email protected]> * Update fmriprep/workflows/bold/base.py * Cleanup to minimize diff. Co-authored-by: Chris Markiewicz <[email protected]>
1 parent d9f1072 commit 726584d

File tree

2 files changed

+50
-48
lines changed

2 files changed

+50
-48
lines changed

fmriprep/workflows/bold/base.py

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def init_func_preproc_wf(bold_file):
125125
* :py:func:`~fmriprep.workflows.bold.t2s.init_bold_t2s_wf`
126126
* :py:func:`~fmriprep.workflows.bold.registration.init_bold_t1_trans_wf`
127127
* :py:func:`~fmriprep.workflows.bold.registration.init_bold_reg_wf`
128-
* :py:func:`~fmriprep.workflows.bold.confounds.init_bold_confounds_wf`
128+
* :py:func:`~fmriprep.workflows.bold.confounds.init_bold_confs_wf`
129129
* :py:func:`~fmriprep.workflows.bold.confounds.init_ica_aroma_wf`
130130
* :py:func:`~fmriprep.workflows.bold.resampling.init_bold_std_trans_wf`
131131
* :py:func:`~fmriprep.workflows.bold.resampling.init_bold_preproc_trans_wf`
@@ -307,13 +307,14 @@ def init_func_preproc_wf(bold_file):
307307
])
308308

309309
# Generate a tentative boldref
310-
bold_reference_wf = init_bold_reference_wf(
310+
initial_boldref_wf = init_bold_reference_wf(
311+
name='initial_boldref_wf',
311312
omp_nthreads=omp_nthreads,
312313
bold_file=bold_file,
313314
sbref_files=sbref_files,
314315
multiecho=multiecho,
315316
)
316-
bold_reference_wf.inputs.inputnode.dummy_scans = config.workflow.dummy_scans
317+
initial_boldref_wf.inputs.inputnode.dummy_scans = config.workflow.dummy_scans
317318

318319
# Top-level BOLD splitter
319320
bold_split = pe.Node(FSLSplit(dimension='t'), name='bold_split',
@@ -365,17 +366,26 @@ def init_func_preproc_wf(bold_file):
365366
)
366367
bold_bold_trans_wf.inputs.inputnode.name_source = ref_file
367368

369+
# Generate a new BOLD reference
370+
# This BOLD references *does not use* single-band reference images.
371+
final_boldref_wf = init_bold_reference_wf(
372+
name='final_boldref_wf',
373+
omp_nthreads=omp_nthreads,
374+
multiecho=multiecho,
375+
)
376+
final_boldref_wf.__desc__ = None # Unset description to avoid second appearance
377+
368378
# SLICE-TIME CORRECTION (or bypass) #############################################
369379
if run_stc is True: # bool('TooShort') == True, so check True explicitly
370380
bold_stc_wf = init_bold_stc_wf(name='bold_stc_wf', metadata=metadata)
371381
workflow.connect([
372-
(bold_reference_wf, bold_stc_wf, [
382+
(initial_boldref_wf, bold_stc_wf, [
373383
('outputnode.skip_vols', 'inputnode.skip_vols')]),
374384
(bold_stc_wf, boldbuffer, [('outputnode.stc_file', 'bold_file')]),
375385
])
376386
if not multiecho:
377387
workflow.connect([
378-
(bold_reference_wf, bold_stc_wf, [
388+
(initial_boldref_wf, bold_stc_wf, [
379389
('outputnode.bold_file', 'inputnode.bold_file')])])
380390
else: # for meepi, iterate through stc_wf for all workflows
381391
meepi_echos = boldbuffer.clone(name='meepi_echos')
@@ -385,7 +395,7 @@ def init_func_preproc_wf(bold_file):
385395
elif not multiecho: # STC is too short or False
386396
# bypass STC from original BOLD to the splitter through boldbuffer
387397
workflow.connect([
388-
(bold_reference_wf, boldbuffer, [('outputnode.bold_file', 'bold_file')])])
398+
(initial_boldref_wf, boldbuffer, [('outputnode.bold_file', 'bold_file')])])
389399
else:
390400
# for meepi, iterate over all meepi echos to boldbuffer
391401
boldbuffer.iterables = ('bold_file', bold_file)
@@ -404,10 +414,12 @@ def init_func_preproc_wf(bold_file):
404414

405415
inputnode.inputs.bold_file = ref_file # Replace reference w first echo
406416

407-
join_echos = pe.JoinNode(niu.IdentityInterface(fields=['bold_files']),
408-
joinsource=('meepi_echos' if run_stc is True else 'boldbuffer'),
409-
joinfield=['bold_files'],
410-
name='join_echos')
417+
join_echos = pe.JoinNode(
418+
niu.IdentityInterface(fields=['bold_files', 'skullstripped_bold_files']),
419+
joinsource=('meepi_echos' if run_stc is True else 'boldbuffer'),
420+
joinfield=['bold_files', 'skullstripped_bold_files'],
421+
name='join_echos'
422+
)
411423

412424
# create optimal combination, adaptive T2* map
413425
bold_t2s_wf = init_bold_t2s_wf(echo_times=tes,
@@ -422,10 +434,10 @@ def init_func_preproc_wf(bold_file):
422434
# BOLD buffer has slice-time corrected if it was run, original otherwise
423435
(boldbuffer, bold_split, [('bold_file', 'in_file')]),
424436
# HMC
425-
(bold_reference_wf, bold_hmc_wf, [
437+
(initial_boldref_wf, bold_hmc_wf, [
426438
('outputnode.raw_ref_image', 'inputnode.raw_ref_image'),
427439
('outputnode.bold_file', 'inputnode.bold_file')]),
428-
(bold_reference_wf, summary, [
440+
(initial_boldref_wf, summary, [
429441
('outputnode.algo_dummy_scans', 'algo_dummy_scans')]),
430442
# EPI-T1 registration workflow
431443
(inputnode, bold_reg_wf, [
@@ -456,7 +468,7 @@ def init_func_preproc_wf(bold_file):
456468
# SDC (or pass-through workflow)
457469
(t1w_brain, bold_sdc_wf, [
458470
('out_file', 'inputnode.t1w_brain')]),
459-
(bold_reference_wf, bold_sdc_wf, [
471+
(initial_boldref_wf, bold_sdc_wf, [
460472
('outputnode.ref_image', 'inputnode.epi_file'),
461473
('outputnode.ref_image_brain', 'inputnode.epi_brain'),
462474
('outputnode.bold_mask', 'inputnode.epi_mask')]),
@@ -477,11 +489,10 @@ def init_func_preproc_wf(bold_file):
477489
('outputnode.rmsd_file', 'inputnode.rmsd_file')]),
478490
(bold_reg_wf, bold_confounds_wf, [
479491
('outputnode.itk_t1_to_bold', 'inputnode.t1_bold_xform')]),
480-
(bold_reference_wf, bold_confounds_wf, [
492+
(initial_boldref_wf, bold_confounds_wf, [
481493
('outputnode.skip_vols', 'inputnode.skip_vols')]),
482-
(bold_bold_trans_wf, bold_confounds_wf, [
483-
('outputnode.bold_mask', 'inputnode.bold_mask'),
484-
]),
494+
(final_boldref_wf, bold_confounds_wf, [
495+
('outputnode.bold_mask', 'inputnode.bold_mask')]),
485496
(bold_confounds_wf, outputnode, [
486497
('outputnode.confounds_file', 'confounds'),
487498
]),
@@ -504,6 +515,8 @@ def init_func_preproc_wf(bold_file):
504515
('bold_file', 'inputnode.source_file')]),
505516
(bold_bold_trans_wf, bold_confounds_wf, [
506517
('outputnode.bold', 'inputnode.bold')]),
518+
(bold_bold_trans_wf, final_boldref_wf, [
519+
('outputnode.bold', 'inputnode.bold_file')]),
507520
(bold_split, bold_t1_trans_wf, [
508521
('out_files', 'inputnode.bold_split')]),
509522
(bold_hmc_wf, bold_t1_trans_wf, [
@@ -516,12 +529,16 @@ def init_func_preproc_wf(bold_file):
516529
# update name source for optimal combination
517530
(inputnode, func_derivatives_wf, [
518531
(('bold_file', combine_meepi_source), 'inputnode.source_file')]),
532+
(bold_bold_trans_wf, join_echos, [
533+
('outputnode.bold', 'bold_files')]),
534+
(join_echos, final_boldref_wf, [
535+
('bold_files', 'inputnode.bold_file')]),
519536
(bold_bold_trans_wf, skullstrip_bold_wf, [
520537
('outputnode.bold', 'inputnode.in_file')]),
521538
(skullstrip_bold_wf, join_echos, [
522-
('outputnode.skull_stripped_file', 'bold_files')]),
539+
('outputnode.skull_stripped_file', 'skullstripped_bold_files')]),
523540
(join_echos, bold_t2s_wf, [
524-
('bold_files', 'inputnode.bold_file')]),
541+
('skullstripped_bold_files', 'inputnode.bold_file')]),
525542
(bold_t2s_wf, bold_confounds_wf, [
526543
('outputnode.bold', 'inputnode.bold')]),
527544
(bold_t2s_wf, split_opt_comb, [
@@ -541,7 +558,7 @@ def init_func_preproc_wf(bold_file):
541558
workflow.connect([
542559
(inputnode, fmap_unwarp_report_wf, [
543560
('t1w_dseg', 'inputnode.in_seg')]),
544-
(bold_reference_wf, fmap_unwarp_report_wf, [
561+
(initial_boldref_wf, fmap_unwarp_report_wf, [
545562
('outputnode.ref_image', 'inputnode.in_pre')]),
546563
(bold_reg_wf, fmap_unwarp_report_wf, [
547564
('outputnode.itk_t1_to_bold', 'inputnode.in_xfm')]),
@@ -578,7 +595,7 @@ def init_func_preproc_wf(bold_file):
578595
workflow.connect([
579596
(inputnode, syn_unwarp_report_wf, [
580597
('t1w_dseg', 'inputnode.in_seg')]),
581-
(bold_reference_wf, syn_unwarp_report_wf, [
598+
(initial_boldref_wf, syn_unwarp_report_wf, [
582599
('outputnode.ref_image', 'inputnode.in_pre')]),
583600
(bold_reg_wf, syn_unwarp_report_wf, [
584601
('outputnode.itk_t1_to_bold', 'inputnode.in_xfm')]),
@@ -607,19 +624,19 @@ def init_func_preproc_wf(bold_file):
607624
('outputnode.itk_bold_to_t1', 'transforms')]),
608625
(bold_t1_trans_wf, boldmask_to_t1w, [
609626
('outputnode.bold_mask_t1', 'reference_image')]),
610-
(bold_bold_trans_wf, boldmask_to_t1w, [
627+
(final_boldref_wf, boldmask_to_t1w, [
611628
('outputnode.bold_mask', 'input_image')]),
612629
(boldmask_to_t1w, outputnode, [
613630
('output_image', 'bold_mask_t1')]),
614631
])
615632

616633
if nonstd_spaces.intersection(('func', 'run', 'bold', 'boldref', 'sbref')):
617634
workflow.connect([
618-
(bold_bold_trans_wf, outputnode, [
619-
('outputnode.bold', 'bold_native')]),
620-
(bold_bold_trans_wf, func_derivatives_wf, [
621-
('outputnode.bold_ref', 'inputnode.bold_native_ref'),
635+
(final_boldref_wf, func_derivatives_wf, [
636+
('outputnode.ref_image', 'inputnode.bold_native_ref'),
622637
('outputnode.bold_mask', 'inputnode.bold_mask_native')]),
638+
(bold_bold_trans_wf if not multiecho else bold_t2s_wf, outputnode, [
639+
('outputnode.bold', 'bold_native')])
623640
])
624641

625642
if spaces.get_spaces(nonstandard=False, dim=(3,)):
@@ -640,10 +657,10 @@ def init_func_preproc_wf(bold_file):
640657
('bold_file', 'inputnode.name_source'),
641658
('t1w_aseg', 'inputnode.bold_aseg'),
642659
('t1w_aparc', 'inputnode.bold_aparc')]),
660+
(final_boldref_wf, bold_std_trans_wf, [
661+
('outputnode.bold_mask', 'inputnode.bold_mask')]),
643662
(bold_reg_wf, bold_std_trans_wf, [
644663
('outputnode.itk_bold_to_t1', 'inputnode.itk_bold_to_t1')]),
645-
(bold_bold_trans_wf, bold_std_trans_wf, [
646-
('outputnode.bold_mask', 'inputnode.bold_mask')]),
647664
(bold_std_trans_wf, outputnode, [('outputnode.bold_std', 'bold_std'),
648665
('outputnode.bold_std_ref', 'bold_std_ref'),
649666
('outputnode.bold_mask_std', 'bold_mask_std')]),
@@ -721,7 +738,7 @@ def init_func_preproc_wf(bold_file):
721738
('bold_file', 'inputnode.name_source')]),
722739
(bold_hmc_wf, ica_aroma_wf, [
723740
('outputnode.movpar_file', 'inputnode.movpar_file')]),
724-
(bold_reference_wf, ica_aroma_wf, [
741+
(initial_boldref_wf, ica_aroma_wf, [
725742
('outputnode.skip_vols', 'inputnode.skip_vols')]),
726743
(bold_confounds_wf, join, [
727744
('outputnode.confounds_file', 'in_file')]),
@@ -815,15 +832,16 @@ def init_func_preproc_wf(bold_file):
815832
('std2anat_xfm', 'inputnode.std2anat_xfm')]),
816833
(bold_bold_trans_wf if not multiecho else bold_t2s_wf, carpetplot_wf, [
817834
('outputnode.bold', 'inputnode.bold')]),
818-
(bold_bold_trans_wf, carpetplot_wf, [
835+
(final_boldref_wf, carpetplot_wf, [
819836
('outputnode.bold_mask', 'inputnode.bold_mask')]),
820837
(bold_reg_wf, carpetplot_wf, [
821838
('outputnode.itk_t1_to_bold', 'inputnode.t1_bold_xform')]),
822839
])
823840

824841
workflow.connect([
825842
(bold_confounds_wf, carpetplot_wf, [
826-
('outputnode.confounds_file', 'inputnode.confounds_file')])
843+
('outputnode.confounds_file', 'inputnode.confounds_file')
844+
])
827845
])
828846

829847
# REPORTING ############################################################
@@ -840,7 +858,7 @@ def init_func_preproc_wf(bold_file):
840858

841859
workflow.connect([
842860
(summary, ds_report_summary, [('out_report', 'in_file')]),
843-
(bold_reference_wf, ds_report_validation, [
861+
(initial_boldref_wf, ds_report_validation, [
844862
('outputnode.validation_report', 'in_file')]),
845863
])
846864

fmriprep/workflows/bold/resampling.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -472,16 +472,9 @@ def init_bold_preproc_trans_wf(mem_gb, omp_nthreads,
472472
-------
473473
bold
474474
BOLD series, resampled in native space, including all preprocessing
475-
bold_mask
476-
BOLD series mask calculated with the new time-series
477-
bold_ref
478-
BOLD reference image: an average-like 3D image of the time-series
479-
bold_ref_brain
480-
Same as ``bold_ref``, but once the brain mask has been applied
481475
482476
"""
483477
from niworkflows.engine.workflows import LiterateWorkflow as Workflow
484-
from niworkflows.func.util import init_bold_reference_wf
485478
from niworkflows.interfaces.itk import MultiApplyTransforms
486479
from niworkflows.interfaces.nilearn import Merge
487480

@@ -515,10 +508,6 @@ def init_bold_preproc_trans_wf(mem_gb, omp_nthreads,
515508

516509
merge = pe.Node(Merge(compress=use_compression), name='merge', mem_gb=mem_gb * 3)
517510

518-
# Generate a new BOLD reference
519-
bold_reference_wf = init_bold_reference_wf(omp_nthreads=omp_nthreads)
520-
bold_reference_wf.__desc__ = None # Unset description to avoid second appearance
521-
522511
workflow.connect([
523512
(inputnode, merge_xforms, [('fieldwarp', 'in1'),
524513
('hmc_xforms', 'in2')]),
@@ -527,12 +516,7 @@ def init_bold_preproc_trans_wf(mem_gb, omp_nthreads,
527516
(inputnode, merge, [('name_source', 'header_source')]),
528517
(merge_xforms, bold_transform, [('out', 'transforms')]),
529518
(bold_transform, merge, [('out_files', 'in_files')]),
530-
(merge, bold_reference_wf, [('out_file', 'inputnode.bold_file')]),
531519
(merge, outputnode, [('out_file', 'bold')]),
532-
(bold_reference_wf, outputnode, [
533-
('outputnode.ref_image', 'bold_ref'),
534-
('outputnode.ref_image_brain', 'bold_ref_brain'),
535-
('outputnode.bold_mask', 'bold_mask')]),
536520
])
537521

538522
return workflow

0 commit comments

Comments
 (0)