@@ -278,6 +278,7 @@ def init_bbreg_wf(
278
278
from nipype .interfaces .freesurfer import BBRegister
279
279
from niworkflows .engine .workflows import LiterateWorkflow as Workflow
280
280
from niworkflows .interfaces .nitransforms import ConcatenateXFMs
281
+ from niworkflows .interfaces .utility import DictMerge
281
282
282
283
from fmriprep .interfaces .patches import FreeSurferSource , MRICoreg
283
284
@@ -346,6 +347,8 @@ def init_bbreg_wf(
346
347
dof = bold2anat_dof ,
347
348
contrast_type = 't2' ,
348
349
out_lta_file = True ,
350
+ # Bug in nipype prevents using init_cost_file=True
351
+ init_cost_file = 'bbregister.initcost' ,
349
352
),
350
353
name = 'bbregister' ,
351
354
mem_gb = 12 ,
@@ -362,8 +365,11 @@ def init_bbreg_wf(
362
365
merge_ltas = pe .Node (niu .Merge (2 ), name = 'merge_ltas' , run_without_submitting = True )
363
366
concat_xfm = pe .Node (ConcatenateXFMs (inverse = True ), name = 'concat_xfm' )
364
367
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' )
365
371
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 ' )
367
373
368
374
workflow .connect ([
369
375
(inputnode , merge_ltas , [('fsnative2t1w_xfm' , 'in2' )]),
@@ -374,13 +380,15 @@ def init_bbreg_wf(
374
380
(concat_xfm , outputnode , [('out_xfm' , 'itk_bold_to_t1' )]),
375
381
(concat_xfm , outputnode , [('out_inv' , 'itk_t1_to_bold' )]),
376
382
# 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' )]),
379
387
]) # fmt:skip
380
388
381
389
# Do not initialize with header, use mri_coreg
382
390
if bold2anat_init != 'header' :
383
- metadata .inputs .in2 = {
391
+ gen_by .inputs .in2 = {
384
392
'GeneratedBy' : [
385
393
{'Name' : 'mri_coreg' , 'Version' : mri_coreg .interface .version or '<unknown>' }
386
394
]
@@ -416,12 +424,26 @@ def init_bbreg_wf(
416
424
(bbregister , transforms , [('out_lta_file' , 'in1' )]),
417
425
]) # fmt:skip
418
426
419
- metadata .inputs .in1 = {
427
+ gen_by .inputs .in1 = {
420
428
'GeneratedBy' : [
421
429
{'Name' : 'bbregister' , 'Version' : bbregister .interface .version or '<unknown>' }
422
430
]
423
431
}
424
432
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
+
425
447
# Short-circuit workflow building, use boundary-based registration
426
448
if use_bbr is True :
427
449
outputnode .inputs .fallback = False
@@ -435,7 +457,8 @@ def init_bbreg_wf(
435
457
(transforms , compare_transforms , [('out' , 'lta_list' )]),
436
458
(compare_transforms , outputnode , [('out' , 'fallback' )]),
437
459
(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' )]),
439
462
]) # fmt:skip
440
463
441
464
return workflow
@@ -792,3 +815,10 @@ def _conditional_downsampling(in_file, in_mask, zoom_th=4.0):
792
815
nb .Nifti1Image (newmaskdata , newmask .affine , hdr ).to_filename (out_mask )
793
816
794
817
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