<commit_before>"""The fsl module provides classes for interfacing with the `FSL
<http://www.fmrib.ox.ac.uk/fsl/index.html>`_ command line tools.  This
was written to work with FSL version 4.1.4.

Examples
--------
See the docstrings of the individual classes for examples.

"""

import os
from glob import glob
import warnings

from nipype.interfaces.fsl.base import FSLCommand, FSLInfo
from nipype.interfaces.fsl.base import NEW_FSLCommand, FSLTraitedSpec
from nipype.interfaces.base import Bunch, TraitedSpec, isdefined, File
from nipype.utils.filemanip import fname_presuffix, list_to_filename
from nipype.utils.docparse import get_doc
from nipype.utils.misc import container_to_string, is_container

import enthought.traits.api as traits

warn = warnings.warn
warnings.filterwarnings('always', category=UserWarning)

class BetInputSpec(FSLTraitedSpec):
    '''Note: Currently we don't support -R, -S, -Z,-A or -A2'''
    # We use position args here as list indices - so a negative number
    # will put something on the end
    infile = File(exists=True,
                  desc = 'input file to skull strip',
                  argstr='%s', position=0, mandatory=True)
    outfile = File(desc = 'name of output skull stripped image',
                   argstr='%s', position=1, genfile=True)
    outline = traits.Bool(desc = 'create surface outline image',
                          argstr='-o')
    mask = traits.Bool(desc = 'create binary mask image',
                       argstr='-m')
    skull = traits.Bool(desc = 'create skull image',
                        argstr='-s')
    nooutput = traits.Bool(argstr='-n',
                           desc="Don't generate segmented output")
    frac = traits.Float(desc = 'fractional intensity threshold',
                        argstr='-f %.2f')
    vertical_gradient = traits.Float(argstr='-g %.2f',
             desc='vertical gradient in fractional intensity ' \
                                         'threshold (-1, 1)')
    radius = traits.Int(argstr='-r %d', units='mm',
                        desc="head radius")
    center = traits.List(traits.Int, desc = 'center of gravity in voxels',
                         argstr='-c %s', minlen=0, maxlen=3,
                         units='voxels')
    threshold = traits.Bool(argstr='-t',
                   desc="apply thresholding to segmented brain image and mask")
    mesh = traits.Bool(argstr='-e',
                       desc="generate a vtk mesh brain surface")
    # XXX how do we know these two are mutually exclusive?
    _xor_inputs = ('functional', 'reduce_bias')
    functional = traits.Bool(argstr='-F', xor=_xor_inputs,
                             desc="apply to 4D fMRI data")
    reduce_bias = traits.Bool(argstr='-B', xor=_xor_inputs,
                              desc="bias field and neck cleanup")

class BetOutputSpec(TraitedSpec):
    outfile = File(exists=True,
                   desc="path/name of skullstripped file")
    maskfile = File(
        desc="path/name of binary brain mask (if generated)")
    outlinefile = File(
        desc="path/name of outline file (if generated)")
    meshfile = File(
        desc="path/name of vtk mesh file (if generated)")

class Bet(NEW_FSLCommand):
    """Use FSL BET command for skull stripping.

    For complete details, see the `BET Documentation.
    <http://www.fmrib.ox.ac.uk/fsl/bet2/index.html>`_

    To print out the command line help, use:
        fsl.Bet().inputs_help()

    Examples
    --------
    Initialize Bet with no options, assigning them when calling run:

    >>> from nipype.interfaces import fsl
    >>> btr = fsl.Bet()
    >>> res = btr.run('infile', 'outfile', frac=0.5) # doctest: +SKIP

    Assign options through the ``inputs`` attribute:

    >>> btr = fsl.Bet()
    >>> btr.inputs.infile = 'foo.nii'
    >>> btr.inputs.outfile = 'bar.nii'
    >>> btr.inputs.frac = 0.7
    >>> res = btr.run() # doctest: +SKIP

    Specify options when creating a Bet instance:

    >>> btr = fsl.Bet(infile='infile', outfile='outfile', frac=0.5)
    >>> res = btr.run() # doctest: +SKIP

    Loop over many inputs (Note: the snippet below would overwrite the
    outfile each time):

    >>> btr = fsl.Bet(infile='infile', outfile='outfile')
    >>> fracvals = [0.3, 0.4, 0.5]
    >>> for val in fracvals:
    ...     res = btr.run(frac=val) # doctest: +SKIP

    """

    _cmd = 'bet'
    input_spec = BetInputSpec
    output_spec = BetOutputSpec

    def _run_interface(self, runtime):
        # The returncode is meaningless in Bet.  So check the output
        # in stderr and if it's set, then update the returncode
        # accordingly.
        runtime = super(Bet, self)._run_interface(runtime)
        if runtime.stderr:
            runtime.returncode = 1
        return runtime

    def _list_outputs(self):
        outputs = self.output_spec().get()
        outputs['outfile'] = self.inputs.outfile
        if not isdefined(outputs['outfile']) and isdefined(self.inputs.infile):
            outputs['outfile'] = self._gen_fname(self.inputs.infile,
                                              suffix = '_brain')
        if isdefined(self.inputs.mesh) and self.inputs.mesh:
            outputs['meshfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mesh.vtk',
                                               change_ext = False)
        if (isdefined(self.inputs.mask) and self.inputs.mask) or \
                (isdefined(self.inputs.reduce_bias) and \
                     self.inputs.reduce_bias):
            outputs['maskfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mask')
        return outputs

    def _gen_filename(self, name):
        if name == 'outfile':
            return self._list_outputs()[name]
        return None


