@@ -46,14 +46,14 @@ class FieldMapInputSpec(SPMCommandInputSpec):
46
46
desc = "one of: calculatevdm, applyvdm" ,
47
47
)
48
48
phase_file = File (
49
- mandatory = True ,
49
+ # mandatory=True,
50
50
exists = True ,
51
51
copyfile = False ,
52
52
field = "subj.data.presubphasemag.phase" ,
53
53
desc = "presubstracted phase file" ,
54
54
)
55
55
magnitude_file = File (
56
- mandatory = True ,
56
+ # mandatory=True,
57
57
exists = True ,
58
58
copyfile = False ,
59
59
field = "subj.data.presubphasemag.magnitude" ,
@@ -62,7 +62,7 @@ class FieldMapInputSpec(SPMCommandInputSpec):
62
62
echo_times = traits .Tuple (
63
63
traits .Float ,
64
64
traits .Float ,
65
- mandatory = True ,
65
+ # mandatory=True,
66
66
field = "subj.defaults.defaultsval.et" ,
67
67
desc = "short and long echo times" ,
68
68
)
@@ -169,7 +169,7 @@ class FieldMapInputSpec(SPMCommandInputSpec):
169
169
epi_file = File (
170
170
copyfile = False ,
171
171
exists = True ,
172
- mandatory = True ,
172
+ # mandatory=True,
173
173
field = "subj.session.epi" ,
174
174
desc = "EPI to unwarp" ,
175
175
)
@@ -195,10 +195,61 @@ class FieldMapInputSpec(SPMCommandInputSpec):
195
195
desc = "match anatomical image to EPI" ,
196
196
)
197
197
198
+ in_files = InputMultiObject (
199
+ traits .Either (ImageFileSPM (exists = True ),
200
+ traits .List (ImageFileSPM (exists = True ))),
201
+ field = 'data.scans' ,mandatory = True ,
202
+ copyfile = True ,
203
+ desc = 'list of filenames to apply the vdm to' )
204
+ vdmfile = File (
205
+ field = 'data.vdmfile' ,
206
+ desc = 'Voxel displacement map to use' ,mandatory = True ,
207
+ copyfile = True )
208
+ distortion_direction = traits .Int (
209
+ 2 , field = 'roptions.pedir' , desc = 'phase encode direction input data have been acquired with' ,
210
+ usedefault = True )
211
+ write_which = traits .ListInt (
212
+ [2 , 1 ],
213
+ field = 'roptions.which' ,
214
+ minlen = 2 ,
215
+ maxlen = 2 ,
216
+ usedefault = True ,
217
+ desc = 'determines which images to apply vdm to' )
218
+ interpolation = traits .Int (
219
+ 4 , field = 'roptions.rinterp' , desc = 'phase encode direction input data have been acquired with' ,
220
+ usedefault = True )
221
+ reslice_interp = traits .Range (
222
+ low = 0 ,
223
+ high = 7 ,
224
+ field = 'roptions.rinterp' ,
225
+ desc = 'degree of b-spline used for interpolation' )
226
+ write_wrap = traits .List (
227
+ traits .Int (),
228
+ minlen = 3 ,
229
+ maxlen = 3 ,
230
+ field = 'roptions.wrap' ,
231
+ desc = ('Check if interpolation should wrap in [x,y,z]' ))
232
+ write_mask = traits .Bool (
233
+ field = 'roptions.mask' , desc = 'True/False mask time series images' )
234
+ out_prefix = traits .String (
235
+ 'u' ,
236
+ field = 'roptions.prefix' ,
237
+ usedefault = True ,
238
+ desc = 'fieldmap corrected output prefix' )
239
+
198
240
199
241
class FieldMapOutputSpec (TraitedSpec ):
200
242
vdm = File (exists = True , desc = "voxel difference map" )
201
243
244
+ out_files = OutputMultiPath (
245
+ traits .Either (traits .List (File (exists = True )), File (exists = True )),
246
+ desc = ('If jobtype is applyvdm, '
247
+ 'these will be the fieldmap corrected files.'
248
+ ' Otherwise, they will be copies '
249
+ 'of in_files that have had their '
250
+ 'headers rewritten.' ))
251
+ mean_image = File (exists = True , desc = 'Mean image' )
252
+
202
253
203
254
class FieldMap (SPMCommand ):
204
255
"""Use the fieldmap toolbox from spm to calculate the voxel displacement map (VDM).
@@ -231,25 +282,76 @@ class FieldMap(SPMCommand):
231
282
232
283
def _format_arg (self , opt , spec , val ):
233
284
"""Convert input to appropriate format for spm"""
234
- if opt in ["phase_file" , "magnitude_file" , "anat_file" , "epi_file" ]:
285
+
286
+ if ((self .inputs .jobtype == "calculatevdm" ) and (opt in ['phase_file' , 'magnitude_file' , 'anat_file' , 'epi_file' ])):
235
287
return scans_for_fname (ensure_list (val ))
236
288
289
+ if ((self .inputs .jobtype == "applyvdm" ) and (opt == 'in_files' )):
290
+ return scans_for_fnames (ensure_list (val ))
291
+ if ((self .inputs .jobtype == "applyvdm" ) and (opt == 'vdmfile' )):
292
+ return scans_for_fname (ensure_list (val ))
237
293
return super (FieldMap , self )._format_arg (opt , spec , val )
238
294
295
+
239
296
def _parse_inputs (self ):
240
297
"""validate spm fieldmap options if set to None ignore"""
241
- einputs = super (FieldMap , self )._parse_inputs ()
242
- return [{self .inputs .jobtype : einputs [0 ]}]
298
+
299
+ if self .inputs .jobtype == "applyvdm" :
300
+ einputs = (super (FieldMap , self )
301
+ ._parse_inputs (skip = ('jobtype' ,'phase_file' , 'magnitude_file' ,
302
+ 'echo_times' , 'blip_direction' ,
303
+ 'total_readout_time' ,'maskbrain' ,
304
+ 'epifm' ,'jacobian_modulation' ,
305
+ 'method' ,'unwarp_fwhm' ,'pad' ,'ws' ,
306
+ 'template' ,'mask_fwhm' ,'nerode' ,'ndilate' ,
307
+ 'thresh' ,'reg' ,'epi_file' ,'matchvdm' ,
308
+ 'sessname' ,'writeunwarped' ,
309
+ 'anat_file' ,'matchanat' )))
310
+
311
+ else :
312
+ einputs = (super (FieldMap , self )
313
+ ._parse_inputs (skip = ('jobtype' ,'in_files' , 'vdmfile' )))
314
+ jobtype = self .inputs .jobtype
315
+
316
+ return [{'%s' % (jobtype ): einputs [0 ]}]
317
+
243
318
244
319
def _list_outputs (self ):
245
320
outputs = self ._outputs ().get ()
246
321
jobtype = self .inputs .jobtype
322
+ resliced_all = self .inputs .write_which [0 ] > 0
323
+ resliced_mean = self .inputs .write_which [1 ] > 0
247
324
if jobtype == "calculatevdm" :
248
- outputs ["vdm" ] = fname_presuffix (self .inputs .phase_file , prefix = "vdm5_sc" )
325
+ outputs ['vdm' ] = fname_presuffix (self .inputs .phase_file , prefix = 'vdm5_sc' )
326
+ elif jobtype == "applyvdm" :
327
+ if resliced_mean :
328
+ if isinstance (self .inputs .in_files [0 ], list ):
329
+ first_image = self .inputs .in_files [0 ][0 ]
330
+ else :
331
+ first_image = self .inputs .in_files [0 ]
332
+ outputs ['mean_image' ] = fname_presuffix (
333
+ first_image , prefix = 'meanu' )
334
+
335
+ if resliced_all :
336
+ outputs ['out_files' ] = []
337
+ for idx , imgf in enumerate (ensure_list (self .inputs .in_files )):
338
+ appliedvdm_run = []
339
+ if isinstance (imgf , list ):
340
+ for i , inner_imgf in enumerate (ensure_list (imgf )):
341
+ newfile = fname_presuffix (inner_imgf ,
342
+ prefix = self .inputs .out_prefix )
343
+ appliedvdm_run .append (newfile )
344
+ else :
345
+ appliedvdm_run = fname_presuffix (imgf ,
346
+ prefix = self .inputs .out_prefix )
347
+ outputs ['out_files' ].append (appliedvdm_run )
348
+ return outputs
349
+
249
350
250
351
return outputs
251
352
252
353
354
+
253
355
class SliceTimingInputSpec (SPMCommandInputSpec ):
254
356
in_files = InputMultiPath (
255
357
traits .Either (
0 commit comments