5
5
from nipype .pipeline import engine as pe
6
6
from nipype .interfaces import utility as niu
7
7
8
- from ...config import DEFAULT_MEMORY_MIN_GB
8
+ from ... import config
9
9
from ...interfaces import DerivativesDataSink
10
10
11
11
12
12
def prepare_timing_parameters (metadata ):
13
- """Convert initial timing metadata to post-realignment timing metadata
14
-
13
+ """ Convert initial timing metadata to post-realignment timing metadata
15
14
In particular, SliceTiming metadata is invalid once STC or any realignment is applied,
16
15
as a matrix of voxels no longer corresponds to an acquisition slice.
17
16
Therefore, if SliceTiming is present in the metadata dictionary, and a sparse
18
17
acquisition paradigm is detected, DelayTime or AcquisitionDuration must be derived to
19
18
preserve the timing interpretation.
20
-
21
19
Examples
22
20
--------
23
-
21
+ .. testsetup::
22
+ >>> from unittest import mock
23
+ If SliceTiming metadata is absent, then the only change is to note that
24
+ STC has not been applied:
24
25
>>> prepare_timing_parameters(dict(RepetitionTime=2))
25
- {'RepetitionTime': 2}
26
+ {'RepetitionTime': 2, 'SliceTimingCorrected': False }
26
27
>>> prepare_timing_parameters(dict(RepetitionTime=2, DelayTime=0.5))
27
- {'RepetitionTime': 2, 'DelayTime': 0.5}
28
- >>> prepare_timing_parameters(dict(RepetitionTime=2, SliceTiming=[0.0, 0.2, 0.4, 0.6]))
29
- {'RepetitionTime': 2, 'DelayTime': 1.2}
28
+ {'RepetitionTime': 2, 'DelayTime': 0.5, 'SliceTimingCorrected': False}
30
29
>>> prepare_timing_parameters(dict(VolumeTiming=[0.0, 1.0, 2.0, 5.0, 6.0, 7.0],
31
30
... AcquisitionDuration=1.0))
32
- {'VolumeTiming': [0.0, 1.0, 2.0, 5.0, 6.0, 7.0], 'AcquisitionDuration': 1.0}
33
- >>> prepare_timing_parameters(dict(VolumeTiming=[0.0, 1.0, 2.0, 5.0, 6.0, 7.0],
34
- ... SliceTiming=[0.0, 0.2, 0.4, 0.6, 0.8]))
35
- {'VolumeTiming': [0.0, 1.0, 2.0, 5.0, 6.0, 7.0], 'AcquisitionDuration': 1.0}
36
-
31
+ {'VolumeTiming': [0.0, 1.0, 2.0, 5.0, 6.0, 7.0], 'AcquisitionDuration': 1.0,
32
+ 'SliceTimingCorrected': False}
33
+ When SliceTiming is available and used, then ``SliceTimingCorrected`` is ``True``
34
+ and the ``StartTime`` indicates a series offset.
35
+ >>> with mock.patch("fmriprep.config.workflow.ignore", []):
36
+ ... prepare_timing_parameters(dict(RepetitionTime=2, SliceTiming=[0.0, 0.2, 0.4, 0.6]))
37
+ {'RepetitionTime': 2, 'SliceTimingCorrected': True, 'DelayTime': 1.2, 'StartTime': 0.3}
38
+ >>> with mock.patch("fmriprep.config.workflow.ignore", []):
39
+ ... prepare_timing_parameters(dict(VolumeTiming=[0.0, 1.0, 2.0, 5.0, 6.0, 7.0],
40
+ ... SliceTiming=[0.0, 0.2, 0.4, 0.6, 0.8]))
41
+ {'VolumeTiming': [0.0, 1.0, 2.0, 5.0, 6.0, 7.0], 'SliceTimingCorrected': True,
42
+ 'AcquisitionDuration': 1.0, 'StartTime': 0.4}
43
+ When SliceTiming is available and not used, then ``SliceTimingCorrected`` is ``False``
44
+ and TA is indicated with ``DelayTime`` or ``AcquisitionDuration``.
45
+ >>> with mock.patch("fmriprep.config.workflow.ignore", ["slicetiming"]):
46
+ ... prepare_timing_parameters(dict(RepetitionTime=2, SliceTiming=[0.0, 0.2, 0.4, 0.6]))
47
+ {'RepetitionTime': 2, 'SliceTimingCorrected': False, 'DelayTime': 1.2}
48
+ >>> with mock.patch("fmriprep.config.workflow.ignore", ["slicetiming"]):
49
+ ... prepare_timing_parameters(dict(VolumeTiming=[0.0, 1.0, 2.0, 5.0, 6.0, 7.0],
50
+ ... SliceTiming=[0.0, 0.2, 0.4, 0.6, 0.8]))
51
+ {'VolumeTiming': [0.0, 1.0, 2.0, 5.0, 6.0, 7.0], 'SliceTimingCorrected': False,
52
+ 'AcquisitionDuration': 1.0}
37
53
"""
38
54
timing_parameters = {
39
55
key : metadata [key ]
40
- for key in (
41
- "RepetitionTime" ,
42
- "VolumeTiming" ,
43
- "DelayTime" ,
44
- "AcquisitionDuration" ,
45
- "SliceTiming" ,
46
- )
47
- if key in metadata
48
- }
56
+ for key in ("RepetitionTime" , "VolumeTiming" , "DelayTime" ,
57
+ "AcquisitionDuration" , "SliceTiming" )
58
+ if key in metadata }
59
+
60
+ run_stc = "SliceTiming" in metadata and 'slicetiming' not in config .workflow .ignore
61
+ timing_parameters ["SliceTimingCorrected" ] = run_stc
49
62
50
63
if "SliceTiming" in timing_parameters :
51
64
st = sorted (timing_parameters .pop ("SliceTiming" ))
@@ -58,6 +71,13 @@ def prepare_timing_parameters(metadata):
58
71
# For variable TR paradigms, use AcquisitionDuration
59
72
elif "VolumeTiming" in timing_parameters :
60
73
timing_parameters ["AcquisitionDuration" ] = TA
74
+
75
+ if run_stc :
76
+ first , last = st [0 ], st [- 1 ]
77
+ frac = config .workflow .slice_time_ref
78
+ tzero = np .round (first + frac * (last - first ), 3 )
79
+ timing_parameters ["StartTime" ] = tzero
80
+
61
81
return timing_parameters
62
82
63
83
@@ -162,7 +182,7 @@ def init_func_derivatives_wf(
162
182
),
163
183
name = "ds_confounds" ,
164
184
run_without_submitting = True ,
165
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
185
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
166
186
)
167
187
ds_ref_t1w_xfm = pe .Node (
168
188
DerivativesDataSink (
@@ -216,7 +236,7 @@ def init_func_derivatives_wf(
216
236
),
217
237
name = "ds_bold_native" ,
218
238
run_without_submitting = True ,
219
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
239
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
220
240
)
221
241
ds_bold_native_ref = pe .Node (
222
242
DerivativesDataSink (
@@ -227,7 +247,7 @@ def init_func_derivatives_wf(
227
247
),
228
248
name = "ds_bold_native_ref" ,
229
249
run_without_submitting = True ,
230
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
250
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
231
251
)
232
252
ds_bold_mask_native = pe .Node (
233
253
DerivativesDataSink (
@@ -239,7 +259,7 @@ def init_func_derivatives_wf(
239
259
),
240
260
name = "ds_bold_mask_native" ,
241
261
run_without_submitting = True ,
242
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
262
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
243
263
)
244
264
245
265
# fmt: off
@@ -268,7 +288,7 @@ def init_func_derivatives_wf(
268
288
),
269
289
name = "ds_bold_t1" ,
270
290
run_without_submitting = True ,
271
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
291
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
272
292
)
273
293
ds_bold_t1_ref = pe .Node (
274
294
DerivativesDataSink (
@@ -280,7 +300,7 @@ def init_func_derivatives_wf(
280
300
),
281
301
name = "ds_bold_t1_ref" ,
282
302
run_without_submitting = True ,
283
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
303
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
284
304
)
285
305
ds_bold_mask_t1 = pe .Node (
286
306
DerivativesDataSink (
@@ -293,7 +313,7 @@ def init_func_derivatives_wf(
293
313
),
294
314
name = "ds_bold_mask_t1" ,
295
315
run_without_submitting = True ,
296
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
316
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
297
317
)
298
318
299
319
# fmt: off
@@ -319,7 +339,7 @@ def init_func_derivatives_wf(
319
339
),
320
340
name = "ds_bold_aseg_t1" ,
321
341
run_without_submitting = True ,
322
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
342
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
323
343
)
324
344
ds_bold_aparc_t1 = pe .Node (
325
345
DerivativesDataSink (
@@ -332,7 +352,7 @@ def init_func_derivatives_wf(
332
352
),
333
353
name = "ds_bold_aparc_t1" ,
334
354
run_without_submitting = True ,
335
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
355
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
336
356
)
337
357
338
358
# fmt: off
@@ -351,7 +371,7 @@ def init_func_derivatives_wf(
351
371
),
352
372
name = "ds_aroma_noise_ics" ,
353
373
run_without_submitting = True ,
354
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
374
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
355
375
)
356
376
ds_melodic_mix = pe .Node (
357
377
DerivativesDataSink (
@@ -362,7 +382,7 @@ def init_func_derivatives_wf(
362
382
),
363
383
name = "ds_melodic_mix" ,
364
384
run_without_submitting = True ,
365
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
385
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
366
386
)
367
387
ds_aroma_std = pe .Node (
368
388
DerivativesDataSink (
@@ -375,7 +395,7 @@ def init_func_derivatives_wf(
375
395
),
376
396
name = "ds_aroma_std" ,
377
397
run_without_submitting = True ,
378
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
398
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
379
399
)
380
400
381
401
# fmt: off
@@ -406,7 +426,7 @@ def init_func_derivatives_wf(
406
426
KeySelect (fields = ["template" , "bold_std" , "bold_std_ref" , "bold_mask_std" ]),
407
427
name = "select_std" ,
408
428
run_without_submitting = True ,
409
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
429
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
410
430
)
411
431
412
432
ds_bold_std = pe .Node (
@@ -420,7 +440,7 @@ def init_func_derivatives_wf(
420
440
),
421
441
name = "ds_bold_std" ,
422
442
run_without_submitting = True ,
423
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
443
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
424
444
)
425
445
ds_bold_std_ref = pe .Node (
426
446
DerivativesDataSink (
@@ -431,7 +451,7 @@ def init_func_derivatives_wf(
431
451
),
432
452
name = "ds_bold_std_ref" ,
433
453
run_without_submitting = True ,
434
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
454
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
435
455
)
436
456
ds_bold_mask_std = pe .Node (
437
457
DerivativesDataSink (
@@ -443,7 +463,7 @@ def init_func_derivatives_wf(
443
463
),
444
464
name = "ds_bold_mask_std" ,
445
465
run_without_submitting = True ,
446
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
466
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
447
467
)
448
468
449
469
# fmt: off
@@ -481,7 +501,7 @@ def init_func_derivatives_wf(
481
501
KeySelect (fields = ["bold_aseg_std" , "bold_aparc_std" , "template" ]),
482
502
name = "select_fs_std" ,
483
503
run_without_submitting = True ,
484
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
504
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
485
505
)
486
506
ds_bold_aseg_std = pe .Node (
487
507
DerivativesDataSink (
@@ -493,7 +513,7 @@ def init_func_derivatives_wf(
493
513
),
494
514
name = "ds_bold_aseg_std" ,
495
515
run_without_submitting = True ,
496
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
516
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
497
517
)
498
518
ds_bold_aparc_std = pe .Node (
499
519
DerivativesDataSink (
@@ -505,7 +525,7 @@ def init_func_derivatives_wf(
505
525
),
506
526
name = "ds_bold_aparc_std" ,
507
527
run_without_submitting = True ,
508
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
528
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
509
529
)
510
530
511
531
# fmt: off
@@ -538,7 +558,7 @@ def init_func_derivatives_wf(
538
558
KeySelect (fields = ["surfaces" , "surf_kwargs" ]),
539
559
name = "select_fs_surf" ,
540
560
run_without_submitting = True ,
541
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
561
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
542
562
)
543
563
select_fs_surf .iterables = [("key" , fs_outputs )]
544
564
select_fs_surf .inputs .surf_kwargs = [{"space" : s } for s in fs_outputs ]
@@ -560,7 +580,7 @@ def init_func_derivatives_wf(
560
580
iterfield = ["in_file" , "hemi" ],
561
581
name = "ds_bold_surfs" ,
562
582
run_without_submitting = True ,
563
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
583
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
564
584
)
565
585
566
586
# fmt: off
@@ -588,7 +608,7 @@ def init_func_derivatives_wf(
588
608
),
589
609
name = "ds_bold_cifti" ,
590
610
run_without_submitting = True ,
591
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
611
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
592
612
)
593
613
594
614
# fmt: off
@@ -690,7 +710,7 @@ def init_bold_preproc_report_wf(mem_gb, reportlets_dir, name="bold_preproc_repor
690
710
dismiss_entities = ("echo" ,),
691
711
),
692
712
name = "ds_report_bold" ,
693
- mem_gb = DEFAULT_MEMORY_MIN_GB ,
713
+ mem_gb = config . DEFAULT_MEMORY_MIN_GB ,
694
714
run_without_submitting = True ,
695
715
)
696
716
0 commit comments