class FastInputSpec(FSLTraitedSpec):
    """ Defines inputs (trait classes) for Fast """
    infiles = traits.List(File(exists=True),
                          desc = 'image, or multi-channel set of images, ' \
                              'to be segmented',
                          argstr='%s', position=-1, mandatory=True)
    out_basename = File(desc = 'base name of output files',
                        argstr='-o %s', genfile=True) # maybe not genfile
    number_classes = traits.Range(low=1, high=10, argstr = '-n %d',
                                  desc = 'number of tissue-type classes')
    output_biasfield = traits.Bool(desc = 'output estimated bias field',
                                   argstr = '-b', genfile=True)
    output_biascorrected = traits.Bool(desc = 'output restored image ' \
                                           '(bias-corrected image)',
                                       argstr = '-B', genfile = True)
    img_type = traits.Enum((1,2,3), desc = 'int specifying type of image: ' \
                               '(1 = T1, 2 = T2, 3 = PD)',
                           argstr = '-t %d')
    bias_iters = traits.Range(low = 1, high = 10, argstr = '-I %d',
                              desc = 'number of main-loop iterations during ' \
                                  'bias-field removal')
    bias_lowpass = traits.Range(low = 4, high = 40, 
                                desc = 'bias field smoothing extent (FWHM) ' \
                                    'in mm',
                                argstr = '-l %d', units = 'mm')
    init_seg_smooth = traits.Range(low=0.0001, high = 0.1, 
                                   desc = 'initial segmentation spatial ' \
                                       'smoothness (during bias field ' \
                                       'estimation)',
                                   argstr = '-f %.3f')
    segments = traits.Bool(desc = 'outputs a separate binary image for each ' \
                               'tissue type',
                           argstr = '-g', genfile=True)
    init_transform = File(exists=True, desc = '<standard2input.mat> initialise'\
                              ' using priors',
                          argstr = '-a %s')
    other_priors = traits.List(File, desc = 'alternative prior images',
                               argstr = '-A %s', minlen=3, maxlen=3)
    nopve = traits.Bool(desc = 'turn off PVE (partial volume estimation)',
                        argstr = '--nopve')
    nobias = traits.Bool(desc = 'do not remove bias field',
                         argstr = '-N')
    use_priors = traits.Bool(desc = 'use priors throughout',
                             argstr = '-P')   # must also set -a!,
                                              # mutually inclusive??
                                              # No, conditional
                                              # mandatory... need to
                                              # figure out how to
                                              # handle with traits.
    segment_iters = traits.Range(low=1, high=50, 
                                 desc = 'number of segmentation-initialisation'\
                                     ' iterations',
                                 argstr = '-W %d')
    mixel_smooth = traits.Range(low = 0.0, high=1.0, 
                                desc = 'spatial smoothness for mixeltype',
                                argstr = '-R %.2f')
    iters_afterbias = traits.Range(low = 1, hight = 20,
                                   desc = 'number of main-loop iterations ' \
                                       'after bias-field removal',
                                   argstr = '-O %d')
    hyper = traits.Range(low = 0.0, high = 1.0, 
                         desc = 'segmentation spatial smoothness',
                         argstr = '-H %.2f')
    verbose = traits.Bool(desc = 'switch on diagnostic messages',
                          argstr = '-v')
    manualseg = File(exists=True, desc = 'Filename containing intensities',
                     argstr = '-s %s')
    probability_maps = traits.Bool(desc = 'outputs individual probability maps',
                                   argstr = '-p', genfile = True)
    

