@@ -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