@@ -103,45 +103,89 @@ def _run_interface( self, runtime ):
103
103
return runtime
104
104
105
105
106
-
107
- class TOPUPInputSpec ( FSLCommandInputSpec ):
108
- in_file = File ( exists = True , mandatory = True , desc = 'name of 4D file with images' , argstr = '--imain=%s' )
109
- encoding_file = File ( exists = True , desc = 'name of text file with PE directions/times' , argstr = '--datain=%s' )
110
- encoding_direction = traits .Enum ( 'y' ,'x' ,'z' ,'x-' ,'y-' ,'z-' , desc = 'encoding direction for automatic generation of encoding_file' )
111
- readout_times = traits .List (traits .Float , desc = 'readout times (dwell times by # phase-encode steps minus 1)' )
112
- out_base = File ( desc = 'base-name of output files (spline coefficients (Hz) and movement parameters)' , argstr = '--out=%s' )
113
- out_field = File ( argstr = '--fout=%s' , desc = 'name of image file with field (Hz)' )
114
- out_corrected = File ( argstr = '--iout=%s' , desc = 'name of 4D image file with unwarped images' )
115
- out_logfile = File ( argstr = '--logout=%s' , desc = 'name of log-file' )
116
- warp_res = traits .Float ( 10.0 , argstr = '--warpres=%f' , desc = '(approximate) resolution (in mm) of warp basis for the different sub-sampling levels' )
117
- subsamp = traits .Int ( 1 , argstr = '--subsamp=%d' , desc = 'sub-sampling scheme, default 1' )
118
- fwhm = traits .Float ( 8.0 , argstr = '--fwhm=%f' , desc = 'FWHM (in mm) of gaussian smoothing kernel' )
119
- config = traits .String ('b02b0.cnf' , desc = 'Name of config file specifying command line arguments' , argstr = '--config=%s' , usedefault = True )
120
- max_iter = traits .Int ( 5 , argstr = '--miter=%d' , desc = 'max # of non-linear iterations' )
121
- # @oesteban: I don't know how to implement these 3 parameters, AFAIK there's no documentation.
106
+ class TOPUPInputSpec (FSLCommandInputSpec ):
107
+ in_file = File (exists = True , mandatory = True ,
108
+ desc = 'name of 4D file with images' , argstr = '--imain=%s' )
109
+ encoding_file = File (exists = True , mandatory = True ,
110
+ xor = ['encoding_direction' ],
111
+ desc = 'name of text file with PE directions/times' ,
112
+ argstr = '--datain=%s' )
113
+ encoding_direction = traits .List (traits .Enum ('y' ,'x' ,'z' ,'x-' ,'y-' ,'z-' ),
114
+ mandatory = True , xor = ['encoding_file' ],
115
+ requires = ['readout_times' ],
116
+ argstr = '--datain=%s' ,
117
+ desc = ('encoding direction for automatic '
118
+ 'generation of encoding_file' ))
119
+ readout_times = InputMultiPath (traits .Float ,
120
+ requires = ['encoding_direction' ],
121
+ xor = ['encoding_file' ], mandatory = True ,
122
+ desc = ('readout times (dwell times by # '
123
+ 'phase-encode steps minus 1)' ))
124
+ out_base = File (desc = ('base-name of output files (spline '
125
+ 'coefficients (Hz) and movement parameters)' ),
126
+ name_source = ['in_file' ], name_template = '%s_base' ,
127
+ keep_extension = True ,
128
+ argstr = '--out=%s' , hash_files = False )
129
+ out_field = File (argstr = '--fout=%s' , hash_files = False ,
130
+ name_source = ['in_file' ], name_template = '%s_field' ,
131
+ desc = 'name of image file with field (Hz)' )
132
+ out_corrected = File (argstr = '--iout=%s' , hash_files = False ,
133
+ name_source = ['in_file' ], name_template = '%s_corrected' ,
134
+ desc = 'name of 4D image file with unwarped images' )
135
+ out_logfile = File (argstr = '--logout=%s' , desc = 'name of log-file' ,
136
+ name_source = ['in_file' ], name_template = '%s_topup.log' ,
137
+ keep_extension = True , hash_files = False )
138
+ warp_res = traits .Float (10.0 , argstr = '--warpres=%f' ,
139
+ desc = ('(approximate) resolution (in mm) of warp '
140
+ 'basis for the different sub-sampling levels' ))
141
+ subsamp = traits .Int (1 , argstr = '--subsamp=%d' ,
142
+ desc = 'sub-sampling scheme' )
143
+ fwhm = traits .Float (8.0 , argstr = '--fwhm=%f' ,
144
+ desc = 'FWHM (in mm) of gaussian smoothing kernel' )
145
+ config = traits .String ('b02b0.cnf' , argstr = '--config=%s' , usedefault = True ,
146
+ desc = ('Name of config file specifying command line '
147
+ 'arguments' ))
148
+ max_iter = traits .Int (5 , argstr = '--miter=%d' ,
149
+ desc = 'max # of non-linear iterations' )
150
+ # @oesteban: I don't know how to implement these 3 parameters, AFAIK there's
151
+ # no documentation.
122
152
#lambda Weight of regularisation, default depending on --ssqlambda and --regmod switches. See user documetation.
123
153
#ssqlambda If set (=1), lambda is weighted by current ssq, default 1
124
154
#regmod Model for regularisation of warp-field [membrane_energy bending_energy], default bending_energy
125
- estmov = traits .Enum ( 1 , 0 , desc = 'estimate movements if set' , argstr = '--estmov=%d' )
126
- minmet = traits .Enum ( 0 , 1 , desc = 'Minimisation method 0=Levenberg-Marquardt, 1=Scaled Conjugate Gradient' , argstr = '--minmet=%d' )
127
- splineorder = traits .Int ( 3 , argstr = '--splineorder=%d' , desc = 'order of spline, 2->Qadratic spline, 3->Cubic spline' )
128
- numprec = traits .Enum ( 'double' , 'float' , argstr = '--numprec=%s' , desc = 'Precision for representing Hessian, double or float.' )
129
- interp = traits .Enum ( 'spline' , 'linear' , argstr = '--interp=%s' , desc = 'Image interpolation model, linear or spline.' )
130
- scale = traits .Enum ( 0 , 1 , argstr = '--scale=%d' , desc = 'If set (=1), the images are individually scaled to a common mean' )
131
- regrid = traits .Enum ( 1 , 0 , argstr = '--regrid=%d' , desc = 'If set (=1), the calculations are done in a different grid' )
132
-
133
- class TOPUPOutputSpec ( TraitedSpec ):
134
- out_fieldcoef = File ( exists = True , desc = 'file containing the field coefficients' )
135
- out_movpar = File ( exists = True , desc = 'movpar.txt output file' )
136
-
137
- out_enc_file = File ( desc = 'encoding directions file output for applytopup' )
138
- out_topup = File ( desc = 'basename for the <out_base>_fieldcoef.nii.gz and <out_base>_movpar.txt files' )
139
- out_field = File ( desc = 'name of image file with field (Hz)' )
140
- out_corrected = File ( desc = 'name of 4D image file with unwarped images' )
141
- out_logfile = File ( desc = 'name of log-file' )
142
-
143
- class TOPUP ( FSLCommand ):
144
- """ Interface for FSL topup, a tool for estimating and correcting susceptibility induced distortions
155
+ estmov = traits .Enum (1 , 0 ,
156
+ desc = 'estimate movements if set' , argstr = '--estmov=%d' )
157
+ minmet = traits .Enum (0 , 1 , argstr = '--minmet=%d' ,
158
+ desc = ('Minimisation method 0=Levenberg-Marquardt, '
159
+ '1=Scaled Conjugate Gradient' ))
160
+ splineorder = traits .Int (3 , argstr = '--splineorder=%d' ,
161
+ desc = ('order of spline, 2->Qadratic spline, '
162
+ '3->Cubic spline' ))
163
+ numprec = traits .Enum ('double' , 'float' , argstr = '--numprec=%s' ,
164
+ desc = ('Precision for representing Hessian, double '
165
+ 'or float.' ))
166
+ interp = traits .Enum ('spline' , 'linear' , argstr = '--interp=%s' ,
167
+ desc = 'Image interpolation model, linear or spline.' )
168
+ scale = traits .Enum (0 , 1 , argstr = '--scale=%d' ,
169
+ desc = ('If set (=1), the images are individually scaled '
170
+ 'to a common mean' ))
171
+ regrid = traits .Enum (1 , 0 , argstr = '--regrid=%d' ,
172
+ desc = ('If set (=1), the calculations are done in a '
173
+ 'different grid' ))
174
+
175
+
176
+ class TOPUPOutputSpec (TraitedSpec ):
177
+ out_fieldcoef = File (exists = True ,
178
+ desc = 'file containing the field coefficients' )
179
+ out_movpar = File (exists = True , desc = 'movpar.txt output file' )
180
+ out_enc_file = File (desc = 'encoding directions file output for applytopup' )
181
+ out_field = File (desc = 'name of image file with field (Hz)' )
182
+ out_corrected = File (desc = 'name of 4D image file with unwarped images' )
183
+ out_logfile = File (desc = 'name of log-file' )
184
+
185
+
186
+ class TOPUP (FSLCommand ):
187
+ """ Interface for FSL topup, a tool for estimating and correcting
188
+ susceptibility induced distortions
145
189
Reference: http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/TOPUP
146
190
Example: http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/topup/ExampleTopupFollowedByApplytopup
147
191
@@ -164,73 +208,50 @@ class TOPUP( FSLCommand ):
164
208
input_spec = TOPUPInputSpec
165
209
output_spec = TOPUPOutputSpec
166
210
167
- def _parse_inputs ( self , skip = None ):
168
- if skip is None :
169
- skip = []
170
-
171
- if not isdefined (self .inputs .out_base ):
172
- self .inputs .out_base = './nipypetu'
173
-
174
- self .inputs .out_base = os .path .abspath (self .inputs .out_base )
175
-
176
- if isdefined ( self .inputs .encoding_file ):
177
- skip .append ( 'encoding_direction' )
178
- skip .append ( 'readout_times' )
179
- else :
180
- encdir = 'y'
181
- enctimes = None
182
-
183
- if isdefined ( self .inputs .encoding_direction ):
184
- encdir = self .inputs .encoding_direction
185
-
186
- if isdefined ( self .inputs .readout_times ):
187
- enctimes = self .inputs .readout_times
188
-
189
- self .inputs .encoding_file = self ._generate_encfile ( encdir , enctimes )
190
-
191
- return super (TOPUP , self )._parse_inputs (skip = skip )
211
+ def _format_arg (self , name , trait_spec , value ):
212
+ if name == 'encoding_direction' :
213
+ return trait_spec .argstr % self ._generate_encfile ()
214
+ return super (TOPUP , self )._format_arg (name , trait_spec , value )
192
215
193
216
def _list_outputs (self ):
194
- outputs = self .output_spec ().get ()
195
- outputs ['out_topup' ] = self .inputs .out_base
196
- outputs ['out_fieldcoef' ] = '%s_%s.nii.gz' % (self .inputs .out_base , 'fieldcoef' )
197
- outputs ['out_movpar' ] = '%s_%s.txt' % (self .inputs .out_base , 'movpar' )
198
- outputs ['out_enc_file' ] = self .inputs .encoding_file
199
-
200
- if isdefined ( self .inputs .out_field ):
201
- outputs ['out_field' ] = self .inputs .out_field
217
+ outputs = super (TOPUP , self )._list_outputs ()
218
+ if isdefined (self .inputs .out_base ):
219
+ base = self .inputs .out_base
202
220
else :
203
- outputs ['out_field' ] = Undefined
221
+ base = split_filename (self .inputs .in_file )[1 ] + '_base'
222
+ outputs ['out_fieldcoef' ] = self ._gen_fname (base , suffix = '_fieldcoeff' )
223
+ outputs ['out_movpar' ] = self ._gen_fname (base , suffix = '_movpar' )
204
224
205
- if isdefined ( self .inputs .out_corrected ):
206
- outputs ['out_corrected' ] = self .inputs .out_corrected
207
- else :
208
- outputs ['out_corrected' ] = Undefined
209
-
210
- if isdefined ( self .inputs .out_logfile ):
211
- outputs ['out_logfile' ] = self .inputs .out_logfile
212
- else :
213
- outputs ['out_logfile' ] = Undefined
225
+ if isdefined (self .inputs .encoding_direction ):
226
+ outputs ['out_enc_file' ] = self ._get_encfilename ()
214
227
return outputs
215
228
216
- def _generate_encfile ( self , encdir , enctime = None ):
217
- out_file = '%s_encfile.txt' % self .inputs .out_base
218
- direction = 1.0
219
- if len (encdir )== 2 and encdir [1 ]== '-' :
220
- direction = - 1.0
221
-
222
- if enctime is None :
223
- enctime = [ 1.0 , 1.0 ]
224
-
225
- file1 = [ float (val [0 ]== encdir [0 ]) * direction for val in [ 'x' , 'y' , 'z' ] ]
226
- file2 = [ float (val [0 ]== encdir [0 ]) * direction * - 1.0 for val in [ 'x' , 'y' , 'z' ] ]
227
-
228
- file1 .append ( enctime [0 ] )
229
- file2 .append ( enctime [1 ] )
230
-
231
-
232
- np .savetxt ( out_file , np .array ( [ file1 , file2 ] ), fmt = '%.2f' )
229
+ def _get_encfilename (self ):
230
+ out_file = os .path .join (os .getcwd (),
231
+ ('%s_encfile.txt' %
232
+ split_filename (self .inputs .in_file )[1 ]))
233
+ return out_file
233
234
235
+ def _generate_encfile (self ):
236
+ """Generate a topup compatible encoding file based on given directions
237
+ """
238
+ out_file = self ._get_encfilename ()
239
+ durations = self .inputs .readout_times
240
+ if len (self .inputs .encoding_direction ) != len (durations ):
241
+ if len (self .inputs .readout_times ) != 1 :
242
+ raise ValueError (('Readout time must be a float or match length'
243
+ ' of encoding directions' ))
244
+ durations = durations * len (self .inputs .encoding_direction )
245
+
246
+ lines = []
247
+ for idx , encdir in enumerate (self .inputs .encoding_direction ):
248
+ direction = 1.0
249
+ if encdir .endswith ('-' ):
250
+ direction = - 1.0
251
+ line = [float (val [0 ] == encdir [0 ]) * direction
252
+ for val in ['x' , 'y' , 'z' ]] + [durations [idx ]]
253
+ lines .append (line )
254
+ np .savetxt (out_file , np .array (lines ), fmt = '%d %d %d %.3f' )
234
255
return out_file
235
256
236
257
class ApplyTOPUPInputSpec ( FSLCommandInputSpec ):
0 commit comments