class FastOutputSpec(TraitedSpec):
    """Specify possible outputs from Fast"""
    tissue_class_map = File(exists=True,
                            desc = 'path/name of binary segmented volume file' \
                                ' one val for each class  _seg')
    tissue_class_files = File(desc = 'path/name of binary segmented volumes ' \
                                  'one file for each class  _seg_x')
    restored_image = File(desc = 'restored images (one for each input image) ' \
                              'named according to the input images _restore')

    mixeltype  = File(desc = "path/name of mixeltype volume file _mixeltype")

    partial_volume_map = File(desc = "path/name of partial volume file _pveseg")
    partial_volume_files  = File(desc = 'path/name of partial volumes files ' \
                                     'one for each class, _pve_x')
    
    bias_field = File(desc = 'Estimated bias field _bias')
    probability_maps = File(desc= 'filenames, one for each class, for each ' \
                                'input, prob_x')


class NEW_Fast(NEW_FSLCommand):
    """ Use FSL FAST for segmenting and bias correction.

    For complete details, see the `FAST Documentation.
    <http://www.fmrib.ox.ac.uk/fsl/fast4/index.html>`_
    """
    _cmd = 'fast'
    input_spec = FastInputSpec
    output_spec = FastOutputSpec

    def _list_outputs(self):
        outputs = self.output_spec().get()
        orignames = self.inputs.infiles
        if isdefined(self.inputs.out_basename):
            basepth, basename = os.path.split(self.inputs.out_basename)
        
        for item in self.inputs.infiles:
            print item
        outputs['tissue_class_map'] = 'FIX'
        if not isdefined(outputs['outfile']) and isdefined(self.inputs.infile):
            outputs['outfile'] = self._gen_fname(self.inputs.infile,
                                              suffix = '_brain')
        if isdefined(self.inputs.mesh) and self.inputs.mesh:
            outputs['meshfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mesh.vtk',
                                               change_ext = False)
        if (isdefined(self.inputs.mask) and self.inputs.mask) or \
                (isdefined(self.inputs.reduce_bias) and self.inputs.reduce_bias):
            outputs['maskfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mask')
        return outputs 


   

