Skip to content

Commit f41f77c

Browse files
committed
rf: Collate pre-computed and to-compute fieldmaps
1 parent 80942f0 commit f41f77c

File tree

1 file changed

+69
-20
lines changed

1 file changed

+69
-20
lines changed

fmriprep/workflows/base.py

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"""
3131

3232
import os
33+
import re
3334
import sys
3435
import warnings
3536
from copy import deepcopy
@@ -555,11 +556,61 @@ def init_single_subject_wf(subject_id: str):
555556
filters=config.execution.get().get('bids_filters', {}).get('fmap'),
556557
)
557558

559+
fmap_merge_nodes = {
560+
field: pe.Node(niu.Merge(2), name=f'{field}_merge', run_without_submitting=True)
561+
for field in ['fmap', 'fmap_ref', 'fmap_coeff', 'fmap_mask', 'fmap_id', 'sdc_method']
562+
}
563+
564+
fmap_buffer = pe.Node(
565+
niu.IdentityInterface(
566+
fields=['fmap', 'fmap_ref', 'fmap_coeff', 'fmap_mask', 'fmap_id', 'sdc_method']
567+
),
568+
name='fmap_buffer',
569+
)
570+
571+
workflow.connect(
572+
[(fmap_merge_nodes[field], fmap_buffer, [('out', field)]) for field in fmap_merge_nodes]
573+
)
574+
575+
missing_estimators = []
558576
if fmap_estimators:
577+
# Map fmapid entity to internal bids_id
578+
fmapid_map = {re.sub(r'[^a-zA-Z0-9]', '', e.bids_id): e.bids_id for e in fmap_estimators}
579+
pared_cache = {
580+
fmapid_map[fmapid]: fmap_cache[fmapid] for fmapid in fmap_cache if fmapid in fmapid_map
581+
}
582+
583+
missing_estimators = [e for e in fmap_estimators if e.bids_id not in pared_cache]
584+
585+
if pared_cache:
586+
config.loggers.workflow.info(
587+
'Precomputed B0 field inhomogeneity maps found for the following '
588+
f'{len(pared_cache)} estimator(s): {list(pared_cache)}.'
589+
)
590+
591+
fmap_merge_nodes['fmap'].inputs.in1 = [
592+
pared_cache[fmapid]['fieldmap'] for fmapid in pared_cache
593+
]
594+
fmap_merge_nodes['fmap_ref'].inputs.in1 = [
595+
pared_cache[fmapid]['magnitude'] for fmapid in pared_cache
596+
]
597+
fmap_merge_nodes['fmap_coeff'].inputs.in1 = [
598+
pared_cache[fmapid]['coeffs'] for fmapid in pared_cache
599+
]
600+
# Note that masks are not emitted. The BOLD-fmap transforms cannot be
601+
# computed with precomputed fieldmaps until we either start emitting masks
602+
# or start skull-stripping references on the fly.
603+
fmap_merge_nodes['fmap_mask'].inputs.in1 = [
604+
pared_cache[fmapid].get('mask', 'MISSING') for fmapid in pared_cache
605+
]
606+
fmap_merge_nodes['fmap_id'].inputs.in1 = list(pared_cache)
607+
fmap_merge_nodes['sdc_method'].inputs.in1 = ['precomputed'] * len(pared_cache)
608+
609+
if missing_estimators:
559610
config.loggers.workflow.info(
560611
'B0 field inhomogeneity map will be estimated with the following '
561-
f'{len(fmap_estimators)} estimator(s): '
562-
f'{[e.method for e in fmap_estimators]}.'
612+
f'{len(missing_estimators)} estimator(s): '
613+
f'{[e.method for e in missing_estimators]}.'
563614
)
564615

565616
from sdcflows import fieldmaps as fm
@@ -585,24 +636,31 @@ def init_single_subject_wf(subject_id: str):
585636
if node.split('.')[-1].startswith('ds_'):
586637
fmap_wf.get_node(node).interface.out_path_base = ''
587638

639+
workflow.connect([
640+
(fmap_wf, fmap_merge_nodes[field], [
641+
# We get "sdc_method" as "method" from estimator workflows
642+
# All else stays the same, and no other sdc_ prefixes are used
643+
(f'outputnode.{field.removeprefix("sdc_")}', 'in2'),
644+
])
645+
for field in fmap_merge_nodes
646+
]) # fmt:skip
647+
588648
fmap_select_std = pe.Node(
589649
KeySelect(fields=['std2anat_xfm'], key='MNI152NLin2009cAsym'),
590650
name='fmap_select_std',
591651
run_without_submitting=True,
592652
)
593653
if any(estimator.method == fm.EstimatorType.ANAT for estimator in fmap_estimators):
594-
# fmt:off
595654
workflow.connect([
596655
(anat_fit_wf, fmap_select_std, [
597656
('outputnode.std2anat_xfm', 'std2anat_xfm'),
598657
('outputnode.template', 'keys')]),
599-
])
600-
# fmt:on
658+
]) # fmt:skip
601659

602660
for estimator in fmap_estimators:
603661
config.loggers.workflow.info(
604662
f"""\
605-
Setting-up fieldmap "{estimator.bids_id}" ({estimator.method}) with \
663+
Setting up fieldmap "{estimator.bids_id}" ({estimator.method}) with \
606664
<{', '.join(s.path.name for s in estimator.sources)}>"""
607665
)
608666

@@ -645,7 +703,6 @@ def init_single_subject_wf(subject_id: str):
645703
syn_preprocessing_wf.inputs.inputnode.in_epis = sources
646704
syn_preprocessing_wf.inputs.inputnode.in_meta = source_meta
647705

648-
# fmt:off
649706
workflow.connect([
650707
(anat_fit_wf, syn_preprocessing_wf, [
651708
('outputnode.t1w_preproc', 'inputnode.in_anat'),
@@ -661,8 +718,7 @@ def init_single_subject_wf(subject_id: str):
661718
('outputnode.anat_mask', f'in_{estimator.bids_id}.anat_mask'),
662719
('outputnode.sd_prior', f'in_{estimator.bids_id}.sd_prior'),
663720
]),
664-
])
665-
# fmt:on
721+
]) # fmt:skip
666722

667723
# Append the functional section to the existing anatomical excerpt
668724
# That way we do not need to stream down the number of bold datasets
@@ -729,18 +785,11 @@ def init_single_subject_wf(subject_id: str):
729785
'inputnode.sphere_reg_fsLR',
730786
),
731787
]),
788+
(fmap_buffer, bold_wf, [
789+
(field, f'inputnode.{field}')
790+
for field in fmap_merge_nodes
791+
]),
732792
]) # fmt:skip
733-
if fieldmap_id:
734-
workflow.connect([
735-
(fmap_wf, bold_wf, [
736-
('outputnode.fmap', 'inputnode.fmap'),
737-
('outputnode.fmap_ref', 'inputnode.fmap_ref'),
738-
('outputnode.fmap_coeff', 'inputnode.fmap_coeff'),
739-
('outputnode.fmap_mask', 'inputnode.fmap_mask'),
740-
('outputnode.fmap_id', 'inputnode.fmap_id'),
741-
('outputnode.method', 'inputnode.sdc_method'),
742-
]),
743-
]) # fmt:skip
744793

745794
if config.workflow.level == 'full':
746795
if template_iterator_wf is not None:

0 commit comments

Comments
 (0)