@@ -222,6 +222,7 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
222
222
'magnitude2' : 'sub-03/ses-2/fmap/sub-03_ses-2_run-1_magnitude2.nii.gz'
223
223
}]
224
224
run_stc = True
225
+ bold_pe = 'j'
225
226
else :
226
227
metadata = layout .get_metadata (bold_file )
227
228
# Find fieldmaps. Options: (phase1|phase2|phasediff|epi|fieldmap)
@@ -232,6 +233,7 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
232
233
run_stc = ("SliceTiming" in metadata and
233
234
'slicetiming' not in ignore and
234
235
(_get_series_len (bold_file ) > 4 or "TooShort" ))
236
+ bold_pe = metadata .get ("PhaseEncodingDirection" )
235
237
236
238
# TODO: To be removed (supported fieldmaps):
237
239
if not set ([fmap ['type' ] for fmap in fmaps ]).intersection (['phasediff' , 'fieldmap' , 'epi' ]):
@@ -254,7 +256,8 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
254
256
'aroma_noise_ics' , 'melodic_mix' , 'nonaggr_denoised_file' ]),
255
257
name = 'outputnode' )
256
258
257
- summary = pe .Node (FunctionalSummary (output_spaces = output_spaces ), name = 'summary' ,
259
+ summary = pe .Node (FunctionalSummary (output_spaces = output_spaces ,
260
+ pe_direction = bold_pe ), name = 'summary' ,
258
261
mem_gb = 0.05 )
259
262
summary .inputs .slice_timing = run_stc
260
263
summary .inputs .registration = 'bbregister' if freesurfer else 'FLIRT'
@@ -462,16 +465,14 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
462
465
463
466
if use_syn :
464
467
nonlinear_sdc_wf = init_nonlinear_sdc_wf (
465
- bold_file = bold_file , layout = layout , freesurfer = freesurfer , bold2t1w_dof = bold2t1w_dof ,
468
+ bold_file = bold_file , bold_pe = bold_pe , freesurfer = freesurfer , bold2t1w_dof = bold2t1w_dof ,
466
469
template = template , omp_nthreads = omp_nthreads )
467
470
468
471
workflow .connect ([
469
472
(inputnode , nonlinear_sdc_wf , [
470
473
('t1_brain' , 'inputnode.t1_brain' ),
471
474
('t1_seg' , 'inputnode.t1_seg' ),
472
- ('t1_2_mni_reverse_transform' , 'inputnode.t1_2_mni_reverse_transform' ),
473
- ('subjects_dir' , 'inputnode.subjects_dir' ),
474
- ('subject_id' , 'inputnode.subject_id' )]),
475
+ ('t1_2_mni_reverse_transform' , 'inputnode.t1_2_mni_reverse_transform' )]),
475
476
(bold_reference_wf , nonlinear_sdc_wf , [
476
477
('outputnode.ref_image_brain' , 'inputnode.bold_ref' )]),
477
478
(nonlinear_sdc_wf , func_reports_wf , [
@@ -896,9 +897,9 @@ def init_bold_reg_wf(freesurfer, bold2t1w_dof, bold_file_size_gb, omp_nthreads,
896
897
)
897
898
898
899
if freesurfer :
899
- bbr_wf = init_bbreg_wf (bold2t1w_dof , report = True )
900
+ bbr_wf = init_bbreg_wf (bold2t1w_dof )
900
901
else :
901
- bbr_wf = init_fsl_bbr_wf (bold2t1w_dof , report = True )
902
+ bbr_wf = init_fsl_bbr_wf (bold2t1w_dof )
902
903
903
904
workflow .connect ([
904
905
(inputnode , bbr_wf , [
@@ -1242,20 +1243,17 @@ def _aslist(in_value):
1242
1243
return workflow
1243
1244
1244
1245
1245
- def init_nonlinear_sdc_wf (bold_file , layout , freesurfer , bold2t1w_dof ,
1246
- template , omp_nthreads ,
1246
+ def init_nonlinear_sdc_wf (bold_file , freesurfer , bold2t1w_dof ,
1247
+ template , omp_nthreads , bold_pe = 'j' ,
1247
1248
atlas_threshold = 3 , name = 'nonlinear_sdc_wf' ):
1248
1249
"""
1249
1250
This workflow takes a skull-stripped T1w image and reference BOLD image and
1250
1251
estimates a susceptibility distortion correction warp, using ANTs symmetric
1251
1252
normalization (SyN) and the average fieldmap atlas described in
1252
1253
[Treiber2016]_.
1253
1254
1254
- If the phase-encoding (PE) direction is known, the SyN deformation is
1255
- restricted to that direction; otherwise, deformation fields are calculated
1256
- for both the right-left and anterior-posterior directions, and selected
1257
- based on the unwarped file that can be aligned to the T1w image with the
1258
- lowest boundary-based registration (BBR) cost.
1255
+ SyN deformation is restricted to the phase-encoding (PE) direction.
1256
+ If no PE direction is specified, anterior-posterior PE is assumed.
1259
1257
1260
1258
SyN deformation is also restricted to regions that are expected to have a
1261
1259
>3mm (approximately 1 voxel) warp, based on the fieldmap atlas.
@@ -1270,7 +1268,7 @@ def init_nonlinear_sdc_wf(bold_file, layout, freesurfer, bold2t1w_dof,
1270
1268
from fmriprep.workflows.bold import init_nonlinear_sdc_wf
1271
1269
wf = init_nonlinear_sdc_wf(
1272
1270
bold_file='/dataset/sub-01/func/sub-01_task-rest_bold.nii.gz',
1273
- layout=None ,
1271
+ bold_pe='j' ,
1274
1272
freesurfer=True,
1275
1273
bold2t1w_dof=9,
1276
1274
template='MNI152NLin2009cAsym',
@@ -1286,10 +1284,6 @@ def init_nonlinear_sdc_wf(bold_file, layout, freesurfer, bold2t1w_dof,
1286
1284
FAST segmentation white and gray matter, in native T1w space
1287
1285
t1_2_mni_reverse_transform
1288
1286
inverse registration transform of T1w image to MNI template
1289
- subjects_dir
1290
- FreeSurfer subjects directory (if applicable)
1291
- subject_id
1292
- FreeSurfer subject_id (if applicable)
1293
1287
1294
1288
Outputs
1295
1289
@@ -1320,13 +1314,17 @@ def init_nonlinear_sdc_wf(bold_file, layout, freesurfer, bold2t1w_dof,
1320
1314
workflow = pe .Workflow (name = name )
1321
1315
inputnode = pe .Node (
1322
1316
niu .IdentityInterface (['t1_brain' , 'bold_ref' , 't1_2_mni_reverse_transform' ,
1323
- 'subjects_dir' , 'subject_id' , ' t1_seg' ]), # BBR requirements
1317
+ 't1_seg' ]),
1324
1318
name = 'inputnode' )
1325
1319
outputnode = pe .Node (
1326
1320
niu .IdentityInterface (['out_reference_brain' , 'out_mask' , 'out_warp' ,
1327
1321
'out_warp_report' , 'out_mask_report' ]),
1328
1322
name = 'outputnode' )
1329
1323
1324
+ if bold_pe is None or bold_pe not in ['i' , 'j' ]:
1325
+ LOGGER .warning ('Incorrect phase-encoding direction, assuming PA (posterior-to-anterior' )
1326
+ bold_pe = 'j'
1327
+
1330
1328
# Collect predefined data
1331
1329
# Atlas image and registration affine
1332
1330
atlas_img = pkgr .resource_filename ('fmriprep' , 'data/fmap_atlas.nii.gz' )
@@ -1369,22 +1367,11 @@ def init_nonlinear_sdc_wf(bold_file, layout, freesurfer, bold2t1w_dof,
1369
1367
mem_gb = DEFAULT_MEMORY_MIN_GB )
1370
1368
fixed_image_masks .inputs .in1 = 'NULL'
1371
1369
1372
- if layout is None :
1373
- bold_pe = None
1374
- else :
1375
- bold_pe = layout .get_metadata (bold_file ).get ("PhaseEncodingDirection" )
1376
-
1377
- restrict_i = [[1 , 0 , 0 ], [1 , 0 , 0 ]]
1378
- restrict_j = [[0 , 1 , 0 ], [0 , 1 , 0 ]]
1379
-
1380
- syn_i = pe .Node (
1381
- ants .Registration (from_file = syn_transform , num_threads = omp_nthreads ,
1382
- restrict_deformation = restrict_i ),
1383
- name = 'syn_i' , n_procs = omp_nthreads )
1384
- syn_j = pe .Node (
1370
+ restrict = [[int (bold_pe [0 ] == 'i' ), int (bold_pe [0 ] == 'j' ), 0 ]] * 2
1371
+ syn = pe .Node (
1385
1372
ants .Registration (from_file = syn_transform , num_threads = omp_nthreads ,
1386
- restrict_deformation = restrict_j ),
1387
- name = 'syn_j ' , n_procs = omp_nthreads )
1373
+ restrict_deformation = restrict ),
1374
+ name = 'syn ' , n_procs = omp_nthreads )
1388
1375
1389
1376
seg_2_ref = pe .Node (
1390
1377
ants .ApplyTransforms (interpolation = 'NearestNeighbor' , float = True ,
@@ -1411,79 +1398,23 @@ def init_nonlinear_sdc_wf(bold_file, layout, freesurfer, bold2t1w_dof,
1411
1398
(transform_list , atlas_2_ref , [('out' , 'transforms' )]),
1412
1399
(atlas_2_ref , threshold_atlas , [('output_image' , 'in_file' )]),
1413
1400
(threshold_atlas , fixed_image_masks , [('out_file' , 'in2' )]),
1414
- ])
1415
-
1416
- if bold_pe is None :
1417
- if freesurfer :
1418
- bbr_i_wf = init_bbreg_wf (bold2t1w_dof , report = False , reregister = False , name = 'bbr_i_wf' )
1419
- bbr_j_wf = init_bbreg_wf (bold2t1w_dof , report = False , reregister = False , name = 'bbr_j_wf' )
1420
- else :
1421
- bbr_i_wf = init_fsl_bbr_wf (bold2t1w_dof , report = False , name = 'bbr_i_wf' )
1422
- bbr_j_wf = init_fsl_bbr_wf (bold2t1w_dof , report = False , name = 'bbr_j_wf' )
1423
-
1424
- def select_outputs (cost_i , warped_image_i , forward_transforms_i ,
1425
- cost_j , warped_image_j , forward_transforms_j ):
1426
- if cost_i < cost_j :
1427
- return warped_image_i , forward_transforms_i
1428
- else :
1429
- return warped_image_j , forward_transforms_j
1430
-
1431
- pe_chooser = pe .Node (
1432
- niu .Function (function = select_outputs ,
1433
- output_names = ['warped_image' , 'forward_transforms' ]),
1434
- name = 'pe_chooser' , mem_gb = DEFAULT_MEMORY_MIN_GB )
1435
-
1436
- workflow .connect ([(inputnode , syn_i , [('bold_ref' , 'moving_image' )]),
1437
- (t1_2_ref , syn_i , [('output_image' , 'fixed_image' )]),
1438
- (fixed_image_masks , syn_i , [('out' , 'fixed_image_masks' )]),
1439
- (inputnode , syn_j , [('bold_ref' , 'moving_image' )]),
1440
- (t1_2_ref , syn_j , [('output_image' , 'fixed_image' )]),
1441
- (fixed_image_masks , syn_j , [('out' , 'fixed_image_masks' )]),
1442
- (inputnode , bbr_i_wf , [('subjects_dir' , 'inputnode.subjects_dir' ),
1443
- ('subject_id' , 'inputnode.subject_id' ),
1444
- ('t1_seg' , 'inputnode.t1_seg' ),
1445
- ('t1_brain' , 'inputnode.t1_brain' )]),
1446
- (inputnode , bbr_j_wf , [('subjects_dir' , 'inputnode.subjects_dir' ),
1447
- ('subject_id' , 'inputnode.subject_id' ),
1448
- ('t1_seg' , 'inputnode.t1_seg' ),
1449
- ('t1_brain' , 'inputnode.t1_brain' )]),
1450
- (syn_i , bbr_i_wf , [('warped_image' , 'inputnode.in_file' )]),
1451
- (syn_j , bbr_j_wf , [('warped_image' , 'inputnode.in_file' )]),
1452
- (bbr_i_wf , pe_chooser , [('outputnode.final_cost' , 'cost_i' )]),
1453
- (bbr_j_wf , pe_chooser , [('outputnode.final_cost' , 'cost_j' )]),
1454
- (syn_i , pe_chooser , [('warped_image' , 'warped_image_i' ),
1455
- ('forward_transforms' , 'forward_transforms_i' )]),
1456
- (syn_j , pe_chooser , [('warped_image' , 'warped_image_j' ),
1457
- ('forward_transforms' , 'forward_transforms_j' )]),
1458
- ])
1459
- syn_out = pe_chooser
1460
- elif bold_pe [0 ] == 'i' :
1461
- workflow .connect ([(inputnode , syn_i , [('bold_ref' , 'moving_image' )]),
1462
- (t1_2_ref , syn_i , [('output_image' , 'fixed_image' )]),
1463
- (fixed_image_masks , syn_i , [('out' , 'fixed_image_masks' )]),
1464
- ])
1465
- syn_out = syn_i
1466
- elif bold_pe [0 ] == 'j' :
1467
- workflow .connect ([(inputnode , syn_j , [('bold_ref' , 'moving_image' )]),
1468
- (t1_2_ref , syn_j , [('output_image' , 'fixed_image' )]),
1469
- (fixed_image_masks , syn_j , [('out' , 'fixed_image_masks' )]),
1470
- ])
1471
- syn_out = syn_j
1472
-
1473
- workflow .connect ([(inputnode , seg_2_ref , [('t1_seg' , 'input_image' )]),
1474
- (ref_2_t1 , seg_2_ref , [('forward_transforms' , 'transforms' )]),
1475
- (syn_out , seg_2_ref , [('warped_image' , 'reference_image' )]),
1476
- (seg_2_ref , sel_wm , [('output_image' , 'in_seg' )]),
1477
- (inputnode , syn_rpt , [('bold_ref' , 'before' )]),
1478
- (syn_out , syn_rpt , [('warped_image' , 'after' )]),
1479
- (sel_wm , syn_rpt , [('out' , 'wm_seg' )]),
1480
- (syn_out , skullstrip_bold_wf , [('warped_image' , 'inputnode.in_file' )]),
1481
- (syn_out , outputnode , [('forward_transforms' , 'out_warp' )]),
1482
- (skullstrip_bold_wf , outputnode , [
1483
- ('outputnode.skull_stripped_file' , 'out_reference_brain' ),
1484
- ('outputnode.mask_file' , 'out_mask' ),
1485
- ('outputnode.out_report' , 'out_mask_report' )]),
1486
- (syn_rpt , outputnode , [('out_report' , 'out_warp_report' )])])
1401
+ (inputnode , syn , [('bold_ref' , 'moving_image' )]),
1402
+ (t1_2_ref , syn , [('output_image' , 'fixed_image' )]),
1403
+ (fixed_image_masks , syn , [('out' , 'fixed_image_masks' )]),
1404
+ (inputnode , seg_2_ref , [('t1_seg' , 'input_image' )]),
1405
+ (ref_2_t1 , seg_2_ref , [('forward_transforms' , 'transforms' )]),
1406
+ (syn , seg_2_ref , [('warped_image' , 'reference_image' )]),
1407
+ (seg_2_ref , sel_wm , [('output_image' , 'in_seg' )]),
1408
+ (inputnode , syn_rpt , [('bold_ref' , 'before' )]),
1409
+ (syn , syn_rpt , [('warped_image' , 'after' )]),
1410
+ (sel_wm , syn_rpt , [('out' , 'wm_seg' )]),
1411
+ (syn , skullstrip_bold_wf , [('warped_image' , 'inputnode.in_file' )]),
1412
+ (syn , outputnode , [('forward_transforms' , 'out_warp' )]),
1413
+ (skullstrip_bold_wf , outputnode , [
1414
+ ('outputnode.skull_stripped_file' , 'out_reference_brain' ),
1415
+ ('outputnode.mask_file' , 'out_mask' ),
1416
+ ('outputnode.out_report' , 'out_mask_report' )]),
1417
+ (syn_rpt , outputnode , [('out_report' , 'out_warp_report' )])])
1487
1418
1488
1419
return workflow
1489
1420
0 commit comments