class Fast(FSLCommand):
    """Use FSL FAST for segmenting and bias correction.

    For complete details, see the `FAST Documentation.
    <http://www.fmrib.ox.ac.uk/fsl/fast4/index.html>`_

    To print out the command line help, use:
        fsl.Fast().inputs_help()

    Examples
    --------
    >>> from nipype.interfaces import fsl
    >>> faster = fsl.Fast(out_basename = 'myfasted')
    >>> fasted = faster.run(['file1', 'file2'])

    >>> faster = fsl.Fast(infiles=['filea', 'fileb'], out_basename='myfasted')
    >>> fasted = faster.run()

    """

    @property
    def cmd(self):
        """sets base command, not editable"""
        return 'fast'

    opt_map = {'number_classes':       '-n %d',
            'bias_iters':           '-I %d',
            'bias_lowpass':         '-l %d',  # in mm
            'img_type':             '-t %d',
            'init_seg_smooth':      '-f %.3f',
            'segments':             '-g',
            'init_transform':       '-a %s',
            # This option is not really documented on the Fast web page:
            # http://www.fmrib.ox.ac.uk/fsl/fast4/index.html#fastcomm
            # I'm not sure if there are supposed to be exactly 3 args or what
            'other_priors':         '-A %s %s %s',
            'nopve':                '--nopve',
            'output_biasfield':     '-b',
            'output_biascorrected': '-B',
            'nobias':               '-N',
            'n_inputimages':        '-S %d',
            'out_basename':         '-o %s',
            'use_priors':           '-P',  # must also set -a!
            'segment_iters':        '-W %d',
            'mixel_smooth':         '-R %.2f',
            'iters_afterbias':      '-O %d',
            'hyper':                '-H %.2f',
            'verbose':              '-v',
            'manualseg':            '-s %s',
            'probability_maps':     '-p',
            'infiles':               None,
            }

    def inputs_help(self):
        """Print command line documentation for FAST."""
        print get_doc(self.cmd, self.opt_map, trap_error=False)

    def run(self, infiles=None, **inputs):
        """Execute the FSL fast command.

        Parameters
        ----------
        infiles : string or list of strings
            File(s) to be segmented or bias corrected
        inputs : dict, optional
            Additional ``inputs`` assignments can be passed in.

        Returns
        -------
        results : InterfaceResult
            An :class:`nipype.interfaces.base.InterfaceResult` object
            with a copy of self in `interface`

        """

        if infiles:
            self.inputs.infiles = infiles
        if not self.inputs.infiles:
            raise AttributeError('Fast requires input file(s)')
        self.inputs.update(**inputs)
        return super(Fast, self).run()

    def _parse_inputs(self):
        '''Call our super-method, then add our input files'''
        # Could do other checking above and beyond regular _parse_inputs here
        allargs = super(Fast, self)._parse_inputs(skip=('infiles'))
        if self.inputs.infiles:
            allargs.append(container_to_string(self.inputs.infiles))
        return allargs

    def outputs(self):
        """Returns a :class:`nipype.interfaces.base.Bunch` with outputs

        Parameters
        ----------
        Each attribute in ``outputs`` is a list.  There will be
        one set of ``outputs`` for each file specified in
        ``infiles``.  ``outputs`` will contain the following
        files:

        mixeltype : list
            filename(s)
        partial_volume_map : list
            filenames, one for each input
        partial_volume_files : list
            filenames, one for each class, for each input
        tissue_class_map : list
            filename(s), each tissue has unique int value
        tissue_class_files : list
            filenames, one for each class, for each input
        restored_image : list
            filename(s) bias corrected image(s)
        bias_field : list
            filename(s)
        probability_maps : list
            filenames, one for each class, for each input

        """

        outputs = Bunch(mixeltype=[],
                seg=[],
                partial_volume_map=[],
                partial_volume_files=[],
                tissue_class_map=[],
                tissue_class_files=[],
                bias_corrected=[],
                bias_field=[],
                prob_maps=[])
        return outputs

    def aggregate_outputs(self):
        """Create a Bunch which contains all possible files generated
        by running the interface.  Some files are always generated, others
        depending on which ``inputs`` options are set.

        Returns
        -------
        outputs : Bunch object

        Notes
        -----
        For each item in Bunch:
        If [] empty list, optional file was not generated
        Else, list contains path,filename of generated outputfile(s)

        Raises
        ------
        IOError
            If any expected output file is not found.

        """
        _, envext = FSLInfo.outputtype()
        outputs = self.outputs()

        if not is_container(self.inputs.infiles):
            infiles = [self.inputs.infiles]
        else:
            infiles = self.inputs.infiles
        for item in infiles:
            # get basename (correct fsloutpputytpe extension)
            if self.inputs.out_basename:
                pth, nme = os.path.split(item)
                _, _ = os.path.splitext(nme)
                item = pth + self.inputs.out_basename + envext
            else:
                nme, _ = os.path.splitext(item)
                item = nme + envext
            # get number of tissue classes
            if not self.inputs.number_classes:
                nclasses = 3
            else:
                nclasses = self.inputs.number_classes

            # always seg, (plus mutiple?)
            outputs.seg.append(fname_presuffix(item, suffix='_seg'))
            if self.inputs.segments:
                for i in range(nclasses):
                    outputs.seg.append(fname_presuffix(item,
                        suffix='_seg_%d' % (i)))
                    # always pve,mixeltype unless nopve = True
            if not self.inputs.nopve:
                fname = fname_presuffix(item, suffix='_pveseg')
                outputs.partial_volume_map.append(fname)
                fname = fname_presuffix(item, suffix='_mixeltype')
                outputs.mixeltype.append(fname)

                for i in range(nclasses):
                    fname = fname_presuffix(item, suffix='_pve_%d' % (i))
                    outputs.partial_volume_files.append(fname)

            # biasfield ?
            if self.inputs.output_biasfield:
                outputs.bias_field.append(fname_presuffix(item, suffix='_bias'))

            # restored image (bias corrected)?
            if self.inputs.output_biascorrected:
                fname = fname_presuffix(item, suffix='_restore')
                outputs.biascorrected.append(fname)

            # probability maps ?
            if self.inputs.probability_maps:
                for i in range(nclasses):
                    fname = fname_presuffix(item, suffix='_prob_%d' % (i))
                    outputs.prob_maps.append(fname)

        # For each output file-type (key), check that any expected
        # files in the output list exist.
        for outtype, outlist in outputs.items():
            if len(outlist) > 0:
                for outfile in outlist:
                    if not len(glob(outfile)) == 1:
                        msg = "Output file '%s' of type '%s' was not generated"\
                                % (outfile, outtype)
                        raise IOError(msg)

        return outputs


class Flirt(FSLCommand):
    """Use FSL FLIRT for coregistration.
<commit_msg>Start FlirtInputSpec<commit_after>"""The fsl module provides classes for interfacing with the `FSL
<http://www.fmrib.ox.ac.uk/fsl/index.html>`_ command line tools.  This
was written to work with FSL version 4.1.4.

Examples
--------
See the docstrings of the individual classes for examples.

