|
29 | 29 | import os
|
30 | 30 | import warnings
|
31 | 31 |
|
32 |
| -from ...utils.filemanip import fname_presuffix |
33 |
| -from ..base import (CommandLine, traits, CommandLineInputSpec, isdefined) |
| 32 | +from ...utils.filemanip import fname_presuffix, split_filename, copyfile |
| 33 | +from ..base import (traits, isdefined, |
| 34 | + CommandLine, CommandLineInputSpec, TraitedSpec, |
| 35 | + File, Directory, InputMultiPath, OutputMultiPath) |
34 | 36 |
|
35 | 37 | warn = warnings.warn
|
36 | 38 | warnings.filterwarnings('always', category=UserWarning)
|
@@ -243,6 +245,185 @@ def _overload_extension(self, value, name=None):
|
243 | 245 | return value + Info.output_type_to_ext(self.inputs.output_type)
|
244 | 246 |
|
245 | 247 |
|
| 248 | +class FSLXCommandInputSpec(FSLCommandInputSpec): |
| 249 | + out_dir = Directory('.', mandatory=True, desc='output directory', |
| 250 | + usedefault=True, position=1, argstr='%s') |
| 251 | + dwi = File(exists=True, argstr='--data=%s', mandatory=True, |
| 252 | + desc='diffusion weighted image data file') |
| 253 | + mask = File(exists=True, argstr='--mask=%s', mandatory=True, |
| 254 | + desc='brain binary mask file (i.e. from BET)') |
| 255 | + bvecs = File(exists=True, argstr='--bvecs=%s', mandatory=True, |
| 256 | + desc='b vectors file') |
| 257 | + bvals = File(exists=True, argstr='--bvals=%s', mandatory=True, |
| 258 | + desc='b values file') |
| 259 | + |
| 260 | + logdir = Directory('logdir', argstr='--logdir=%s', usedefault=True) |
| 261 | + n_fibres = traits.Range(low=1, argstr='--nfibres=%d', desc=('Maximum ' |
| 262 | + 'number of fibres to fit in each voxel')) |
| 263 | + model = traits.Enum(1, 2, argstr='--model=%d', |
| 264 | + desc=('use monoexponential (1, default, required for ' |
| 265 | + 'single-shell) or multiexponential (2, multi-' |
| 266 | + 'shell) model')) |
| 267 | + fudge = traits.Int(argstr='--fudge=%d', |
| 268 | + desc='ARD fudge factor') |
| 269 | + n_jumps = traits.Int(5000, argstr='--njumps=%d', |
| 270 | + desc='Num of jumps to be made by MCMC') |
| 271 | + burn_in = traits.Range(low=0, default=0, argstr='--burnin=%d', |
| 272 | + desc=('Total num of jumps at start of MCMC to be ' |
| 273 | + 'discarded')) |
| 274 | + burn_in_no_ard = traits.Range(low=0, default=0, argstr='--burninnoard=%d', |
| 275 | + desc=('num of burnin jumps before the ard is' |
| 276 | + ' imposed')) |
| 277 | + sample_every = traits.Range(low=0, default=1, argstr='--sampleevery=%d', |
| 278 | + desc='Num of jumps for each sample (MCMC)') |
| 279 | + update_proposal_every = traits.Range(low=1, default=40, |
| 280 | + argstr='--updateproposalevery=%d', |
| 281 | + desc=('Num of jumps for each update ' |
| 282 | + 'to the proposal density std ' |
| 283 | + '(MCMC)')) |
| 284 | + seed = traits.Int(argstr='--seed=%d', |
| 285 | + desc='seed for pseudo random number generator') |
| 286 | + |
| 287 | + _xor_inputs1 = ('no_ard', 'all_ard') |
| 288 | + no_ard = traits.Bool(argstr='--noard', xor=_xor_inputs1, |
| 289 | + desc='Turn ARD off on all fibres') |
| 290 | + all_ard = traits.Bool(argstr='--allard', xor=_xor_inputs1, |
| 291 | + desc='Turn ARD on on all fibres') |
| 292 | + |
| 293 | + _xor_inputs2 = ('no_spat', 'non_linear', 'cnlinear') |
| 294 | + no_spat = traits.Bool(argstr='--nospat', xor=_xor_inputs2, |
| 295 | + desc='Initialise with tensor, not spatially') |
| 296 | + non_linear = traits.Bool(argstr='--nonlinear', xor=_xor_inputs2, |
| 297 | + desc='Initialise with nonlinear fitting') |
| 298 | + cnlinear = traits.Bool(argstr='--cnonlinear', xor=_xor_inputs2, |
| 299 | + desc=('Initialise with constrained nonlinear ' |
| 300 | + 'fitting')) |
| 301 | + rician = traits.Bool(argstr='--rician', desc=('use Rician noise modeling')) |
| 302 | + |
| 303 | + _xor_inputs3 = ['f0_noard', 'f0_ard'] |
| 304 | + f0_noard = traits.Bool(argstr='--f0', xor=_xor_inputs3, |
| 305 | + desc=('Noise floor model: add to the model an ' |
| 306 | + 'unattenuated signal compartment f0')) |
| 307 | + f0_ard = traits.Bool(argstr='--f0 --ardf0', xor=_xor_inputs3 + ['all_ard'], |
| 308 | + desc=('Noise floor model: add to the model an ' |
| 309 | + 'unattenuated signal compartment f0')) |
| 310 | + force_dir = traits.Bool(False, argstr='--forcedir', usedefault=True, |
| 311 | + desc=('use the actual directory name given ' |
| 312 | + '(do not add + to make a new directory)')) |
| 313 | + |
| 314 | + |
| 315 | +class FSLXCommandOutputSpec(TraitedSpec): |
| 316 | + merged_thsamples = OutputMultiPath(File(exists=True), desc=('Samples from ' |
| 317 | + 'the distribution on theta')) |
| 318 | + merged_phsamples = OutputMultiPath(File(exists=True), desc=('Samples from ' |
| 319 | + 'the distribution on phi')) |
| 320 | + merged_fsamples = OutputMultiPath(File(exists=True), |
| 321 | + desc=('Samples from the distribution on ' |
| 322 | + 'anisotropic volume fraction.')) |
| 323 | + |
| 324 | + mean_thsamples = OutputMultiPath(File(exists=True), desc=('Mean of ' |
| 325 | + 'distribution on theta')) |
| 326 | + mean_phsamples = OutputMultiPath(File(exists=True), desc=('Mean of ' |
| 327 | + 'distribution on phi')) |
| 328 | + mean_fsamples = OutputMultiPath(File(exists=True), desc=('Mean of ' |
| 329 | + 'distribution on f anisotropy')) |
| 330 | + |
| 331 | + mean_dsamples = File(exists=True, desc='Mean of distribution on ' |
| 332 | + 'diffusivity d') |
| 333 | + mean_S0samples = File(exists=True, desc='Mean of distribution on T2w' |
| 334 | + 'baseline signal intensity S0') |
| 335 | + mean_tausamples = File(exists=True, desc='Mean of distribution on ' |
| 336 | + 'tau samples (only with rician noise)') |
| 337 | + |
| 338 | + dyads = OutputMultiPath(File(exists=True), desc=('Mean of PDD distribution' |
| 339 | + ' in vector form.')) |
| 340 | + dyads_disp = OutputMultiPath(File(exists=True), desc=('Uncertainty on the ' |
| 341 | + ' estimated fiber orientation')) |
| 342 | + fsamples = OutputMultiPath(File(exists=True), desc=('Samples from the ' |
| 343 | + 'distribution on anisotropic volume fraction')) |
| 344 | + |
| 345 | + |
| 346 | +class FSLXCommand(FSLCommand): |
| 347 | + """ |
| 348 | + Base support for ``xfibres`` and ``bedpostx`` |
| 349 | + """ |
| 350 | + input_spec = FSLXCommandInputSpec |
| 351 | + output_spec = FSLXCommandOutputSpec |
| 352 | + |
| 353 | + def _run_interface(self, runtime): |
| 354 | + subjectdir = os.path.abspath(self.inputs.out_dir) |
| 355 | + out_dir = subjectdir + '.bedpostX' |
| 356 | + |
| 357 | + if isdefined(self.inputs.force_dir) and self.inputs.force_dir: |
| 358 | + out_dir = os.path.abspath(self.inputs.out_dir) |
| 359 | + self._out_dir = out_dir |
| 360 | + |
| 361 | + if not os.path.exists(out_dir): |
| 362 | + os.makedirs(out_dir) |
| 363 | + |
| 364 | + _, _, ext = split_filename(self.inputs.mask) |
| 365 | + copyfile(self.inputs.mask, |
| 366 | + os.path.join(subjectdir, |
| 367 | + 'nodif_brain_mask' + ext)) |
| 368 | + _, _, ext = split_filename(self.inputs.dwi) |
| 369 | + copyfile(self.inputs.dwi, |
| 370 | + os.path.join(subjectdir, 'data' + ext)) |
| 371 | + copyfile(self.inputs.bvals, |
| 372 | + os.path.join(subjectdir, 'bvals')) |
| 373 | + copyfile(self.inputs.bvecs, |
| 374 | + os.path.join(subjectdir, 'bvecs')) |
| 375 | + |
| 376 | + runtime = super(FSLXCommand, self)._run_interface(runtime) |
| 377 | + if runtime.stderr: |
| 378 | + self.raise_exception(runtime) |
| 379 | + return runtime |
| 380 | + |
| 381 | + def _list_outputs(self): |
| 382 | + outputs = self.output_spec().get() |
| 383 | + out_dir = self._out_dir |
| 384 | + |
| 385 | + for k in outputs.keys(): |
| 386 | + if k not in ('outputtype', 'environ', 'args', 'bpx_out_directory', |
| 387 | + 'xfms_directory', 'mean_dsamples', 'mean_S0samples', |
| 388 | + 'mean_tausamples'): |
| 389 | + outputs[k] = [] |
| 390 | + |
| 391 | + outputs['mean_dsamples'] = self._gen_fname('mean_dsamples', |
| 392 | + cwd=out_dir) |
| 393 | + outputs['mean_S0samples'] = self._gen_fname('mean_S0samples', |
| 394 | + cwd=out_dir) |
| 395 | + |
| 396 | + if isdefined(self.inputs.rician) and self.inputs.rician: |
| 397 | + outputs['mean_tausamples'] = self._gen_fname('mean_tausamples', |
| 398 | + cwd=out_dir) |
| 399 | + |
| 400 | + for i in xrange(1, self.inputs.fibres + 1): |
| 401 | + outputs['merged_thsamples'].append(self._gen_fname(('merged_th%d' |
| 402 | + 'samples') % i), |
| 403 | + cwd=out_dir) |
| 404 | + outputs['merged_phsamples'].append(self._gen_fname(('merged_ph%d' |
| 405 | + 'samples') % i), |
| 406 | + cwd=out_dir) |
| 407 | + outputs['merged_fsamples'].append(self._gen_fname(('merged_f%d' |
| 408 | + 'samples') % i), |
| 409 | + cwd=out_dir) |
| 410 | + |
| 411 | + outputs['mean_thsamples'].append(self._gen_fname(('mean_th%d' |
| 412 | + 'samples') % i), |
| 413 | + cwd=out_dir) |
| 414 | + outputs['mean_phsamples'].append(self._gen_fname(('mean_ph%d' |
| 415 | + 'samples') % i), |
| 416 | + cwd=out_dir) |
| 417 | + outputs['mean_fsamples'].append(self._gen_fname(('mean_f%d' |
| 418 | + 'samples') % i), |
| 419 | + cwd=out_dir) |
| 420 | + outputs['dyads'].append(self._gen_fname('dyads%d' % i), |
| 421 | + cwd=out_dir) |
| 422 | + outputs['dyads_dispersion'].append(self._gen_fname(('dyads%d' |
| 423 | + '_dispersion') % i), |
| 424 | + cwd=out_dir) |
| 425 | + return outputs |
| 426 | + |
246 | 427 |
|
247 | 428 | def check_fsl():
|
248 | 429 | ver = Info.version()
|
|
0 commit comments