Skip to content

Commit 451954b

Browse files
committed
feat: Extract bbregister costs, if run
1 parent f97f343 commit 451954b

File tree

1 file changed

+36
-6
lines changed

1 file changed

+36
-6
lines changed

fmriprep/workflows/bold/registration.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ def init_bbreg_wf(
278278
from nipype.interfaces.freesurfer import BBRegister
279279
from niworkflows.engine.workflows import LiterateWorkflow as Workflow
280280
from niworkflows.interfaces.nitransforms import ConcatenateXFMs
281+
from niworkflows.interfaces.utility import DictMerge
281282

282283
from fmriprep.interfaces.patches import FreeSurferSource, MRICoreg
283284

@@ -346,6 +347,8 @@ def init_bbreg_wf(
346347
dof=bold2anat_dof,
347348
contrast_type='t2',
348349
out_lta_file=True,
350+
# Bug in nipype prevents using init_cost_file=True
351+
init_cost_file='bbregister.initcost',
349352
),
350353
name='bbregister',
351354
mem_gb=12,
@@ -362,8 +365,11 @@ def init_bbreg_wf(
362365
merge_ltas = pe.Node(niu.Merge(2), name='merge_ltas', run_without_submitting=True)
363366
concat_xfm = pe.Node(ConcatenateXFMs(inverse=True), name='concat_xfm')
364367

368+
# Set up GeneratedBy metadata and add a merge node for cost, if available
369+
gen_by = pe.Node(niu.Merge(2), run_without_submitting=True, name='gen_by')
370+
select_gen = pe.Node(niu.Select(index=0), run_without_submitting=True, name='select_gen')
365371
metadata = pe.Node(niu.Merge(2), run_without_submitting=True, name='metadata')
366-
select_meta = pe.Node(niu.Select(index=0), run_without_submitting=True, name='select_meta')
372+
merge_meta = pe.Node(DictMerge(), run_without_submitting=True, name='merge_meta')
367373

368374
workflow.connect([
369375
(inputnode, merge_ltas, [('fsnative2t1w_xfm', 'in2')]),
@@ -374,13 +380,15 @@ def init_bbreg_wf(
374380
(concat_xfm, outputnode, [('out_xfm', 'itk_bold_to_t1')]),
375381
(concat_xfm, outputnode, [('out_inv', 'itk_t1_to_bold')]),
376382
# Wire up the metadata alternatives
377-
(metadata, select_meta, [('out', 'inlist')]),
378-
(select_meta, outputnode, [('out', 'metadata')]),
383+
(gen_by, select_gen, [('out', 'inlist')]),
384+
(select_gen, metadata, [('out', 'in1')]),
385+
(metadata, merge_meta, [('out', 'in_dicts')]),
386+
(merge_meta, outputnode, [('out_dict', 'metadata')]),
379387
]) # fmt:skip
380388

381389
# Do not initialize with header, use mri_coreg
382390
if bold2anat_init != 'header':
383-
metadata.inputs.in2 = {
391+
gen_by.inputs.in2 = {
384392
'GeneratedBy': [
385393
{'Name': 'mri_coreg', 'Version': mri_coreg.interface.version or '<unknown>'}
386394
]
@@ -416,12 +424,26 @@ def init_bbreg_wf(
416424
(bbregister, transforms, [('out_lta_file', 'in1')]),
417425
]) # fmt:skip
418426

419-
metadata.inputs.in1 = {
427+
gen_by.inputs.in1 = {
420428
'GeneratedBy': [
421429
{'Name': 'bbregister', 'Version': bbregister.interface.version or '<unknown>'}
422430
]
423431
}
424432

433+
costs = pe.Node(niu.Merge(2), run_without_submitting=True, name='cost')
434+
select_cost = pe.Node(niu.Select(index=0), run_without_submitting=True, name='select_cost')
435+
read_cost = pe.Node(niu.Function(function=_read_cost), name='read_cost')
436+
437+
workflow.connect([
438+
(bbregister, costs, [
439+
('min_cost_file', 'in1'),
440+
('init_cost_file', 'in2'),
441+
]),
442+
(costs, select_cost, [('out', 'inlist')]),
443+
(select_cost, read_cost, [('out', 'cost_file')]),
444+
(read_cost, metadata, [('out', 'in2')]),
445+
]) # fmt:skip
446+
425447
# Short-circuit workflow building, use boundary-based registration
426448
if use_bbr is True:
427449
outputnode.inputs.fallback = False
@@ -435,7 +457,8 @@ def init_bbreg_wf(
435457
(transforms, compare_transforms, [('out', 'lta_list')]),
436458
(compare_transforms, outputnode, [('out', 'fallback')]),
437459
(compare_transforms, select_transform, [('out', 'index')]),
438-
(compare_transforms, select_meta, [('out', 'index')]),
460+
(compare_transforms, select_gen, [('out', 'index')]),
461+
(compare_transforms, select_cost, [('out', 'index')]),
439462
]) # fmt:skip
440463

441464
return workflow
@@ -792,3 +815,10 @@ def _conditional_downsampling(in_file, in_mask, zoom_th=4.0):
792815
nb.Nifti1Image(newmaskdata, newmask.affine, hdr).to_filename(out_mask)
793816

794817
return str(out_file), str(out_mask)
818+
819+
820+
def _read_cost(cost_file) -> dict[str, float]:
821+
"""Read a cost from a file."""
822+
# Cost file contains mincost, WM intensity, Ctx intensity, Pct Contrast
823+
with open(cost_file) as fobj:
824+
return {'FinalCost': float(fobj.read().split()[0])}

0 commit comments

Comments
 (0)