"""

import os
from glob import glob
import warnings

from nipype.interfaces.fsl.base import FSLCommand, FSLInfo
from nipype.interfaces.fsl.base import NEW_FSLCommand, FSLTraitedSpec
from nipype.interfaces.base import Bunch, TraitedSpec, isdefined, File
from nipype.utils.filemanip import fname_presuffix, list_to_filename
from nipype.utils.docparse import get_doc
from nipype.utils.misc import container_to_string, is_container

import enthought.traits.api as traits

warn = warnings.warn
warnings.filterwarnings('always', category=UserWarning)

class BetInputSpec(FSLTraitedSpec):
    '''Note: Currently we don't support -R, -S, -Z,-A or -A2'''
    # We use position args here as list indices - so a negative number
    # will put something on the end
    infile = File(exists=True,
                  desc = 'input file to skull strip',
                  argstr='%s', position=0, mandatory=True)
    outfile = File(desc = 'name of output skull stripped image',
                   argstr='%s', position=1, genfile=True)
    outline = traits.Bool(desc = 'create surface outline image',
                          argstr='-o')
    mask = traits.Bool(desc = 'create binary mask image',
                       argstr='-m')
    skull = traits.Bool(desc = 'create skull image',
                        argstr='-s')
    nooutput = traits.Bool(argstr='-n',
                           desc="Don't generate segmented output")
    frac = traits.Float(desc = 'fractional intensity threshold',
                        argstr='-f %.2f')
    vertical_gradient = traits.Float(argstr='-g %.2f',
             desc='vertical gradient in fractional intensity ' \
                                         'threshold (-1, 1)')
    radius = traits.Int(argstr='-r %d', units='mm',
                        desc="head radius")
    center = traits.List(traits.Int, desc = 'center of gravity in voxels',
                         argstr='-c %s', minlen=0, maxlen=3,
                         units='voxels')
    threshold = traits.Bool(argstr='-t',
                   desc="apply thresholding to segmented brain image and mask")
    mesh = traits.Bool(argstr='-e',
                       desc="generate a vtk mesh brain surface")
    # XXX how do we know these two are mutually exclusive?
    _xor_inputs = ('functional', 'reduce_bias')
    functional = traits.Bool(argstr='-F', xor=_xor_inputs,
                             desc="apply to 4D fMRI data")
    reduce_bias = traits.Bool(argstr='-B', xor=_xor_inputs,
                              desc="bias field and neck cleanup")

class BetOutputSpec(TraitedSpec):
    outfile = File(exists=True,
                   desc="path/name of skullstripped file")
    maskfile = File(
        desc="path/name of binary brain mask (if generated)")
    outlinefile = File(
        desc="path/name of outline file (if generated)")
    meshfile = File(
        desc="path/name of vtk mesh file (if generated)")

class Bet(NEW_FSLCommand):
    """Use FSL BET command for skull stripping.

    For complete details, see the `BET Documentation.
    <http://www.fmrib.ox.ac.uk/fsl/bet2/index.html>`_

    To print out the command line help, use:
        fsl.Bet().inputs_help()

    Examples
    --------
    Initialize Bet with no options, assigning them when calling run:

    >>> from nipype.interfaces import fsl
    >>> btr = fsl.Bet()
    >>> res = btr.run('infile', 'outfile', frac=0.5) # doctest: +SKIP

    Assign options through the ``inputs`` attribute:

    >>> btr = fsl.Bet()
    >>> btr.inputs.infile = 'foo.nii'
    >>> btr.inputs.outfile = 'bar.nii'
    >>> btr.inputs.frac = 0.7
    >>> res = btr.run() # doctest: +SKIP

    Specify options when creating a Bet instance:

    >>> btr = fsl.Bet(infile='infile', outfile='outfile', frac=0.5)
    >>> res = btr.run() # doctest: +SKIP

    Loop over many inputs (Note: the snippet below would overwrite the
    outfile each time):

    >>> btr = fsl.Bet(infile='infile', outfile='outfile')
    >>> fracvals = [0.3, 0.4, 0.5]
    >>> for val in fracvals:
    ...     res = btr.run(frac=val) # doctest: +SKIP

    """

    _cmd = 'bet'
    input_spec = BetInputSpec
    output_spec = BetOutputSpec

    def _run_interface(self, runtime):
        # The returncode is meaningless in Bet.  So check the output
        # in stderr and if it's set, then update the returncode
        # accordingly.
        runtime = super(Bet, self)._run_interface(runtime)
        if runtime.stderr:
            runtime.returncode = 1
        return runtime

    def _list_outputs(self):
        outputs = self.output_spec().get()
        outputs['outfile'] = self.inputs.outfile
        if not isdefined(outputs['outfile']) and isdefined(self.inputs.infile):
            outputs['outfile'] = self._gen_fname(self.inputs.infile,
                                              suffix = '_brain')
        if isdefined(self.inputs.mesh) and self.inputs.mesh:
            outputs['meshfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mesh.vtk',
                                               change_ext = False)
        if (isdefined(self.inputs.mask) and self.inputs.mask) or \
                (isdefined(self.inputs.reduce_bias) and \
                     self.inputs.reduce_bias):
            outputs['maskfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mask')
        return outputs

    def _gen_filename(self, name):
        if name == 'outfile':
            return self._list_outputs()[name]
        return None


class FastInputSpec(FSLTraitedSpec):
    """ Defines inputs (trait classes) for Fast """
    infiles = traits.List(File(exists=True),
                          desc = 'image, or multi-channel set of images, ' \
                              'to be segmented',
                          argstr='%s', position=-1, mandatory=True)
    out_basename = File(desc = 'base name of output files',
                        argstr='-o %s', genfile=True) # maybe not genfile
    number_classes = traits.Range(low=1, high=10, argstr = '-n %d',
                                  desc = 'number of tissue-type classes')
    output_biasfield = traits.Bool(desc = 'output estimated bias field',
                                   argstr = '-b', genfile=True)
    output_biascorrected = traits.Bool(desc = 'output restored image ' \
                                           '(bias-corrected image)',
                                       argstr = '-B', genfile = True)
    img_type = traits.Enum((1,2,3), desc = 'int specifying type of image: ' \
                               '(1 = T1, 2 = T2, 3 = PD)',
                           argstr = '-t %d')
    bias_iters = traits.Range(low = 1, high = 10, argstr = '-I %d',
                              desc = 'number of main-loop iterations during ' \
                                  'bias-field removal')
    bias_lowpass = traits.Range(low = 4, high = 40, 
                                desc = 'bias field smoothing extent (FWHM) ' \
                                    'in mm',
                                argstr = '-l %d', units = 'mm')
    init_seg_smooth = traits.Range(low=0.0001, high = 0.1, 
                                   desc = 'initial segmentation spatial ' \
                                       'smoothness (during bias field ' \
                                       'estimation)',
                                   argstr = '-f %.3f')
    segments = traits.Bool(desc = 'outputs a separate binary image for each ' \
                               'tissue type',
                           argstr = '-g', genfile=True)
    init_transform = File(exists=True, desc = '<standard2input.mat> initialise'\
                              ' using priors',
                          argstr = '-a %s')
    other_priors = traits.List(File, desc = 'alternative prior images',
                               argstr = '-A %s', minlen=3, maxlen=3)
    nopve = traits.Bool(desc = 'turn off PVE (partial volume estimation)',
                        argstr = '--nopve')
    nobias = traits.Bool(desc = 'do not remove bias field',
                         argstr = '-N')
    use_priors = traits.Bool(desc = 'use priors throughout',
                             argstr = '-P')   # must also set -a!,
                                              # mutually inclusive??
                                              # No, conditional
                                              # mandatory... need to
                                              # figure out how to
                                              # handle with traits.
    segment_iters = traits.Range(low=1, high=50, 
                                 desc = 'number of segmentation-initialisation'\
                                     ' iterations',
                                 argstr = '-W %d')
    mixel_smooth = traits.Range(low = 0.0, high=1.0, 
                                desc = 'spatial smoothness for mixeltype',
                                argstr = '-R %.2f')
    iters_afterbias = traits.Range(low = 1, hight = 20,
                                   desc = 'number of main-loop iterations ' \
                                       'after bias-field removal',
                                   argstr = '-O %d')
    hyper = traits.Range(low = 0.0, high = 1.0, 
                         desc = 'segmentation spatial smoothness',
                         argstr = '-H %.2f')
    verbose = traits.Bool(desc = 'switch on diagnostic messages',
                          argstr = '-v')
    manualseg = File(exists=True, desc = 'Filename containing intensities',
                     argstr = '-s %s')
    probability_maps = traits.Bool(desc = 'outputs individual probability maps',
                                   argstr = '-p', genfile = True)
    

class FastOutputSpec(TraitedSpec):
    """Specify possible outputs from Fast"""
    tissue_class_map = File(exists=True,
                            desc = 'path/name of binary segmented volume file' \
                                ' one val for each class  _seg')
    tissue_class_files = File(desc = 'path/name of binary segmented volumes ' \
                                  'one file for each class  _seg_x')
    restored_image = File(desc = 'restored images (one for each input image) ' \
                              'named according to the input images _restore')

    mixeltype  = File(desc = "path/name of mixeltype volume file _mixeltype")

    partial_volume_map = File(desc = "path/name of partial volume file _pveseg")
    partial_volume_files  = File(desc = 'path/name of partial volumes files ' \
                                     'one for each class, _pve_x')
    
    bias_field = File(desc = 'Estimated bias field _bias')
    probability_maps = File(desc= 'filenames, one for each class, for each ' \
                                'input, prob_x')


class NEW_Fast(NEW_FSLCommand):
    """ Use FSL FAST for segmenting and bias correction.

    For complete details, see the `FAST Documentation.
    <http://www.fmrib.ox.ac.uk/fsl/fast4/index.html>`_
    """
    _cmd = 'fast'
    input_spec = FastInputSpec
    output_spec = FastOutputSpec

    def _list_outputs(self):
        outputs = self.output_spec().get()
        orignames = self.inputs.infiles
        if isdefined(self.inputs.out_basename):
            basepth, basename = os.path.split(self.inputs.out_basename)
        
        for item in self.inputs.infiles:
            print item
        outputs['tissue_class_map'] = 'FIX'
        if not isdefined(outputs['outfile']) and isdefined(self.inputs.infile):
            outputs['outfile'] = self._gen_fname(self.inputs.infile,
                                              suffix = '_brain')
        if isdefined(self.inputs.mesh) and self.inputs.mesh:
            outputs['meshfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mesh.vtk',
                                               change_ext = False)
        if (isdefined(self.inputs.mask) and self.inputs.mask) or \
                (isdefined(self.inputs.reduce_bias) and self.inputs.reduce_bias):
            outputs['maskfile'] = self._gen_fname(outputs['outfile'],
                                               suffix = '_mask')
        return outputs 


   

class Fast(FSLCommand):
    """Use FSL FAST for segmenting and bias correction.

    For complete details, see the `FAST Documentation.
    <http://www.fmrib.ox.ac.uk/fsl/fast4/index.html>`_

    To print out the command line help, use:
        fsl.Fast().inputs_help()

    Examples
    --------
    >>> from nipype.interfaces import fsl
    >>> faster = fsl.Fast(out_basename = 'myfasted')
    >>> fasted = faster.run(['file1', 'file2'])

    >>> faster = fsl.Fast(infiles=['filea', 'fileb'], out_basename='myfasted')
    >>> fasted = faster.run()

    """

    @property
    def cmd(self):
        """sets base command, not editable"""
        return 'fast'

    opt_map = {'number_classes':       '-n %d',
            'bias_iters':           '-I %d',
            'bias_lowpass':         '-l %d',  # in mm
            'img_type':             '-t %d',
            'init_seg_smooth':      '-f %.3f',
            'segments':             '-g',
            'init_transform':       '-a %s',
            # This option is not really documented on the Fast web page:
            # http://www.fmrib.ox.ac.uk/fsl/fast4/index.html#fastcomm
            # I'm not sure if there are supposed to be exactly 3 args or what
            'other_priors':         '-A %s %s %s',
            'nopve':                '--nopve',
            'output_biasfield':     '-b',
            'output_biascorrected': '-B',
            'nobias':               '-N',
            'n_inputimages':        '-S %d',
            'out_basename':         '-o %s',
            'use_priors':           '-P',  # must also set -a!
            'segment_iters':        '-W %d',
            'mixel_smooth':         '-R %.2f',
            'iters_afterbias':      '-O %d',
            'hyper':                '-H %.2f',
            'verbose':              '-v',
            'manualseg':            '-s %s',
            'probability_maps':     '-p',
            'infiles':               None,
            }

    def inputs_help(self):
        """Print command line documentation for FAST."""
        print get_doc(self.cmd, self.opt_map, trap_error=False)

    def run(self, infiles=None, **inputs):
        """Execute the FSL fast command.

        Parameters
        ----------
        infiles : string or list of strings
            File(s) to be segmented or bias corrected
        inputs : dict, optional
            Additional ``inputs`` assignments can be passed in.

        Returns
        -------
        results : InterfaceResult
            An :class:`nipype.interfaces.base.InterfaceResult` object
            with a copy of self in `interface`

        """

        if infiles:
            self.inputs.infiles = infiles
        if not self.inputs.infiles:
            raise AttributeError('Fast requires input file(s)')
        self.inputs.update(**inputs)
        return super(Fast, self).run()

    def _parse_inputs(self):
        '''Call our super-method, then add our input files'''
        # Could do other checking above and beyond regular _parse_inputs here
        allargs = super(Fast, self)._parse_inputs(skip=('infiles'))
        if self.inputs.infiles:
            allargs.append(container_to_string(self.inputs.infiles))
        return allargs

    def outputs(self):
        """Returns a :class:`nipype.interfaces.base.Bunch` with outputs

        Parameters
        ----------
        Each attribute in ``outputs`` is a list.  There will be
        one set of ``outputs`` for each file specified in
        ``infiles``.  ``outputs`` will contain the following
        files:

        mixeltype : list
            filename(s)
        partial_volume_map : list
            filenames, one for each input
        partial_volume_files : list
            filenames, one for each class, for each input
        tissue_class_map : list
            filename(s), each tissue has unique int value
        tissue_class_files : list
            filenames, one for each class, for each input
        restored_image : list
            filename(s) bias corrected image(s)
        bias_field : list
            filename(s)
        probability_maps : list
            filenames, one for each class, for each input

        """

        outputs = Bunch(mixeltype=[],
                seg=[],
                partial_volume_map=[],
                partial_volume_files=[],
                tissue_class_map=[],
                tissue_class_files=[],
                bias_corrected=[],
                bias_field=[],
                prob_maps=[])
        return outputs

    def aggregate_outputs(self):
        """Create a Bunch which contains all possible files generated
        by running the interface.  Some files are always generated, others
        depending on which ``inputs`` options are set.

        Returns
        -------
        outputs : Bunch object

        Notes
        -----
        For each item in Bunch:
        If [] empty list, optional file was not generated
        Else, list contains path,filename of generated outputfile(s)

        Raises
        ------
        IOError
            If any expected output file is not found.

        """
        _, envext = FSLInfo.outputtype()
        outputs = self.outputs()

        if not is_container(self.inputs.infiles):
            infiles = [self.inputs.infiles]
        else:
            infiles = self.inputs.infiles
        for item in infiles:
            # get basename (correct fsloutpputytpe extension)
            if self.inputs.out_basename:
                pth, nme = os.path.split(item)
                _, _ = os.path.splitext(nme)
                item = pth + self.inputs.out_basename + envext
            else:
                nme, _ = os.path.splitext(item)
                item = nme + envext
            # get number of tissue classes
            if not self.inputs.number_classes:
                nclasses = 3
            else:
                nclasses = self.inputs.number_classes

            # always seg, (plus mutiple?)
            outputs.seg.append(fname_presuffix(item, suffix='_seg'))
            if self.inputs.segments:
                for i in range(nclasses):
                    outputs.seg.append(fname_presuffix(item,
                        suffix='_seg_%d' % (i)))
                    # always pve,mixeltype unless nopve = True
            if not self.inputs.nopve:
                fname = fname_presuffix(item, suffix='_pveseg')
                outputs.partial_volume_map.append(fname)
                fname = fname_presuffix(item, suffix='_mixeltype')
                outputs.mixeltype.append(fname)

                for i in range(nclasses):
                    fname = fname_presuffix(item, suffix='_pve_%d' % (i))
                    outputs.partial_volume_files.append(fname)

            # biasfield ?
            if self.inputs.output_biasfield:
                outputs.bias_field.append(fname_presuffix(item, suffix='_bias'))

            # restored image (bias corrected)?
            if self.inputs.output_biascorrected:
                fname = fname_presuffix(item, suffix='_restore')
                outputs.biascorrected.append(fname)

            # probability maps ?
            if self.inputs.probability_maps:
                for i in range(nclasses):
                    fname = fname_presuffix(item, suffix='_prob_%d' % (i))
                    outputs.prob_maps.append(fname)

        # For each output file-type (key), check that any expected
        # files in the output list exist.
        for outtype, outlist in outputs.items():
            if len(outlist) > 0:
                for outfile in outlist:
                    if not len(glob(outfile)) == 1:
                        msg = "Output file '%s' of type '%s' was not generated"\
                                % (outfile, outtype)
                        raise IOError(msg)

        return outputs

class FlirtInputSpec(FSLTraitedSpec):
    infile = File(exists = True, argstr = '-in %s', mandatory = True,
                  position = 0, desc = 'input file')
    # XXX Not clear if position is required for mandatory flirt inputs
    # since they are prefixed with argstrs.  But doing it to follow
    # our previous convention and so we can test the generated command
    # line.
    reference = File(exists = True, argstr = '-ref %s', mandatory = True,
                     position = 1, desc = 'reference file')
    # XXX need to review outfile, outmatrix and inmatrix for mandatory
    # and position metadata
    outfile = File(argstr = '-out', desc = 'output file')
    outmatrix = File(argstr = '-omat', desc = 'output affine matris in 4x4 ' \
                         'asciii format')
    inmatrix = File(argstr = '-init', desc = 'input 4x4 affine matrix')

    datatype = traits.Enum('char', 'short', 'int', 'float', 'double',
                           argstr = '-datatype %d',
                           desc = 'force output data type')

class Flirt(FSLCommand):
    """Use FSL FLIRT for coregistration.

{'fraction_non_alphanumeric': 0.10726389382628274, 'fraction_numerical': 0.004123711340206186, 'mean_word_length': 1.616643929058663, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 123, 'https://': 0, 'lorem ipsum': 0, 'www.': 10, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 108, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6869748', 'n_tokens_mistral': 11691, 'n_tokens_neox': 11210, 'n_words': 3171}