19
19
DEFAULT_MEMORY_MIN_GB = 0.01
20
20
21
21
22
- def init_sdc_estimate_wf (fmaps , epi_meta , omp_nthreads = 1 , debug = False , ignore = None ):
22
+ def init_sdc_estimate_wf (fmaps , epi_meta , omp_nthreads = 1 , debug = False ):
23
23
"""
24
24
Build a :abbr:`SDC (susceptibility distortion correction)` workflow.
25
25
@@ -66,8 +66,8 @@ def init_sdc_estimate_wf(fmaps, epi_meta, omp_nthreads=1, debug=False, ignore=No
66
66
67
67
Outputs
68
68
-------
69
- epi_file
70
- An unwarped EPI scan reference
69
+ epi_corrected
70
+ The EPI scan reference after unwarping.
71
71
epi_mask
72
72
The corresponding new mask after unwarping
73
73
epi_brain
@@ -77,6 +77,8 @@ def init_sdc_estimate_wf(fmaps, epi_meta, omp_nthreads=1, debug=False, ignore=No
77
77
syn_ref
78
78
If ``--force-syn``, an unwarped EPI scan reference with this
79
79
method (for reporting purposes)
80
+ method : str
81
+ Short description of the estimation method that was run.
80
82
81
83
"""
82
84
workflow = Workflow (name = 'sdc_estimate_wf' if fmaps else 'sdc_bypass_wf' )
@@ -85,28 +87,25 @@ def init_sdc_estimate_wf(fmaps, epi_meta, omp_nthreads=1, debug=False, ignore=No
85
87
name = 'inputnode' )
86
88
87
89
outputnode = pe .Node (niu .IdentityInterface (
88
- fields = ['output_ref ' , 'epi_mask' , 'epi_brain' ,
90
+ fields = ['epi_corrected ' , 'epi_mask' , 'epi_brain' ,
89
91
'out_warp' , 'syn_ref' , 'method' ]),
90
92
name = 'outputnode' )
91
93
92
94
# No fieldmaps - forward inputs to outputs
93
- ignored = False if ignore is None else 'fieldmaps' in ignore
94
- if not fmaps or ignored :
95
+ if not fmaps :
95
96
workflow .__postdesc__ = """\
96
- Susceptibility distortion correction (SDC) has been skipped because the
97
- dataset does not contain extra field map acquisitions correctly described
98
- with metadata, and the experimental SDC-SyN method was not explicitly selected.
97
+ Susceptibility distortion correction (SDC) was omitted.
99
98
"""
100
99
outputnode .inputs .method = 'None'
101
100
workflow .connect ([
102
- (inputnode , outputnode , [('epi_file' , 'output_ref ' ),
101
+ (inputnode , outputnode , [('epi_file' , 'epi_corrected ' ),
103
102
('epi_mask' , 'epi_mask' ),
104
103
('epi_brain' , 'epi_brain' )]),
105
104
])
106
105
return workflow
107
106
108
107
workflow .__postdesc__ = """\
109
- Based on the estimated susceptibility distortion, an unwarped
108
+ Based on the estimated susceptibility distortion, a corrected
110
109
EPI (echo-planar imaging) reference was calculated for a more
111
110
accurate co-registration with the anatomical reference.
112
111
"""
@@ -151,6 +150,7 @@ def init_sdc_estimate_wf(fmaps, epi_meta, omp_nthreads=1, debug=False, ignore=No
151
150
152
151
# FIELDMAP path
153
152
elif 'fieldmap' in fmaps or 'phasediff' in fmaps :
153
+ from .fmap import init_fmap2field_wf
154
154
from .unwarp import init_sdc_unwarp_wf
155
155
156
156
# SyN works without this metadata
@@ -161,39 +161,60 @@ def init_sdc_estimate_wf(fmaps, epi_meta, omp_nthreads=1, debug=False, ignore=No
161
161
162
162
if 'fieldmap' in fmaps :
163
163
from .fmap import init_fmap_wf
164
+ try :
165
+ fmap , = fmaps ['fieldmap' ]
166
+ except ValueError :
167
+ LOGGER .warning ('Several B0 fieldmaps found for the given target, using '
168
+ 'the first one.' )
169
+ fmap = fmaps ['fieldmap' ][0 ]
170
+
164
171
outputnode .inputs .method = 'FMB (fieldmap-based) - directly measured B0 map'
165
172
fmap_wf = init_fmap_wf (
166
173
omp_nthreads = omp_nthreads ,
167
174
fmap_bspline = False )
168
175
# set inputs
169
176
fmap_wf .inputs .inputnode .magnitude = [
170
- m for m , _ in fmaps [ 'fieldmap' ] ['magnitude' ]]
177
+ m for m , _ in fmap ['magnitude' ]]
171
178
fmap_wf .inputs .inputnode .fieldmap = [
172
- m for m , _ in fmaps [ 'fieldmap' ] ['fieldmap' ]]
179
+ m for m , _ in fmap ['fieldmap' ]]
173
180
elif 'phasediff' in fmaps :
174
181
from .phdiff import init_phdiff_wf
182
+ try :
183
+ fmap , = fmaps ['phasediff' ]
184
+ except ValueError :
185
+ LOGGER .warning ('Several phase-difference maps found for the given target, using '
186
+ 'the first one.' )
187
+ fmap = fmaps ['phasediff' ][0 ]
188
+
175
189
outputnode .inputs .method = 'FMB (fieldmap-based) - phase-difference map'
176
190
fmap_wf = init_phdiff_wf (omp_nthreads = omp_nthreads )
177
191
# set inputs
178
192
fmap_wf .inputs .inputnode .magnitude = [
179
- m for m , _ in fmaps ['phasediff' ]['magnitude' ]]
180
- fmap_wf .inputs .inputnode .phasediff = fmaps ['phasediff' ]['phases' ]
193
+ m for m , _ in fmap ['magnitude' ]]
194
+ fmap_wf .inputs .inputnode .phasediff = fmap ['phases' ]
195
+
196
+ fmap2field_wf = init_fmap2field_wf (omp_nthreads = omp_nthreads , debug = debug )
197
+ fmap2field_wf .inputs .inputnode .metadata = epi_meta
181
198
182
199
sdc_unwarp_wf = init_sdc_unwarp_wf (
183
200
omp_nthreads = omp_nthreads ,
184
201
debug = debug ,
185
202
name = 'sdc_unwarp_wf' )
186
- sdc_unwarp_wf .inputs .inputnode .metadata = epi_meta
187
203
188
204
workflow .connect ([
205
+ (inputnode , fmap2field_wf , [
206
+ ('epi_file' , 'inputnode.in_reference' ),
207
+ ('epi_brain' , 'inputnode.in_reference_brain' )]),
189
208
(inputnode , sdc_unwarp_wf , [
190
209
('epi_file' , 'inputnode.in_reference' ),
191
- ('epi_brain' , 'inputnode.in_reference_brain' ),
192
- ('epi_mask' , 'inputnode.in_mask' )]),
193
- (fmap_wf , sdc_unwarp_wf , [
210
+ ('epi_mask' , 'inputnode.in_reference_mask' )]),
211
+ (fmap_wf , fmap2field_wf , [
194
212
('outputnode.fmap' , 'inputnode.fmap' ),
195
213
('outputnode.fmap_ref' , 'inputnode.fmap_ref' ),
196
214
('outputnode.fmap_mask' , 'inputnode.fmap_mask' )]),
215
+ (fmap2field_wf , sdc_unwarp_wf , [
216
+ ('outputnode.out_warp' , 'inputnode.in_warp' )]),
217
+
197
218
])
198
219
elif not only_syn :
199
220
raise ValueError ('Fieldmaps of types %s are not supported' %
@@ -228,9 +249,44 @@ def init_sdc_estimate_wf(fmaps, epi_meta, omp_nthreads=1, debug=False, ignore=No
228
249
workflow .connect ([
229
250
(sdc_unwarp_wf , outputnode , [
230
251
('outputnode.out_warp' , 'out_warp' ),
231
- ('outputnode.out_reference' , 'epi_file ' ),
252
+ ('outputnode.out_reference' , 'epi_corrected ' ),
232
253
('outputnode.out_reference_brain' , 'epi_brain' ),
233
254
('outputnode.out_mask' , 'epi_mask' )]),
234
255
])
235
256
236
257
return workflow
258
+
259
+
260
+ def fieldmap_wrangler (layout , target_image , use_syn = False , force_syn = False ):
261
+ """Query the BIDSLayout for fieldmaps, and arrange them for the orchestration workflow."""
262
+ from collections import defaultdict
263
+ fmap_bids = layout .get_fieldmap (target_image , return_list = True )
264
+ fieldmaps = defaultdict (list )
265
+ for fmap in fmap_bids :
266
+ if fmap ['suffix' ] == 'epi' :
267
+ fieldmaps ['epi' ].append ((fmap ['epi' ], layout .get_metadata (fmap ['epi' ])))
268
+
269
+ if fmap ['suffix' ] == 'fieldmap' :
270
+ fieldmaps ['fieldmap' ].append ({
271
+ 'magnitude' : [(fmap ['magnitude' ], layout .get_metadata (fmap ['magnitude' ]))],
272
+ 'fieldmap' : [(fmap ['fieldmap' ], layout .get_metadata (fmap ['fieldmap' ]))],
273
+ })
274
+
275
+ if fmap ['suffix' ] == 'phasediff' :
276
+ fieldmaps ['phasediff' ].append ({
277
+ 'magnitude' : [(fmap [k ], layout .get_metadata (fmap [k ]))
278
+ for k in sorted (fmap .keys ()) if k .startswith ('magnitude' )],
279
+ 'phases' : [(fmap ['phasediff' ], layout .get_metadata (fmap ['phasediff' ]))],
280
+ })
281
+
282
+ if fmap ['suffix' ] == 'phase' :
283
+ fieldmaps ['phasediff' ].append ({
284
+ 'magnitude' : [(fmap [k ], layout .get_metadata (fmap [k ]))
285
+ for k in sorted (fmap .keys ()) if k .startswith ('magnitude' )],
286
+ 'phases' : [(fmap [k ], layout .get_metadata (fmap [k ]))
287
+ for k in sorted (fmap .keys ()) if k .startswith ('phase' )],
288
+ })
289
+
290
+ if force_syn is True or (not fieldmaps and use_syn is True ):
291
+ fieldmaps ['syn' ] = force_syn
292
+ return fieldmaps
0 commit comments