diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ISISIndirectEnergyTransfer.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ISISIndirectEnergyTransfer.py
new file mode 100644
index 0000000000000000000000000000000000000000..3979814f91c1314cdcffa186061997875fb3c8ac
--- /dev/null
+++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ISISIndirectEnergyTransfer.py
@@ -0,0 +1,842 @@
+from mantid.kernel import *
+from mantid.api import *
+from mantid.simpleapi import *
+import mantid
+import os
+import string
+import numpy as np
+
+
+_str_or_none = lambda s: s if s != '' else None
+_float_or_none = lambda i: float(i) if i != '' else None
+_elems_or_none = lambda l: l if len(l) != 0 else None
+
+
+class ISISIndirectEnergyTransfer(DataProcessorAlgorithm):
+
+    def category(self):
+        return 'Workflow\\Inelastic;PythonAlgorithms;Inelastic'
+
+
+    def summary(self):
+        return 'Runs an energy transfer reduction for an inelastic indirect geometry instrument.'
+
+
+    def PyInit(self):
+        # Input properties
+        self.declareProperty(StringArrayProperty(name='InputFiles'),
+                             doc='Comma separated list of input files')
+
+        self.declareProperty(name='SumFiles', defaultValue=False, doc='Toggle input file summing or sequential processing')
+
+        self.declareProperty(WorkspaceProperty('CalibrationWorkspace', '',
+                             direction=Direction.Input, optional=PropertyMode.Optional), doc='Workspace contining calibration data')
+
+        # Instrument configuration properties
+        self.declareProperty(name='Instrument', defaultValue='', doc='Instrument used during run.',
+                             validator=StringListValidator(['IRIS', 'OSIRIS', 'TOSCA', 'TFXA']))
+        self.declareProperty(name='Analyser', defaultValue='', doc='Analyser bank used during run.',
+                             validator=StringListValidator(['graphite', 'mica', 'fmica']))
+        self.declareProperty(name='Reflection', defaultValue='', doc='Reflection number for instrument setup during run.',
+                             validator=StringListValidator(['002', '004', '006']))
+
+        self.declareProperty(IntArrayProperty(name='SpectraRange', values=[0, 1],
+                             validator=IntArrayMandatoryValidator()),
+                             doc='Comma separated range of spectra number to use.')
+        self.declareProperty(FloatArrayProperty(name='BackgroundRange'),
+                             doc='Range of background to subtact from raw data in time of flight.')
+        self.declareProperty(name='RebinString', defaultValue='', doc='Rebin string parameters.')
+        self.declareProperty(name='DetailedBalance', defaultValue='', doc='')
+        self.declareProperty(name='ScaleFactor', defaultValue=1.0, doc='Factor by which to scale result.')
+        self.declareProperty(name='FoldMultipleFrames', defaultValue=True,
+                             doc='Folds multiple framed data sets into a single workspace.')
+
+        # Spectra grouping options
+        self.declareProperty(name='GroupingMethod', defaultValue='IPF',
+                             validator=StringListValidator(['Individual', 'All', 'File', 'Workspace', 'IPF']),
+                             doc='Method used to group spectra.')
+        self.declareProperty(WorkspaceProperty('GroupingWorkspace', '',
+                             direction=Direction.Input, optional=PropertyMode.Optional),
+                             doc='Workspace containing spectra grouping.')
+        self.declareProperty(FileProperty('MapFile', '',
+                             action=FileAction.OptionalLoad, extensions=['.map']),
+                             doc='Workspace containing spectra grouping.')
+
+        # Output properties
+        self.declareProperty(name='UnitX', defaultValue='DeltaE', doc='X axis units for the result workspace.',
+                             validator=StringListValidator(['DeltaE', 'DeltaE_inWavenumber']))
+        self.declareProperty(StringArrayProperty(name='SaveFormats'), doc='Comma seperated list of save formats')
+        self.declareProperty(name='Plot', defaultValue='None', doc='Type of plot to output after reduction.',
+                             validator=StringListValidator(['None', 'Spectra', 'Contour', 'Both']))
+
+        self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '',
+                             direction=Direction.Output),
+                             doc='Workspace group for the resulting workspaces.')
+
+
+    def PyExec(self):
+        self._setup()
+        self._load_files()
+
+        for c_ws_name in self._workspace_names:
+            is_multi_frame = isinstance(mtd[c_ws_name], WorkspaceGroup)
+
+            # Get list of workspaces
+            if is_multi_frame:
+                workspaces = mtd[c_ws_name].getNames()
+            else:
+                workspaces = [c_ws_name]
+
+            # Process rebinning for framed data
+            if self._rebin_string is not None and is_multi_frame:
+                rebin_string_comp = self._rebin_string.split(',')
+                if len(rebin_string_comp) >= 5:
+                    rebin_string_2 = ','.join(rebin_string_comp[2:])
+                else:
+                    rebin_string_2 = self._rebin_string
+
+                bin_counts = [mtd[ws].blocksize() for ws in mtd[c_ws_name].getNames()]
+                num_bins = np.amax(bin_counts)
+
+            masked_detectors = self._identify_bad_detectors(workspaces[0])
+
+            # Process workspaces
+            for ws_name in workspaces:
+                monitor_ws_name = ws_name + '_mon'
+
+                # Process monitor
+                if not self._unwrap_monitor(ws_name):
+                    ConvertUnits(InputWorkspace=monitor_ws_name, OutputWorkspace=monitor_ws_name, Target='Wavelength', EMode='Elastic')
+
+                self._process_monitor_efficiency(ws_name)
+                self._scale_monitor(ws_name)
+
+
+                # Do background removal if a range was provided
+                if self._background_range is not None:
+                    ConvertToDistribution(Workspace=ws_name)
+                    CalculateFlatBackground(InputWorkspace=ws_name, OutputWorkspace=ws_name,
+                                            StartX=self._background_range[0],
+                                            EndX=self._background_range[1],
+                                            Mode='Mean')
+                    ConvertFromDistribution(Workspace=ws_name)
+
+                # Divide by the calibration workspace if one was provided
+                if self._calibration_ws is not None:
+                    Divide(LHSWorkspace=ws_name,
+                           RHSWorkspace=self._calibration_ws,
+                           OutputWorkspace=ws_name)
+
+                # Scale detector data by monitor intensities
+                ConvertUnits(InputWorkspace=ws_name, OutputWorkspace=ws_name, Target='Wavelength', EMode='Indirect')
+                RebinToWorkspace(WorkspaceToRebin=ws_name, WorkspaceToMatch=monitor_ws_name, OutputWorkspace=ws_name)
+                Divide(LHSWorkspace=ws_name, RHSWorkspace=monitor_ws_name, OutputWorkspace=ws_name)
+
+                # Remove the no longer needed monitor workspace
+                DeleteWorkspace(monitor_ws_name)
+
+                # Convert to energy
+                ConvertUnits(InputWorkspace=ws_name, OutputWorkspace=ws_name, Target='DeltaE', EMode='Indirect')
+                CorrectKiKf(InputWorkspace=ws_name, OutputWorkspace=ws_name, EMode='Indirect')
+
+                # Handle rebinning
+                if self._rebin_string is not None:
+                    if is_multi_frame:
+                        # Mulit frame data
+                        if mtd[ws_name].blocksize() == num_bins:
+                            Rebin(InputWorkspace=ws_name, OutputWorkspace=ws_name, Params=self._rebin_string)
+                        else:
+                            Rebin(InputWorkspace=ws_name, OutputWorkspace=ws_name, Params=rebin_string_2)
+                    else:
+                        # Regular data
+                        Rebin(InputWorkspace=ws_name, OutputWorkspace=ws_name, Params=self._rebin_string)
+                else:
+                    try:
+                        # If user does not want to rebin then just ensure uniform binning across spectra
+                        RebinToWorkspace(WorkspaceToRebin=ws_name, WorkspaceToMatch=ws_name, OutputWorkspace=ws_name)
+                    except RuntimeError:
+                        logger.warning('Rebinning failed, will try to continue anyway.')
+
+                # Detailed balance
+                if self._detailed_balance is not None:
+                    corr_factor = 11.606 / (2 * self._detailed_balance)
+                    ExponentialCorrection(InputWorkspaces=ws_name, OutputWorkspace=ws_name,
+                                          C0=1.0, C1=corr_factor, Operation='Multiply')
+
+                # Scale
+                if self._scale_factor != 1.0:
+                    Scale(InputWorkspaces=ws_name, OutputWorkspace=ws_name,
+                          Factor=self._scale_factor, Operation='Multiply')
+
+                # Group spectra
+                self._group_spectra(ws_name, masked_detectors)
+
+            if self._fold_multiple_frames and is_multi_frame:
+                self._fold_chopped(c_ws_name)
+
+            # Convert to output units if needed
+            if self._output_x_units != 'DeltaE':
+                ConvertUnits(InputWorkspace=c_ws_name, OutputWorkspace=c_ws_name,
+                             EMode='Indirect', Target=self._output_x_units)
+
+        # Rename output workspaces
+        output_workspace_names = [self._rename_workspace(ws_name) for ws_name in self._workspace_names]
+
+        # Save result workspaces
+        if self._save_formats is not None:
+            self._save(output_workspace_names)
+
+        # Group result workspaces
+        GroupWorkspaces(InputWorkspaces=output_workspace_names, OutputWorkspace=self._output_ws)
+
+        self.setProperty('OutputWorkspace', self._output_ws)
+
+        # Plot result workspaces
+        if self._plot_type != 'None':
+            for ws_name in mtd[self._output_ws].getNames():
+                self._plot_workspace(ws_name)
+
+
+    def validateInputs(self):
+        """
+        Validates algorithm properties.
+        """
+        issues = dict()
+
+        # Validate the instrument configuration by checking if a parameter file exists
+        instrument_name = self.getPropertyValue('Instrument')
+        analyser = self.getPropertyValue('Analyser')
+        reflection = self.getPropertyValue('Reflection')
+
+        ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                    instrument_name + '_' + analyser + '_' + reflection + '_Parameters.xml')
+
+        if not os.path.exists(ipf_filename):
+            error_message = 'Invalid instrument configuration'
+            issues['Instrument'] = error_message
+            issues['Analyser'] = error_message
+            issues['Reflection'] = error_message
+
+        # Validate spectra range
+        spectra_range = self.getProperty('SpectraRange').value
+        if len(spectra_range) != 2:
+            issues['SpectraRange'] = 'Range must contain exactly two items'
+        elif spectra_range[0] > spectra_range[1]:
+            issues['SpectraRange'] = 'Range must be in format: lower,upper'
+
+        # Validate background range
+        background_range = _elems_or_none(self.getProperty('BackgroundRange').value)
+        if background_range is not None:
+            if len(background_range) != 2:
+                issues['BackgroundRange'] = 'Range must contain exactly two items'
+            elif background_range[0] > background_range[1]:
+                issues['BackgroundRange'] = 'Range must be in format: lower,upper'
+
+        # Validate grouping method
+        grouping_method = self.getPropertyValue('GroupingMethod')
+        grouping_ws = _str_or_none(self.getPropertyValue('GroupingWorkspace'))
+
+        if grouping_method == 'Workspace' and grouping_ws is None:
+            issues['GroupingWorkspace'] = 'Must select a grouping workspace for current GroupingWorkspace'
+
+        # Validate save formats
+        save_formats = self.getProperty('SaveFormats').value
+        valid_formats = ['nxs', 'ascii', 'spe', 'nxspe', 'aclimax', 'davegrp']
+        for format_name in save_formats:
+            if format_name not in valid_formats:
+                issues['SaveFormats'] = '%s is not a valid save format' % format_name
+                break
+
+        return issues
+
+
+    def _setup(self):
+        """
+        Gets algorithm properties.
+        """
+
+        # Get properties
+        self._data_files = self.getProperty('InputFiles').value
+        self._sum_files = self.getProperty('SumFiles').value
+        self._calibration_ws = _str_or_none(self.getPropertyValue('CalibrationWorkspace'))
+
+        self._instrument_name = self.getPropertyValue('Instrument')
+        self._analyser = self.getPropertyValue('Analyser')
+        self._reflection = self.getPropertyValue('Reflection')
+
+        self._spectra_range = self.getProperty('SpectraRange').value
+        self._background_range = _elems_or_none(self.getProperty('BackgroundRange').value)
+        self._rebin_string = _str_or_none(self.getPropertyValue('RebinString'))
+        self._detailed_balance = _float_or_none(self.getPropertyValue('DetailedBalance'))
+        self._scale_factor = self.getProperty('ScaleFactor').value
+        self._fold_multiple_frames = self.getProperty('FoldMultipleFrames').value
+
+        self._grouping_method = self.getPropertyValue('GroupingMethod')
+        self._grouping_ws = _str_or_none(self.getPropertyValue('GroupingWorkspace'))
+        self._grouping_map_file = _str_or_none(self.getPropertyValue('MapFile'))
+
+        self._output_x_units = self.getPropertyValue('UnitX')
+        self._plot_type = self.getPropertyValue('Plot')
+        self._save_formats = _elems_or_none(self.getProperty('SaveFormats').value)
+
+        self._output_ws = self.getPropertyValue('OutputWorkspace')
+
+        # Disable sum files if there is only one file
+        if len(self._data_files) == 1:
+            if self._sum_files:
+                logger.warning('SumFiles disabled when only one input file is provided.')
+            self._sum_files = False
+
+        # Get the IPF filename
+        self._ipf_filename = os.path.join(config['instrumentDefinition.directory'],
+                                          self._instrument_name + '_' + self._analyser + '_' + self._reflection + '_Parameters.xml')
+        logger.information('Instrument parameter file: %s' % self._ipf_filename)
+
+        # Warn when grouping options are to be ignored
+        if self._grouping_method != 'Workspace' and self._grouping_ws is not None:
+            logger.warning('GroupingWorkspace will be ignored by selected GroupingMethod')
+
+        if self._grouping_method != 'File' and self._grouping_map_file is not None:
+            logger.warning('MapFile will be ignored by selected GroupingMethod')
+
+        # The list of workspaces being processed
+        self._workspace_names = []
+
+
+    def _load_files(self):
+        """
+        Loads a set of files and extracts just the spectra we care about (i.e. detector range and monitor).
+        """
+
+        for filename in self._data_files:
+            # The filename without path and extension will be the workspace name
+            ws_name = os.path.splitext(os.path.basename(filename))[0]
+            logger.debug('Loading file %s as workspace %s' % (filename, ws_name))
+
+            Load(Filename=filename, OutputWorkspace=ws_name)
+
+            # Load the instrument parameters
+            LoadParameterFile(Workspace=ws_name, Filename=self._ipf_filename)
+
+            # Add the workspace to the list of workspaces
+            self._workspace_names.append(ws_name)
+
+            # Get the spectrum number for the monitor
+            instrument = mtd[ws_name].getInstrument()
+            monitor_index = int(instrument.getNumberParameter('Workflow.Monitor1-SpectrumNumber')[0])
+            logger.debug('Workspace %s monitor 1 spectrum number :%d' % (ws_name, monitor_index))
+
+            # Chop data if required
+            try:
+                chop_threshold = mtd[ws_name].getInstrument().getNumberParameter('Workflow.ChopDataIfGreaterThan')[0]
+                x_max = mtd[ws_name].readX(0)[-1]
+                self._chopped_data =  x_max > chop_threshold
+            except IndexError:
+                self._chopped_data = False
+            logger.information('Workspace %s need data chop: %s' % (ws_name, str(self._chopped_data)))
+
+            workspaces = [ws_name]
+            if self._chopped_data:
+                ChopData(InputWorkspace=ws_name, OutputWorkspace=ws_name, MonitorWorkspaceIndex=monitor_index,
+                         IntegrationRangeLower=5000.0, IntegrationRangeUpper=10000.0, NChops=5)
+                workspaces = mtd[ws_name].getNames()
+
+            for chop_ws_name in workspaces:
+                # Get the monitor spectrum
+                monitor_ws_name = chop_ws_name + '_mon'
+                ExtractSingleSpectrum(InputWorkspace=chop_ws_name, OutputWorkspace=monitor_ws_name,
+                                      WorkspaceIndex=monitor_index)
+
+                # Crop to the detectors required
+                CropWorkspace(InputWorkspace=chop_ws_name, OutputWorkspace=chop_ws_name,
+                              StartWorkspaceIndex=int(self._spectra_range[0]) - 1,
+                              EndWorkspaceIndex=int(self._spectra_range[1]) - 1)
+
+        logger.information('Loaded workspace names: %s' % (str(self._workspace_names)))
+        logger.information('Chopped data: %s' % (str(self._chopped_data)))
+
+        # Sum files if needed
+        if self._sum_files:
+            if self._chopped_data:
+                self._sum_chopped_runs()
+            else:
+                self._sum_regular_runs()
+
+        logger.information('Summed workspace names: %s' % (str(self._workspace_names)))
+
+
+    def _sum_regular_runs(self):
+        """
+        Sum runs with single workspace data.
+        """
+
+        # Use the first workspace name as the result of summation
+        summed_detector_ws_name = self._workspace_names[0]
+        summed_monitor_ws_name = self._workspace_names[0] + '_mon'
+
+        # Get a list of the run numbers for the original data
+        run_numbers = ','.join([str(mtd[ws_name].getRunNumber()) for ws_name in self._workspace_names])
+
+        # Generate lists of the detector and monitor workspaces
+        detector_workspaces = ','.join(self._workspace_names)
+        monitor_workspaces = ','.join([ws_name + '_mon' for ws_name in self._workspace_names])
+
+        # Merge the raw workspaces
+        MergeRuns(InputWorkspaces=detector_workspaces, OutputWorkspace=summed_detector_ws_name)
+        MergeRuns(InputWorkspaces=monitor_workspaces, OutputWorkspace=summed_monitor_ws_name)
+
+        # Delete old workspaces
+        for idx in range(1, len(self._workspace_names)):
+            DeleteWorkspace(self._workspace_names[idx])
+            DeleteWorkspace(self._workspace_names[idx] + '_mon')
+
+        # Derive the scale factor based on number of merged workspaces
+        scale_factor = 1.0 / len(self._workspace_names)
+        logger.information('Scale factor for summed workspaces: %f' % scale_factor)
+
+        # Scale the new detector and monitor workspaces
+        Scale(InputWorkspace=summed_detector_ws_name, OutputWorkspace=summed_detector_ws_name,
+              Factor=scale_factor)
+        Scale(InputWorkspace=summed_monitor_ws_name, OutputWorkspace=summed_monitor_ws_name,
+              Factor=scale_factor)
+
+        # Add the list of run numbers to the result workspace as a sample log
+        AddSampleLog(Workspace=summed_detector_ws_name, LogName='multi_run_numbers',
+                     LogType='String', LogText=run_numbers)
+
+        # Only have the one workspace now
+        self._workspace_names = [summed_detector_ws_name]
+
+
+    def _sum_chopped_runs(self):
+        """
+        Sum runs with chopped data.
+        """
+
+        try:
+            num_merges = len(mtd[self._workspace_names[0]].getNames())
+        except:
+            raise RuntimeError('Not all runs have been chapped, cannot sum.')
+
+        merges = list()
+
+        # Generate a list of workspaces to be merged
+        for idx in range(0, num_merges):
+            merges.append({'detector':list(), 'monitor':list()})
+
+            for ws_name in self._workspace_names:
+                detector_ws_name = mtd[ws_name].getNames()[idx]
+                monitor_ws_name = detector_ws_name + '_mon'
+
+                merges[idx]['detector'].append(detector_ws_name)
+                merges[idx]['monitor'].append(monitor_ws_name)
+
+        for merge in merges:
+            # Merge the chopped run segments
+            MergeRuns(InputWorkspaces=','.join(merge['detector']), OutputWorkspace=merge['detector'][0])
+            MergeRuns(InputWorkspaces=','.join(merge['monitor']), OutputWorkspace=merge['monitor'][0])
+
+            # Scale the merged runs
+            merge_size = len(merge['detector'])
+            factor = 1.0 / merge_size
+            Scale(InputWorkspace=merge['detector'][0], OutputWorkspace=merge['detector'][0], Factor=factor, Operation='Multiply')
+            Scale(InputWorkspace=merge['monitor'][0], OutputWorkspace=merge['monitor'][0], Factor=factor, Operation='Multiply')
+
+            # Remove the old workspaces
+            for idx in range(1, merge_size):
+                DeleteWorkspace(merge['detector'][idx])
+                DeleteWorkspace(merge['monitor'][idx])
+
+        # Only have the one workspace now
+        self._workspace_names = [self._workspace_names[0]]
+
+
+    def _identify_bad_detectors(self, ws_name):
+        """
+        Identify detectors which should be masked
+
+        @param ws_name Name of worksapce to use ot get masking detectors
+        """
+
+        instrument = mtd[ws_name].getInstrument()
+
+        try:
+            masking_type = instrument.getStringParameter('Workflow.Masking')[0]
+        except IndexError:
+            masking_type = 'None'
+
+        logger.information('Masking type: %s' % (masking_type))
+
+        masked_spec = list()
+
+        if masking_type == 'IdentifyNoisyDetectors':
+            ws_mask = '__workspace_mask'
+            IdentifyNoisyDetectors(InputWorkspace=ws_name, OutputWorkspace=ws_mask)
+
+            # Convert workspace to a list of spectra
+            num_spec = mtd[ws_mask].getNumberHistograms()
+            masked_spec = [spec for spec in range(0, num_spec) if mtd[ws_mask].readY(spec)[0] == 0.0]
+
+            # Remove the temporary masking workspace
+            DeleteWorkspace(ws_mask)
+
+        logger.debug('Masked specta for workspace %s: %s' % (ws_name, str(masked_spec)))
+
+        return masked_spec
+
+
+    def _unwrap_monitor(self, ws_name):
+        """
+        Unwrap monitor if required based on value of Workflow.UnwrapMonitor parameter
+
+        @param ws_name Name of workspace
+        @return True if the monitor was unwrapped
+        """
+
+        monitor_ws_name = ws_name + '_mon'
+        instrument = mtd[monitor_ws_name].getInstrument()
+
+        # Determine if the monitor should be unwrapped
+        try:
+            unwrap = instrument.getStringParameter('Workflow.UnwrapMonitor')[0]
+
+            if unwrap == 'Always':
+                should_unwrap = True
+            elif unwrap == 'BaseOnTimeRegime':
+                mon_time = mtd[monitor_ws_name].readX(0)[0]
+                det_time = mtd[ws_name].readX(0)[0]
+                logger.notice(str(mon_time) + " " + str(det_time))
+                should_unwrap = mon_time == det_time
+            else:
+                should_unwrap = False
+
+        except IndexError:
+            should_unwrap = False
+
+        logger.debug('Need to unwrap monitor for %s: %s' % (ws_name, str(should_unwrap)))
+
+        if should_unwrap:
+            sample = instrument.getSample()
+            sample_to_source = sample.getPos() - instrument.getSource().getPos()
+            radius = mtd[ws_name].getDetector(0).getDistance(sample)
+            z_dist = sample_to_source.getZ()
+            l_ref = z_dist + radius
+
+            logger.debug('For workspace %s: radius=%d, z_dist=%d, l_ref=%d' %
+                         (ws_name, radius, z_dist, l_ref))
+
+            _, join = UnwrapMonitor(InputWorkspace=monitor_ws_name,
+                                    OutputWorkspace=monitor_ws_name, LRef=l_ref)
+
+            RemoveBins(InputWorkspace=monitor_ws_name, OutputWorkspace=monitor_ws_name,
+                       XMin=join - 0.001, XMax=join + 0.001,
+                       Interpolation='Linear')
+
+            try:
+                FFTSmooth(InputWorkspace=monitor_ws_name, OutputWorkspace=monitor_ws_name, WorkspaceIndex=0)
+            except ValueError:
+                raise ValueError('Uneven bin widths are not supported.')
+
+        return should_unwrap
+
+
+    def _process_monitor_efficiency(self, ws_name):
+        """
+        Process monitor efficiency for a given workspace.
+
+        @param ws_name Name of workspace to process monitor for
+        """
+
+        monitor_ws_name = ws_name + '_mon'
+        instrument = mtd[ws_name].getInstrument()
+
+        try:
+            area = instrument.getNumberParameter('Workflow.Monitor1-Area')[0]
+            thickness = instrument.getNumberParameter('Workflow.Monitor1-Thickness')[0]
+            attenuation = instrument.getNumberParameter('Workflow.Monitor1-Attenuation')[0]
+        except IndexError:
+            raise ValueError('Cannot get monitor details form parameter file')
+
+        if area == -1 or thickness == -1 or attenuation == -1:
+            logger.information('For workspace %s, skipping monitor efficiency' % (ws_name))
+            return
+
+        OneMinusExponentialCor(InputWorkspace=monitor_ws_name, OutputWorkspace=monitor_ws_name,
+                               C=attenuation * thickness, C1=area)
+
+
+    def _scale_monitor(self, ws_name):
+        """
+        Scale monitor intensity by a factor given as the Workflow.MonitorScalingFactor parameter.
+
+        @param ws_name Name of workspace to process monitor for
+        """
+
+        monitor_ws_name = ws_name + '_mon'
+        instrument = mtd[ws_name].getInstrument()
+
+        try:
+            scale_factor = instrument.getNumberParameter('Workflow.Monitor1-ScalingFactor')[0]
+        except IndexError:
+            logger.information('No monitor scaling factor found for workspace %s' % ws_name)
+            return
+
+        if scale_factor != 1.0:
+            Scale(InputWorkspace=monitor_ws_name, OutputWorkspace=monitor_ws_name,
+                  Factor=1.0 / scale_factor, Operation='Multiply')
+
+
+    def _group_spectra(self, ws_name, masked_detectors):
+        """
+        Groups spectra in a given workspace according to the Workflow.GroupingMethod and
+        Workflow.GroupingFile parameters and GrpupingPolicy property.
+
+        @param ws_name Name of workspace to group spectra of
+        @param masked_detectors List of spectra numbers to mask
+        """
+
+        instrument = mtd[ws_name].getInstrument()
+
+        # If grouping as per he IPF is desired
+        if self._grouping_method == 'IPF':
+            # Get the grouping method from the parameter file
+            try:
+                grouping_method = instrument.getStringParameter('Workflow.GroupingMethod')[0]
+            except IndexError:
+                grouping_method = 'Individual'
+
+        else:
+            # Otherwise use the value of GroupingPolicy
+            grouping_method = self._grouping_method
+
+        logger.information('Grouping method for workspace %s is %s' % (ws_name, grouping_method))
+
+        if grouping_method == 'Individual':
+            # Nothing to do here
+            return
+
+        elif grouping_method == 'All':
+            # Get a list of all spectra minus those which are masked
+            num_spec = mtd[ws_name].getNumberHistograms()
+            spectra_list = [spec for spec in range(0, num_spec) if spec not in masked_detectors]
+
+            # Apply the grouping
+            GroupDetectors(InputWorkspace=ws_name, OutputWorkspace=ws_name, Behaviour='Average',
+                           WorkspaceIndexList=spectra_list)
+
+        elif grouping_method == 'File':
+            # Get the filename for the grouping file
+            if self._grouping_map_file is not None:
+                grouping_file = self._grouping_map_file
+            else:
+                try:
+                    grouping_file = instrument.getStringParameter('Workflow.GroupingFile')[0]
+                except IndexError:
+                    raise RuntimeError('Cannot get grouping file from properties or IPF.')
+
+            # If the file is not found assume it is in the grouping files directory
+            if not os.path.isfile(grouping_file):
+                grouping_file = os.path.join(config.getString('groupingFiles.directory'), grouping_file)
+
+            # If it is still not found just give up
+            if not os.path.isfile(grouping_file):
+                raise RuntimeError('Cannot find grouping file: %s' % (grouping_file))
+
+            # Mask detectors if required
+            if len(masked_detectors) > 0:
+                MaskDetectors(Workspace=ws_name, WorkspaceIndexList=masked_detectors)
+
+            # Apply the grouping
+            GroupDetectors(InputWorkspace=ws_name, OutputWorkspace=ws_name, Behaviour='Average',
+                           MapFile=grouping_file)
+
+        elif grouping_method == 'Workspace':
+            # Apply the grouping
+            GroupDetectors(InputWorkspace=ws_name, OutputWorkspace=ws_name, Behaviour='Average',
+                           CopyGroupingFromWorkspace=self._grouping_ws)
+
+        else:
+            raise RuntimeError('Invalid grouping method %s for workspace %s' % (grouping_method, ws_name))
+
+
+    def _fold_chopped(self, ws_name):
+        """
+        Folds multiple frames of a data set into one workspace.
+
+        @param ws_name Name of the group to fold
+        """
+
+        workspaces = mtd[ws_name].getNames()
+        merged_ws = ws_name + '_merged'
+        MergeRuns(InputWorkspaces=','.join(workspaces), OutputWorkspace=merged_ws)
+
+        scaling_ws = '__scaling_ws'
+        unit = mtd[ws_name].getItem(0).getAxis(0).getUnit().unitID()
+
+        ranges = []
+        for ws in mtd[ws_name].getNames():
+            x_min = mtd[ws].dataX(0)[0]
+            x_max = mtd[ws].dataX(0)[-1]
+            ranges.append((x_min, x_max))
+            DeleteWorkspace(Workspace=ws)
+
+        data_x = mtd[merged_ws].readX(0)
+        data_y = []
+        data_e = []
+
+        for i in range(0, mtd[merged_ws].blocksize()):
+            y_val = 0.0
+            for rng in ranges:
+                if data_x[i] >= rng[0] and data_x[i] <= rng[1]:
+                    y_val += 1.0
+
+            data_y.append(y_val)
+            data_e.append(0.0)
+
+        CreateWorkspace(OutputWorkspace=scaling_ws, DataX=data_x, DataY=data_y, DataE=data_e, UnitX=unit)
+
+        Divide(LHSWorkspace=merged_ws, RHSWorkspace=scaling_ws, OutputWorkspace=ws_name)
+        DeleteWorkspace(Workspace=merged_ws)
+        DeleteWorkspace(Workspace=scaling_ws)
+
+    def _rename_workspace(self, ws_name):
+        """
+        Renames a worksapce according to the naming policy in the Workflow.NamingConvention parameter.
+
+        @param ws_name Name of workspace
+        @return New name of workspace
+        """
+
+        is_multi_frame = isinstance(mtd[ws_name], WorkspaceGroup)
+
+        # Get the instrument
+        if is_multi_frame:
+            instrument = mtd[ws_name].getItem(0).getInstrument()
+        else:
+            instrument = mtd[ws_name].getInstrument()
+
+        # Get the naming convention parameter form the parameter file
+        try:
+            convention = instrument.getStringParameter('Workflow.NamingConvention')[0]
+        except IndexError:
+            # Defualt to run title if naming convention parameter not set
+            convention = 'RunTitle'
+        logger.information('Naming convention for workspace %s is %s' % (ws_name, convention))
+
+        # Get run number
+        if is_multi_frame:
+            run_number = mtd[ws_name].getItem(0).getRun()['run_number'].value
+        else:
+            run_number = mtd[ws_name].getRun()['run_number'].value
+        logger.information('Run number for workspace %s is %s' % (ws_name, run_number))
+
+        inst_name = instrument.getName()
+        for facility in config.getFacilities():
+            try:
+                short_inst_name = facility.instrument(inst_name).shortName()
+                break
+            except:
+                pass
+        logger.information('Short name for instrument %s is %s' % (inst_name, short_inst_name))
+
+        # Get run title
+        if is_multi_frame:
+            run_title = mtd[ws_name].getItem(0).getRun()['run_title'].value.strip()
+        else:
+            run_title = mtd[ws_name].getRun()['run_title'].value.strip()
+        logger.information('Run title for workspace %s is %s' % (ws_name, run_title))
+
+        if self._sum_files:
+            multi_run_marker = '_multi'
+        else:
+            multi_run_marker = ''
+
+        if convention == 'None':
+            new_name = ws_name
+
+        elif convention == 'RunTitle':
+            valid = "-_.() %s%s" % (string.ascii_letters, string.digits)
+            formatted_title = ''.join([c for c in run_title if c in valid])
+            new_name = '%s%s%s-%s' % (short_inst_name.lower(), run_number, multi_run_marker, formatted_title)
+
+        elif convention == 'AnalyserReflection':
+            analyser = instrument.getStringParameter('analyser')[0]
+            reflection = instrument.getStringParameter('reflection')[0]
+            new_name = '%s%s%s_%s%s_red' % (short_inst_name.upper(), run_number, multi_run_marker,
+                                            analyser, reflection)
+
+        else:
+            raise RuntimeError('No valid naming convention for workspace %s' % ws_name)
+
+        logger.information('New name for %s workspace: %s' % (ws_name, new_name))
+
+        RenameWorkspace(InputWorkspace=ws_name, OutputWorkspace=new_name)
+        return new_name
+
+
+    def _plot_workspace(self, ws_name):
+        """
+        Plot a given workspace based on the Plot property.
+
+        @param ws_name Name of workspace to plot
+        """
+
+        if self._plot_type == 'Spectra' or self._plot_type == 'Both':
+            from mantidplot import plotSpectrum
+            num_spectra = mtd[ws_name].getNumberHistograms()
+            try:
+                plotSpectrum(ws_name, range(0, num_spectra))
+            except RuntimeError:
+                logger.notice('Spectrum plotting canceled by user')
+
+        can_plot_contour = mtd[ws_name].getNumberHistograms() > 1
+        if (self._plot_type == 'Contour' or self._plot_type == 'Both') and can_plot_contour:
+            from mantidplot import importMatrixWorkspace
+            plot_workspace = importMatrixWorkspace(ws_name)
+            plot_workspace.plotGraph2D()
+
+
+    def _save(self, worksspace_names):
+        """
+        Saves the workspaces to the default save directory.
+
+        @param worksspace_names List of workspace names to save
+        """
+
+        for ws_name in worksspace_names:
+            if 'spe' in self._save_formats:
+                SaveSPE(InputWorkspace=ws_name, Filename=ws_name + '.spe')
+
+            if 'nxs' in self._save_formats:
+                SaveNexusProcessed(InputWorkspace=ws_name, Filename=ws_name + '.nxs')
+
+            if 'nxspe' in self._save_formats:
+                SaveNXSPE(InputWorkspace=ws_name, Filename=ws_name + '.nxspe')
+
+            if 'ascii' in self._save_formats:
+                # Version 1 of SaveASCII produces output that works better with excel/origin
+                # For some reason this has to be done with an algorithm object, using the function
+                # wrapper with Version did not change the version that was run
+                saveAsciiAlg = mantid.api.AlgorithmManager.createUnmanaged('SaveAscii', 1)
+                saveAsciiAlg.initialize()
+                saveAsciiAlg.setProperty('InputWorkspace', ws_name)
+                saveAsciiAlg.setProperty('Filename', ws_name + '.dat')
+                saveAsciiAlg.execute()
+
+            if 'aclimax' in self._save_formats:
+                if self._output_x_units == 'DeltaE_inWavenumber':
+                    bins = '24, -0.005, 4000' #cm-1
+                else:
+                    bins = '3, -0.005, 500' #meV
+                Rebin(InputWorkspace=ws_name,OutputWorkspace= ws_name + '_aclimax_save_temp', Params=bins)
+                SaveAscii(InputWorkspace=ws_name + '_aclimax_save_temp', Filename=ws_name + '_aclimax.dat', Separator='Tab')
+                DeleteWorkspace(Workspace=ws_name + '_aclimax_save_temp')
+
+            if 'davegrp' in self._save_formats:
+                ConvertSpectrumAxis(InputWorkspace=ws_name, OutputWorkspace=ws_name + '_davegrp_save_temp', Target='ElasticQ', EMode='Indirect')
+                SaveDaveGrp(InputWorkspace=ws_name + '_davegrp_save_temp', Filename=ws_name + '.grp')
+                DeleteWorkspace(Workspace=ws_name + '_davegrp_save_temp')
+
+
+# Register algorithm with Mantid
+AlgorithmFactory.subscribe(ISISIndirectEnergyTransfer)
diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectCalibration.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectCalibration.py
index 316d12877b0f512c79da826ec4437c7e67c8c642..e0b2ddb9cf82e0e26278a0310464c70db097232f 100644
--- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectCalibration.py
+++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectCalibration.py
@@ -29,26 +29,28 @@ class IndirectCalibration(DataProcessorAlgorithm):
         self.declareProperty(StringArrayProperty(name='InputFiles'),
                              doc='Comma separated list of input files')
 
-        self.declareProperty(WorkspaceProperty('OutputWorkspace', '',\
-                             direction=Direction.Output),
-                             doc='Output workspace for calibration data')
-
         self.declareProperty(IntArrayProperty(name='DetectorRange', values=[0, 1],\
                              validator=IntArrayMandatoryValidator()),
-                             doc='Range of detectors')
+                             doc='Range of detectors.')
 
         self.declareProperty(FloatArrayProperty(name='PeakRange', values=[0.0, 100.0],\
                              validator=FloatArrayMandatoryValidator()),
-                             doc='')
+                             doc='Time of flight range over the peak.')
 
         self.declareProperty(FloatArrayProperty(name='BackgroundRange', values=[0.0, 1000.0],\
                              validator=FloatArrayMandatoryValidator()),
-                             doc='')
+                             doc='Time of flight range over the background.')
 
         self.declareProperty(name='ScaleFactor', defaultValue=1.0,
-                             doc='')
+                             doc='Factor by which to scale the result.')
+
+        self.declareProperty(name='Plot', defaultValue=False,
+                             doc='Plot the calibration data as a spectra plot.')
+
+        self.declareProperty(WorkspaceProperty('OutputWorkspace', '',
+                             direction=Direction.Output),
+                             doc='Output workspace for calibration data.')
 
-        self.declareProperty(name='Plot', defaultValue=False, doc='Plot the calibration data')
 
 
     def validateInputs(self):
@@ -107,14 +109,25 @@ class IndirectCalibration(DataProcessorAlgorithm):
         else:
             calib_ws_name = runs[0]
 
-        CalculateFlatBackground(InputWorkspace=calib_ws_name, OutputWorkspace=calib_ws_name,\
-                StartX=self._back_range[0], EndX=self._back_range[1], Mode='Mean')
+        CalculateFlatBackground(InputWorkspace=calib_ws_name, OutputWorkspace=calib_ws_name,
+                                StartX=self._back_range[0], EndX=self._back_range[1], Mode='Mean')
+
+        number_historgrams = mtd[calib_ws_name].getNumberHistograms()
+        ws_mask, num_zero_spectra = FindDetectorsOutsideLimits(InputWorkspace=calib_ws_name, OutputWorkspace='__temp_ws_mask')
+        DeleteWorkspace(ws_mask)
+
+        Integration(InputWorkspace=calib_ws_name, OutputWorkspace=calib_ws_name,
+                    RangeLower=self._peak_range[0], RangeUpper=self._peak_range[1])
+
+        temp_sum = SumSpectra(InputWorkspace=calib_ws_name, OutputWorkspace='__temp_sum')
+        total = temp_sum.readY(0)[0]
+        DeleteWorkspace(temp_sum)
+
+        if self._intensity_scale is None:
+            self._intensity_scale = 1 / (total / (number_historgrams - num_zero_spectra))
 
-        from inelastic_indirect_reduction_steps import NormaliseToUnityStep
-        ntu = NormaliseToUnityStep()
-        ntu.set_factor(self._intensity_scale)
-        ntu.set_peak_range(self._peak_range[0], self._peak_range[1])
-        ntu.execute(None, calib_ws_name)
+        Scale(InputWorkspace=calib_ws_name, OutputWorkspace=calib_ws_name,
+              Factor=self._intensity_scale, Operation='Multiply')
 
         RenameWorkspace(InputWorkspace=calib_ws_name, OutputWorkspace=self._out_ws)
 
diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py
index 1e3ccff2bcb72750d5385da98525dce03f355f14..4e44f558bbffd3a82cbdae85be954ca21d09d833 100644
--- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py
+++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectResolution.py
@@ -22,62 +22,59 @@ class IndirectResolution(DataProcessorAlgorithm):
     def category(self):
         return 'Workflow\\Inelastic;PythonAlgorithms;Inelastic'
 
+
     def summary(self):
-        return 'Creates a resolution workspace'
+        return 'Creates a resolution workspace for an indirect inelastic instrument.'
+
 
     def PyInit(self):
         self.declareProperty(StringArrayProperty(name='InputFiles'),
                              doc='Comma seperated list if input files')
 
-        self.declareProperty(WorkspaceProperty('OutputWorkspace', '',\
-                             optional=PropertyMode.Optional,\
-                             direction=Direction.Output),
-                             doc='Output resolution workspace (if left blank a name will '
-                                 'be gernerated automatically)')
-
         self.declareProperty(name='Instrument', defaultValue='',
                              validator=StringListValidator(['IRIS', 'OSIRIS', 'TOSCA']),
-                             doc='Instrument used during run')
+                             doc='Instrument used during run.')
         self.declareProperty(name='Analyser', defaultValue='',
                              validator=StringListValidator(['graphite', 'mica', 'fmica']),
-                             doc='Analyser used during run')
+                             doc='Analyser used during run.')
         self.declareProperty(name='Reflection', defaultValue='',
                              validator=StringListValidator(['002', '004', '006']),
-                             doc='Reflection used during run')
+                             doc='Reflection used during run.')
 
         self.declareProperty(IntArrayProperty(name='DetectorRange', values=[0, 1]),
-                             doc='Range of detetcors to use in resolution calculation')
+                             doc='Range of detetcors to use in resolution calculation.')
         self.declareProperty(FloatArrayProperty(name='BackgroundRange', values=[0.0, 0.0]),
-                             doc='Energy range to use as background')
+                             doc='Energy range to use as background.')
+
 
         self.declareProperty(name='RebinParam', defaultValue='',
                              doc='Rebinning parameters (min,width,max)')
         self.declareProperty(name='ScaleFactor', defaultValue=1.0,
                              doc='Factor to scale resolution curve by')
 
+
         self.declareProperty(name='Plot', defaultValue=False, doc='Plot resolution curve')
         self.declareProperty(name='Save', defaultValue=False,
                              doc='Save resolution workspace as a Nexus file')
 
+        self.declareProperty(WorkspaceProperty('OutputWorkspace', '',
+                             direction=Direction.Output),
+                             doc='Output resolution workspace.')
 
     def PyExec(self):
         from IndirectCommon import getWSprefix
-
         self._setup()
 
-        InelasticIndirectReduction(Instrument=self._instrument,
+        ISISIndirectEnergyTransfer(Instrument=self._instrument,
                                    Analyser=self._analyser,
                                    Reflection=self._reflection,
-                                   Grouping='All',
+                                   GroupingMethod='All',
                                    SumFiles=True,
                                    InputFiles=self._input_files,
-                                   DetectorRange=self._detector_range,
-                                   OutputWorkspace='__icon_ws_group')
-
-        icon_ws = mtd['__icon_ws_group'].getItem(0).getName()
+                                   SpectraRange=self._detector_range,
+                                   OutputWorkspace='__et_ws_group')
 
-        if self._out_ws == "":
-            self._out_ws = getWSprefix(icon_ws) + 'res'
+        icon_ws = mtd['__et_ws_group'].getItem(0).getName()
 
         if self._scale_factor != 1.0:
             Scale(InputWorkspace=icon_ws, OutputWorkspace=icon_ws, Factor=self._scale_factor)
diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py
deleted file mode 100644
index 39070394a695e4f5815bd9135966038d838d16d4..0000000000000000000000000000000000000000
--- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py
+++ /dev/null
@@ -1,246 +0,0 @@
-#pylint: disable=no-init
-from mantid.kernel import *
-from mantid.api import *
-from mantid.simpleapi import *
-
-
-class InelasticIndirectReduction(DataProcessorAlgorithm):
-
-    _out_ws_group = None
-    _data_files = None
-    _instrument = None
-    _analyser = None
-    _reflection = None
-    _param_file = None
-    _detector_range = None
-    _background_range = None
-    _calib_ws_name = None
-    _detailed_balance = None
-    _rebin_string = None
-    _scale_factor = None
-    _sum_files = None
-    _map_file = None
-    _save_formats = None
-    _plot_type = None
-    _use_calib_ws = None
-    _use_detailed_balance = None
-    _use_scale_factor = None
-    _plot_ws = None
-
-    def category(self):
-        return 'Workflow\\Inelastic;PythonAlgorithms;Inelastic'
-
-
-    def summary(self):
-        return 'Runs a reduction for an inelastic indirect geometry instrument.'
-
-
-    def PyInit(self):
-        self.declareProperty(StringArrayProperty(name='InputFiles'),
-                             doc='Comma separated list of input files')
-
-        self.declareProperty(WorkspaceGroupProperty('OutputWorkspace', '',\
-                             direction=Direction.Output),
-                             doc='Workspace group for the resulting workspaces')
-
-        self.declareProperty(name='SumFiles', defaultValue=False, doc='Toggle input file summing or sequential processing')
-        self.declareProperty(name='LoadLogs', defaultValue=False, doc='Load sample logs from input files')
-
-        self.declareProperty(name='Instrument', defaultValue='', doc='Instrument used during run',
-                             validator=StringListValidator(['IRIS', 'OSIRIS', 'TOSCA', 'TFXA', 'BASIS', 'VISION']))
-        self.declareProperty(name='Analyser', defaultValue='', doc='Analyser used during run',
-                             validator=StringListValidator(['graphite', 'mica', 'fmica', 'silicon']))
-        self.declareProperty(name='Reflection', defaultValue='', doc='Reflection used during run',
-                             validator=StringListValidator(['002', '004', '006', '111']))
-
-        self.declareProperty(WorkspaceProperty('CalibrationWorkspace', '',\
-                             direction=Direction.Input, optional=PropertyMode.Optional), doc='Workspace contining calibration data')
-
-        self.declareProperty(IntArrayProperty(name='DetectorRange', values=[0, 1],\
-                             validator=IntArrayMandatoryValidator()),
-                             doc='Comma separated range of detectors to use')
-        self.declareProperty(FloatArrayProperty(name='BackgroundRange'),
-                             doc='')
-
-        self.declareProperty(name='RebinString', defaultValue='', doc='Rebin string parameters')
-        self.declareProperty(name='DetailedBalance', defaultValue=-1.0, doc='')
-        self.declareProperty(name='ScaleFactor', defaultValue=1.0, doc='')
-        self.declareProperty(name='Grouping', defaultValue='',
-                             doc='Method used to group spectra, can be either: Individual, All, a .map filename or a group workspace name')
-        self.declareProperty(name='Fold', defaultValue=False, doc='')
-        self.declareProperty(name='SaveCM1', defaultValue=False, doc='')
-        self.declareProperty(StringArrayProperty(name='SaveFormats'), doc='Comma separated list of save formats')
-
-        self.declareProperty(name='Plot', defaultValue='none', doc='Type of plot to output after reduction',
-                             validator=StringListValidator(['none', 'spectra', 'contour']))
-
-
-    def PyExec(self):
-        from mantid import config, logger
-        import inelastic_indirect_reducer
-
-        self._setup()
-
-        # Setup reducer
-        reducer = inelastic_indirect_reducer.IndirectReducer()
-
-        reducer.set_rename(True)
-
-        reducer.set_instrument_name(self._instrument)
-        reducer.set_parameter_file(self._param_file)
-        try:
-            reducer.set_output_path(config["defaultsave.directory"])
-        except RuntimeError:
-            pass # Use default
-
-        for data_file in self._data_files:
-            reducer.append_data_file(data_file)
-
-        reducer.set_sum_files(self._sum_files)
-
-        reducer.set_detector_range(int(self._detector_range[0]) - 1, int(self._detector_range[1]) - 1)
-
-        self._use_calib_ws = self._calib_ws_name != ''
-        if self._use_calib_ws:
-            logger.information('Using calibration workspace: %s' % self._calib_ws_name)
-            reducer.set_calibration_workspace(self._calib_ws_name)
-
-        if len(self._background_range) == 2:
-            logger.debug('Using background range: ' + str(self._background_range))
-            reducer.set_background(float(self._background_range[0]), float(self._background_range[1]))
-
-        # TODO: There should be a better way to do this
-        self._use_detailed_balance = self._detailed_balance != -1.0
-        if self._use_detailed_balance:
-            logger.debug('Using detailed balance: ' + str(self._detailed_balance))
-            reducer.set_detailed_balance(self._detailed_balance)
-
-        if self._rebin_string != '':
-            logger.debug('Using rebin string: ' + self._rebin_string)
-            reducer.set_rebin_string(self._rebin_string)
-
-        self._use_scale_factor = self._scale_factor != 1.0
-        if self._use_scale_factor:
-            logger.debug('Using scale factor: ' + str(self._scale_factor))
-            reducer.set_scale_factor(self._scale_factor)
-
-        if self._map_file != '':
-            logger.debug('Using mapping file: ' + str(self._map_file))
-            reducer.set_grouping_policy(self._map_file)
-
-        reducer.set_fold_multiple_frames(self.getProperty('Fold').value)
-        reducer.set_save_to_cm_1(self.getProperty('SaveCM1').value)
-        reducer.set_save_formats(self._save_formats)
-
-        # Do reduction and get result workspaces
-        reducer.reduce()
-        ws_list = reducer.get_result_workspaces()
-
-        self._plot_ws = ws_list[0]
-
-        if len(ws_list) < 1:
-            logger.error('Failed to complete reduction')
-            return
-
-        # Add sample logs to output workspace(s)
-        for workspace in ws_list:
-            self._add_ws_logs(workspace)
-
-        # Group output workspaces
-        GroupWorkspaces(InputWorkspaces=ws_list, OutputWorkspace=self._out_ws_group)
-        self.setProperty('OutputWorkspace', self._out_ws_group)
-
-        # Do plotting
-        if self._plot_type != 'none':
-            self._plot()
-
-
-    def validateInputs(self):
-        """
-        Validates algorithm properties.
-        """
-        issues = dict()
-
-        # Validate save format string
-        save_formats = self.getProperty('SaveFormats').value
-        valid_formats = ['nxs', 'spe', 'nxspe', 'ascii', 'aclimax', 'davegrp']
-        invalid_formats = list()
-        for save_format in save_formats:
-            if save_format not in valid_formats:
-                invalid_formats.append(save_format)
-        if len(invalid_formats) > 0:
-            issues['SaveFormats'] = 'The following save formats are not valid: ' + ','.join(invalid_formats)
-
-        return issues
-
-
-    def _setup(self):
-        """
-        Gets and algorithm properties.
-        """
-
-        # Get parameter values
-        self._out_ws_group = self.getPropertyValue('OutputWorkspace')
-        self._data_files = self.getProperty('InputFiles').value
-
-        self._instrument = self.getPropertyValue('Instrument')
-        self._analyser = self.getPropertyValue('Analyser')
-        self._reflection = self.getPropertyValue('Reflection')
-
-        self._param_file = config['instrumentDefinition.directory'] + self._instrument + '_' + self._analyser + '_' + self._reflection + '_Parameters.xml'
-
-        self._detector_range = self.getProperty('DetectorRange').value
-        self._background_range = self.getProperty('BackgroundRange').value
-
-        self._calib_ws_name = self.getPropertyValue('CalibrationWorkspace')
-
-        self._detailed_balance = self.getProperty('DetailedBalance').value
-        self._rebin_string = self.getPropertyValue('RebinString')
-        self._scale_factor = self.getProperty('ScaleFactor').value
-        self._sum_files = self.getProperty('SumFiles').value
-
-        self._map_file = self.getPropertyValue('Grouping')
-
-        self._save_formats = self.getProperty('SaveFormats').value
-        self._plot_type = self.getPropertyValue('Plot')
-
-
-    def _add_ws_logs(self, workspace_name):
-        """
-        Adds sample logs to a given output workspace.
-        """
-
-        AddSampleLog(Workspace=workspace_name, LogName='use_calib_wokspace', LogType='String', LogText=str(self._use_calib_ws))
-        if self._use_calib_ws:
-            AddSampleLog(Workspace=workspace_name, LogName='calib_workspace_name', LogType='String', LogText=str(self._calib_ws_name))
-
-        AddSampleLog(Workspace=workspace_name, LogName='use_detailed_balance', LogType='String', LogText=str(self._use_detailed_balance))
-        if self._use_detailed_balance:
-            AddSampleLog(Workspace=workspace_name, LogName='detailed_balance', LogType='Number', LogText=str(self._detailed_balance))
-
-        AddSampleLog(Workspace=workspace_name, LogName='use_scale_factor', LogType='String', LogText=str(self._use_scale_factor))
-        if self._use_scale_factor:
-            AddSampleLog(Workspace=workspace_name, LogName='scale_factor', LogType='Number', LogText=str(self._scale_factor))
-
-
-    def _plot(self):
-        """
-        Plots results.
-        """
-
-        if self._plot_type == 'spectra':
-            from mantidplot import plotSpectrum
-            num_spectra = mtd[self._plot_ws].getNumberHistograms()
-            try:
-                plotSpectrum(self._plot_ws, range(0, num_spectra))
-            except RuntimeError:
-                logger.notice('Spectrum plotting canceled by user')
-
-        if self._plot_type == 'contour':
-            from mantidplot import importMatrixWorkspace
-            plot_workspace = importMatrixWorkspace(self._plot_ws)
-            plot_workspace.plotGraph2D()
-
-
-# Register algorithm with Mantid
-AlgorithmFactory.subscribe(InelasticIndirectReduction)
diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
index 77b67b9edc8f9142c083ae3d3004f4ffe577537f..ad9fe2847ba1728ad63fe03af6a915570823620b 100644
--- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
+++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
@@ -24,9 +24,9 @@ set ( TEST_PY_FILES
   IndirectCylinderAbsorptionTest.py
   IndirectFlatPlateAbsorptionTest.py
   IndirectILLReductionTest.py
-  InelasticIndirectReductionTest.py
   IndirectTransmissionTest.py
   IndirectTransmissionMonitorTest.py
+  ISISIndirectEnergyTransferTest.py
   LoadDNSLegacyTest.py
   LoadFullprofFileTest.py
   LoadLiveDataTest.py
diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ISISIndirectEnergyTransferTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ISISIndirectEnergyTransferTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..04e4ef43c3a2a576e67062bcae5f426e4a1dbdbb
--- /dev/null
+++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/ISISIndirectEnergyTransferTest.py
@@ -0,0 +1,56 @@
+import unittest
+from mantid.simpleapi import *
+from mantid.api import *
+
+
+class ISISIndirectEnergyTransferTest(unittest.TestCase):
+
+    def test_basic_reduction_completes(self):
+        """
+        Sanity test to ensure the most basic reduction actually completes.
+        """
+
+        ws = ISISIndirectEnergyTransfer(InputFiles=['IRS26176.RAW'],
+                                        Instrument='IRIS',
+                                        Analyser='graphite',
+                                        Reflection='002',
+                                        SpectraRange=[3, 53])
+
+        self.assertTrue(isinstance(ws, WorkspaceGroup), 'Result workspace should be a workspace group.')
+        self.assertEqual(ws.getNames()[0], 'IRS26176_graphite002_red')
+
+
+    def test_instrument_validation_failure(self):
+        """
+        Tests that an invalid instrument configuration causes the validation to fail.
+        """
+
+        self.assertRaises(RuntimeError,
+                          ISISIndirectEnergyTransfer,
+                          OutputWorkspace='__ISISIndirectEnergyTransferTest_ws',
+                          InputFiles=['IRS26176.RAW'],
+                          Instrument='IRIS',
+                          Analyser='graphite',
+                          Reflection='006',
+                          SpectraRange=[3, 53])
+
+
+    def test_group_workspace_validation_failure(self):
+        """
+        Tests that validation fails when Workspace is selected as the GroupingMethod
+        but no workspace is provided.
+        """
+
+        self.assertRaises(RuntimeError,
+                          ISISIndirectEnergyTransfer,
+                          OutputWorkspace='__ISISIndirectEnergyTransferTest_ws',
+                          InputFiles=['IRS26176.RAW'],
+                          Instrument='IRIS',
+                          Analyser='graphite',
+                          Reflection='002',
+                          SpectraRange=[3, 53],
+                          GroupingMethod='Workspace')
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/InelasticIndirectReductionTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/InelasticIndirectReductionTest.py
deleted file mode 100644
index ef51954f33eb75801cbdd116de8c1f1f37c8e997..0000000000000000000000000000000000000000
--- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/InelasticIndirectReductionTest.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import unittest
-from mantid import mtd
-from mantid.simpleapi import InelasticIndirectReduction
-
-
-class InelasticIndirectReductionTest(unittest.TestCase):
-
-    def test_basic(self):
-        InelasticIndirectReduction(InputFiles='IRS26176.RAW',
-                                   OutputWorkspace='IndirectReductions',
-                                   Instrument='IRIS',
-                                   Analyser='graphite',
-                                   Reflection='002',
-                                   DetectorRange=[3, 53])
-
-        reduction_workspace = mtd['IndirectReductions'].getItem(0)
-        self.assertEquals(reduction_workspace.getName(), 'irs26176_graphite002_red')
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.h
index 167b3f9c1e28be3ba9e6b52e011af4fc15cdfb55..d164fa8aa6aae3a65e4c873d541e6d5527df0039 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.h
+++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.h
@@ -63,7 +63,7 @@ namespace CustomInterfaces
   private:
     Ui::ISISEnergyTransfer m_uiForm;
 
-    QString createMapFile(const QString& groupType); ///< create the mapping file with which to group results
+    QPair<QString, QString> createMapFile(const QString& groupType); ///< create the mapping file with which to group results
     std::vector<std::string> getSaveFormats(); ///< get a vector of save formats
 
   };
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui
index e53c1319081ead9934fe2ec4154761eff166696a..e74fc8a361fc8a66aa3c8ae0531bf4c1b9e8d002 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui
+++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>611</width>
-    <height>670</height>
+    <width>617</width>
+    <height>755</height>
    </rect>
   </property>
   <property name="minimumSize">
@@ -25,89 +25,67 @@
      <property name="title">
       <string>Input</string>
      </property>
-     <layout class="QVBoxLayout" name="verticalLayout">
-      <property name="spacing">
-       <number>0</number>
-      </property>
-      <item>
-       <layout class="QHBoxLayout" name="loInput">
-        <item>
-         <layout class="QVBoxLayout" name="loInputSources">
-          <item>
-           <widget class="MantidQt::MantidWidgets::MWRunFiles" name="dsRunFiles" native="true">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>41</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="label" stdset="0">
-             <string>Run Files</string>
-            </property>
-            <property name="multipleFiles" stdset="0">
-             <bool>true</bool>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="MantidQt::MantidWidgets::DataSelector" name="dsCalibrationFile" native="true">
-            <property name="enabled">
-             <bool>false</bool>
-            </property>
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="autoLoad" stdset="0">
-             <bool>true</bool>
-            </property>
-            <property name="showLoad" stdset="0">
-             <bool>false</bool>
-            </property>
-            <property name="workspaceSuffixes" stdset="0">
-             <string>_calib</string>
-            </property>
-            <property name="fileBrowserSuffixes" stdset="0">
-             <string>_calib.nxs</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </item>
-        <item>
-         <layout class="QVBoxLayout" name="loInputOptions">
-          <item>
-           <widget class="QCheckBox" name="ckSumFiles">
-            <property name="toolTip">
-             <string>Sum multiple files together.</string>
-            </property>
-            <property name="text">
-             <string>Sum Files</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="ckLoadLogs">
-            <property name="text">
-             <string>Load Logs</string>
-            </property>
-           </widget>
-          </item>
-          <item>
-           <widget class="QCheckBox" name="ckUseCalib">
-            <property name="toolTip">
-             <string>Use calibration file to adjust for detector efficiency.</string>
-            </property>
-            <property name="text">
-             <string>Use Calib File</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </item>
-       </layout>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="1">
+       <widget class="QCheckBox" name="ckSumFiles">
+        <property name="toolTip">
+         <string>Sum multiple files together.</string>
+        </property>
+        <property name="text">
+         <string>Sum Files</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="MantidQt::MantidWidgets::DataSelector" name="dsCalibrationFile" native="true">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="autoLoad" stdset="0">
+         <bool>true</bool>
+        </property>
+        <property name="showLoad" stdset="0">
+         <bool>false</bool>
+        </property>
+        <property name="workspaceSuffixes" stdset="0">
+         <string>_calib</string>
+        </property>
+        <property name="fileBrowserSuffixes" stdset="0">
+         <string>_calib.nxs</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QCheckBox" name="ckUseCalib">
+        <property name="toolTip">
+         <string>Use calibration file to adjust for detector efficiency.</string>
+        </property>
+        <property name="text">
+         <string>Use Calib File</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="MantidQt::MantidWidgets::MWRunFiles" name="dsRunFiles" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>41</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="label" stdset="0">
+         <string>Run Files</string>
+        </property>
+        <property name="multipleFiles" stdset="0">
+         <bool>true</bool>
+        </property>
+       </widget>
       </item>
      </layout>
     </widget>
@@ -256,9 +234,6 @@
       <property name="sizeConstraint">
        <enum>QLayout::SetDefaultConstraint</enum>
       </property>
-      <property name="spacing">
-       <number>0</number>
-      </property>
       <item row="0" column="0">
        <widget class="QCheckBox" name="ckDetailedBalance">
         <property name="text">
@@ -336,9 +311,6 @@
       <string>Conversion to Energy Transfer</string>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout">
-      <property name="spacing">
-       <number>6</number>
-      </property>
       <item>
        <widget class="QLabel" name="lbEFixed">
         <property name="text">
@@ -422,12 +394,6 @@
       <string>Rebin (meV)</string>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout_14">
-      <property name="spacing">
-       <number>6</number>
-      </property>
-      <property name="margin">
-       <number>6</number>
-      </property>
       <item>
        <layout class="QHBoxLayout" name="loRebin">
         <property name="spacing">
@@ -822,18 +788,6 @@
       <string>Output</string>
      </property>
      <layout class="QGridLayout" name="gridLayout_8">
-      <property name="leftMargin">
-       <number>6</number>
-      </property>
-      <property name="topMargin">
-       <number>6</number>
-      </property>
-      <property name="rightMargin">
-       <number>6</number>
-      </property>
-      <property name="horizontalSpacing">
-       <number>0</number>
-      </property>
       <item row="1" column="0">
        <layout class="QHBoxLayout" name="loSaveFormats">
         <item>
@@ -1126,25 +1080,25 @@
    </hints>
   </connection>
   <connection>
-   <sender>ckUseCalib</sender>
+   <sender>ckBackgroundRemoval</sender>
    <signal>toggled(bool)</signal>
-   <receiver>dsCalibrationFile</receiver>
+   <receiver>spBackgroundStart</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>441</x>
-     <y>98</y>
+     <x>96</x>
+     <y>237</y>
     </hint>
     <hint type="destinationlabel">
-     <x>159</x>
-     <y>86</y>
+     <x>476</x>
+     <y>238</y>
     </hint>
    </hints>
   </connection>
   <connection>
    <sender>ckBackgroundRemoval</sender>
    <signal>toggled(bool)</signal>
-   <receiver>spBackgroundStart</receiver>
+   <receiver>spBackgroundEnd</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
@@ -1152,24 +1106,24 @@
      <y>237</y>
     </hint>
     <hint type="destinationlabel">
-     <x>476</x>
+     <x>554</x>
      <y>238</y>
     </hint>
    </hints>
   </connection>
   <connection>
-   <sender>ckBackgroundRemoval</sender>
+   <sender>ckUseCalib</sender>
    <signal>toggled(bool)</signal>
-   <receiver>spBackgroundEnd</receiver>
+   <receiver>dsCalibrationFile</receiver>
    <slot>setEnabled(bool)</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>96</x>
-     <y>237</y>
+     <x>454</x>
+     <y>86</y>
     </hint>
     <hint type="destinationlabel">
-     <x>554</x>
-     <y>238</y>
+     <x>162</x>
+     <y>86</y>
     </hint>
    </hints>
   </connection>
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp
index 11a8d425db0a29e383bbc6099e4cde2766e74a59..47f571cee9dcce3ca2b2355e12caf263d0feb348 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp
+++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISCalibration.cpp
@@ -430,14 +430,14 @@ namespace CustomInterfaces
     QString detRange = QString::number(m_dblManager->value(m_properties["ResSpecMin"])) + ","
                      + QString::number(m_dblManager->value(m_properties["ResSpecMax"]));
 
-    IAlgorithm_sptr reductionAlg = AlgorithmManager::Instance().create("InelasticIndirectReduction");
+    IAlgorithm_sptr reductionAlg = AlgorithmManager::Instance().create("ISISIndirectEnergyTransfer");
     reductionAlg->initialize();
     reductionAlg->setProperty("Instrument", getInstrumentConfiguration()->getInstrumentName().toStdString());
     reductionAlg->setProperty("Analyser", getInstrumentConfiguration()->getAnalyserName().toStdString());
     reductionAlg->setProperty("Reflection", getInstrumentConfiguration()->getReflectionName().toStdString());
     reductionAlg->setProperty("InputFiles", files.toStdString());
     reductionAlg->setProperty("OutputWorkspace", "__IndirectCalibration_reduction");
-    reductionAlg->setProperty("DetectorRange", detRange.toStdString());
+    reductionAlg->setProperty("SpectraRange", detRange.toStdString());
     reductionAlg->execute();
 
     if(!reductionAlg->isExecuted())
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp
index ae5c94bac4af7dc65a9fd3ccd8dda22f84ce187f..85286e02d02650a17b921f280d22bc2a971e8d12 100644
--- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp
+++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ISISEnergyTransfer.cpp
@@ -1,13 +1,13 @@
 #include "MantidQtCustomInterfaces/Indirect/ISISEnergyTransfer.h"
 
 #include "MantidGeometry/IDTypes.h"
-#include "MantidQtCustomInterfaces/Background.h"
 #include "MantidQtCustomInterfaces/UserInputValidator.h"
 
 #include <QFileInfo>
 #include <QInputDialog>
 
 using namespace Mantid::API;
+using MantidQt::API::BatchAlgorithmRunner;
 
 namespace MantidQt
 {
@@ -106,10 +106,9 @@ namespace CustomInterfaces
 
   void ISISEnergyTransfer::run()
   {
-    using MantidQt::API::BatchAlgorithmRunner;
-
-    IAlgorithm_sptr reductionAlg = AlgorithmManager::Instance().create("InelasticIndirectReduction", -1);
+    IAlgorithm_sptr reductionAlg = AlgorithmManager::Instance().create("ISISIndirectEnergyTransfer");
     reductionAlg->initialize();
+    BatchAlgorithmRunner::AlgorithmRuntimeProps reductionRuntimeProps;
 
     reductionAlg->setProperty("Instrument", getInstrumentConfiguration()->getInstrumentName().toStdString());
     reductionAlg->setProperty("Analyser", getInstrumentConfiguration()->getAnalyserName().toStdString());
@@ -119,7 +118,6 @@ namespace CustomInterfaces
     reductionAlg->setProperty("InputFiles", files.toStdString());
 
     reductionAlg->setProperty("SumFiles", m_uiForm.ckSumFiles->isChecked());
-    reductionAlg->setProperty("LoadLogs", m_uiForm.ckLoadLogs->isChecked());
 
     if(m_uiForm.ckUseCalib->isChecked())
     {
@@ -130,7 +128,7 @@ namespace CustomInterfaces
     std::vector<long> detectorRange;
     detectorRange.push_back(m_uiForm.spSpectraMin->value());
     detectorRange.push_back(m_uiForm.spSpectraMax->value());
-    reductionAlg->setProperty("DetectorRange", detectorRange);
+    reductionAlg->setProperty("SpectraRange", detectorRange);
 
     if(m_uiForm.ckBackgroundRemoval->isChecked())
     {
@@ -157,32 +155,23 @@ namespace CustomInterfaces
     if(m_uiForm.ckScaleMultiplier->isChecked())
       reductionAlg->setProperty("ScaleFactor", m_uiForm.spScaleMultiplier->value());
 
-    if(m_uiForm.cbGroupingOptions->currentText() != "Default")
-    {
-      QString grouping = createMapFile(m_uiForm.cbGroupingOptions->currentText());
-      reductionAlg->setProperty("Grouping", grouping.toStdString());
-    }
+    if(m_uiForm.ckCm1Units->isChecked())
+      reductionAlg->setProperty("UnitX", "DeltaE_inWavenumber");
 
-    reductionAlg->setProperty("Fold", m_uiForm.ckFold->isChecked());
-    reductionAlg->setProperty("SaveCM1", m_uiForm.ckCm1Units->isChecked());
-    reductionAlg->setProperty("SaveFormats", getSaveFormats());
+    QPair<QString, QString> grouping = createMapFile(m_uiForm.cbGroupingOptions->currentText());
+    reductionAlg->setProperty("GroupingMethod", grouping.first.toStdString());
 
-    reductionAlg->setProperty("OutputWorkspace", "IndirectEnergyTransfer_Workspaces");
+    if(grouping.first == "Workspace")
+      reductionRuntimeProps["GroupingWorkspace"] = grouping.second.toStdString();
+    else if(grouping.second == "File")
+      reductionAlg->setProperty("MapFile", grouping.second.toStdString());
 
-    // Plot Output options
-    switch(m_uiForm.cbPlotType->currentIndex())
-    {
-      case 0: // "None"
-        break;
-      case 1: // "Spectra"
-        reductionAlg->setProperty("Plot", "spectra");
-        break;
-      case 2: // "Contour"
-        reductionAlg->setProperty("Plot", "contour");
-        break;
-    }
+    reductionAlg->setProperty("FoldMultipleFrames", m_uiForm.ckFold->isChecked());
+    reductionAlg->setProperty("Plot", m_uiForm.cbPlotType->currentText().toStdString());
+    reductionAlg->setProperty("SaveFormats", getSaveFormats());
+    reductionAlg->setProperty("OutputWorkspace", "IndirectEnergyTransfer_Workspaces");
 
-    m_batchAlgoRunner->addAlgorithm(reductionAlg);
+    m_batchAlgoRunner->addAlgorithm(reductionAlg, reductionRuntimeProps);
 
     connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(algorithmComplete(bool)));
     disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(plotRawComplete(bool)));
@@ -320,7 +309,7 @@ namespace CustomInterfaces
    * @param groupType :: Type of grouping (All, Group, Indiviual)
    * @return path to mapping file, or an empty string if file could not be created.
    */
-  QString ISISEnergyTransfer::createMapFile(const QString& groupType)
+  QPair<QString, QString> ISISEnergyTransfer::createMapFile(const QString& groupType)
   {
     QString specRange = m_uiForm.spSpectraMin->text() + "," + m_uiForm.spSpectraMax->text();
 
@@ -328,10 +317,9 @@ namespace CustomInterfaces
     {
       QString groupFile = m_uiForm.dsMapFile->getFirstFilename();
       if(groupFile == "")
-      {
         emit showMessageBox("You must enter a path to the .map file.");
-      }
-      return groupFile;
+
+      return qMakePair(QString("File"), groupFile);
     }
     else if(groupType == "Groups")
     {
@@ -347,18 +335,22 @@ namespace CustomInterfaces
 
       m_batchAlgoRunner->addAlgorithm(groupingAlg);
 
-      return groupWS;
+      return qMakePair(QString("Workspace"), groupWS);
+    }
+    else if (groupType == "Default")
+    {
+      return qMakePair(QString("IPF"), QString());
     }
     else
     {
       // Catch All and Individual
-      return groupType;
+      return qMakePair(groupType, QString());
     }
   }
 
   /**
    * Converts the checkbox selection to a comma delimited list of save formats for the
-   * InelasticIndirectReduction algorithm.
+   * ISISIndirectEnergyTransfer algorithm.
    *
    * @return A vector of save formats
    */
diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
index 38db816a22fb361f39ccdbf52fb9d3fbd645cc87..f920400b261a3a95578cc714c5ba5f9358dc1537 100644
--- a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
+++ b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
@@ -10,7 +10,6 @@ from mantid.simpleapi import *
 from mantid.api import FileFinder
 
 # Import our workflows.
-from inelastic_indirect_reducer import IndirectReducer
 from IndirectDataAnalysis import furyfitSeq, furyfitMult, confitSeq, abscorFeeder
 
 '''
@@ -18,11 +17,10 @@ from IndirectDataAnalysis import furyfitSeq, furyfitMult, confitSeq, abscorFeede
 - OSIRIS/IRIS supported by all tabs / interfaces.
 - VESUVIO is not supported by any interface as of yet.
 
-For diagrams on the intended work flow of the IDA and Indirect parts of the
-C2E interface, please see:
+For diagrams on the intended work flow of the IDR and IDA interfaces see:
 
-- http://www.mantidproject.org/IDA
-- http://www.mantidproject.org/Indirect
+- Indirect_DataReduction.rst
+- Indirect_DataAnalysis.rst
 
 System test class hierarchy as shown below:
 
@@ -80,7 +78,8 @@ stresstesting.MantidStressTest
 
 
 class ISISIndirectInelasticBase(stresstesting.MantidStressTest):
-    '''A common base class for the ISISIndirectInelastic* base classes.
+    '''
+    A common base class for the ISISIndirectInelastic* base classes.
     '''
 
     __metaclass__ = ABCMeta  # Mark as an abstract class
@@ -96,15 +95,18 @@ class ISISIndirectInelasticBase(stresstesting.MantidStressTest):
         raise NotImplementedError("Implement _run.")
 
     def validate_results_and_references(self):
+        num_ref_files = len(self.get_reference_files())
+        num_results = len(self.result_names)
+
         if type(self.get_reference_files()) != list:
             raise RuntimeError("The reference file(s) should be in a list")
         if type(self.result_names) != list:
             raise RuntimeError("The result workspace(s) should be in a list")
-        if len(self.get_reference_files()) !=\
-           len(self.result_names):
-            raise RuntimeError("The number of result workspaces does not match"
-                               " the number of reference files.")
-        if len(self.get_reference_files()) < 1:
+        if num_ref_files != num_results:
+            raise RuntimeError("The number of result workspaces (%d) does not match"
+                               " the number of reference files (%d)." % (
+                               num_ref_files, num_results))
+        if num_ref_files < 1 or num_results < 1:
             raise RuntimeError("There needs to be a least one result and "
                                "reference.")
 
@@ -147,8 +149,8 @@ class ISISIndirectInelasticBase(stresstesting.MantidStressTest):
         and returns the full path.'''
         return os.path.join(config['defaultsave.directory'], filename)
 
-
 #==============================================================================
+
 class ISISIndirectInelasticReduction(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic reduction tests
 
@@ -171,23 +173,20 @@ class ISISIndirectInelasticReduction(ISISIndirectInelasticBase):
         '''Defines the workflow for the test'''
         self.tolerance = 1e-7
 
-        reducer = IndirectReducer()
-        reducer.set_instrument_name(self.instr_name)
-        reducer.set_detector_range(self.detector_range[0],
-                                   self.detector_range[1])
-        reducer.set_sum_files(self.sum_files)
-        self.parameter_file = self.instr_name + '_graphite_002_Parameters.xml'
-        reducer.set_parameter_file(self.parameter_file)
-
-        for name in self.data_files:
-            reducer.append_data_file(name)
+        kwargs = {}
 
         if self.rebin_string is not None:
-            reducer.set_rebin_string(self.rebin_string)
+            kwargs['RebinString'] = self.rebin_string
 
-        # Do the reduction and rename the result.
-        reducer.reduce()
-        self.result_names = sorted(reducer.get_result_workspaces())
+        reductions = ISISIndirectEnergyTransfer(Instrument=self.instr_name,
+                                                Analyser='graphite',
+                                                Reflection='002',
+                                                InputFiles=self.data_files,
+                                                SumFiles=self.sum_files,
+                                                SpectraRange=self.detector_range,
+                                                **kwargs)
+
+        self.result_names = sorted(reductions.getNames())
 
     def _validate_properties(self):
         '''Check the object properties are in an expected state to continue'''
@@ -205,13 +204,12 @@ class ISISIndirectInelasticReduction(ISISIndirectInelasticBase):
 
 #------------------------- TOSCA tests ----------------------------------------
 
-
 class TOSCAReduction(ISISIndirectInelasticReduction):
 
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'TOSCA'
-        self.detector_range = [0, 139]
+        self.detector_range = [1, 140]
         self.data_files = ['TSC15352.raw']
         self.rebin_string = '-2.5,0.015,3,-0.005,1000'
 
@@ -223,8 +221,8 @@ class TOSCAMultiFileReduction(ISISIndirectInelasticReduction):
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'TOSCA'
-        self.detector_range = [0, 139]
-        self.data_files = ['TSC15352.raw', 'TSC15353.raw','TSC15354.raw']
+        self.detector_range = [1, 140]
+        self.data_files = ['TSC15352.raw', 'TSC15353.raw', 'TSC15354.raw']
         self.rebin_string = '-2.5,0.015,3,-0.005,1000'
 
     def get_reference_files(self):
@@ -237,7 +235,7 @@ class TOSCAMultiFileSummedReduction(ISISIndirectInelasticReduction):
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'TOSCA'
-        self.detector_range = [0, 139]
+        self.detector_range = [1, 140]
         self.data_files = ['TSC15352.raw', 'TSC15353.raw','TSC15354.raw']
         self.rebin_string = '-2.5,0.015,3,-0.005,1000'
         self.sum_files = True
@@ -245,16 +243,14 @@ class TOSCAMultiFileSummedReduction(ISISIndirectInelasticReduction):
     def get_reference_files(self):
         return ['II.TOSCAMultiFileSummedReduction.nxs']
 
-
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISReduction(ISISIndirectInelasticReduction):
 
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'OSIRIS'
-        self.detector_range = [962, 1003]
+        self.detector_range = [963, 1004]
         self.data_files = ['OSIRIS00106550.raw']
         self.rebin_string = None
 
@@ -266,7 +262,7 @@ class OSIRISMultiFileReduction(ISISIndirectInelasticReduction):
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'OSIRIS'
-        self.detector_range = [962, 1003]
+        self.detector_range = [963, 1004]
         self.data_files = ['OSIRIS00106550.raw',' OSIRIS00106551.raw']
         self.rebin_string = None
 
@@ -280,7 +276,7 @@ class OSIRISMultiFileSummedReduction(ISISIndirectInelasticReduction):
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'OSIRIS'
-        self.detector_range = [962, 1003]
+        self.detector_range = [963, 1004]
         self.data_files = ['OSIRIS00106550.raw', 'OSIRIS00106551.raw']
         self.rebin_string = None
         self.sum_files = True
@@ -295,7 +291,7 @@ class IRISReduction(ISISIndirectInelasticReduction):
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'IRIS'
-        self.detector_range = [2, 52]
+        self.detector_range = [3, 53]
         self.data_files = ['IRS21360.raw']
         self.rebin_string = None
 
@@ -308,7 +304,7 @@ class IRISMultiFileReduction(ISISIndirectInelasticReduction):
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'IRIS'
-        self.detector_range = [2, 52]
+        self.detector_range = [3, 53]
         self.data_files = ['IRS21360.raw', 'IRS53664.raw']
         self.rebin_string = None
 
@@ -321,7 +317,7 @@ class IRISMultiFileSummedReduction(ISISIndirectInelasticReduction):
     def __init__(self):
         ISISIndirectInelasticReduction.__init__(self)
         self.instr_name = 'IRIS'
-        self.detector_range = [2, 52]
+        self.detector_range = [3, 53]
         self.data_files = ['IRS21360.raw', 'IRS53664.raw']
         self.sum_files = True
         self.rebin_string = None
@@ -331,19 +327,30 @@ class IRISMultiFileSummedReduction(ISISIndirectInelasticReduction):
         #as they should be the same
         return ['II.IRISMultiFileSummedReduction.nxs']
 
-#--------------------- Generic Reduction tests -----------------------------
+#==============================================================================
 
 class ISISIndirectInelasticReductionOutput(stresstesting.MantidStressTest):
 
     def runTest(self):
-        reducer = self._setup_reducer()
-        reducer.reduce()
-        self.result_names = sorted(reducer.get_result_workspaces())
+        self.file_formats = ['nxs', 'spe', 'nxspe', 'ascii', 'aclimax']
+        self.file_extensions = ['.nxs', '.spe', '.nxspe', '.dat', '_aclimax.dat']
 
-    def validate(self):
-        self.assertEqual(len(self.result_names), 1)
-        self.result_name = self.result_names[0]
+        self.instr_name = 'TOSCA'
+        self.detector_range = [1, 140]
+        self.data_files = ['TSC15352.raw']
+        self.rebin_string = '-2.5,0.015,3,-0.005,1000'
+
+        reductions = ISISIndirectEnergyTransfer(Instrument=self.instr_name,
+                                                Analyser='graphite',
+                                                Reflection='002',
+                                                InputFiles=self.data_files,
+                                                SpectraRange=self.detector_range,
+                                                RebinString=self.rebin_string,
+                                                SaveFormats=self.file_formats)
+
+        self.result_name = reductions[0].getName()
 
+    def validate(self):
         self.output_file_names = self._get_file_names()
         self.assert_reduction_output_exists(self.output_file_names)
         self.assert_ascii_file_matches()
@@ -404,31 +411,6 @@ class ISISIndirectInelasticReductionOutput(stresstesting.MantidStressTest):
         actual_result = self._read_ascii_file(file_path, num_lines)
         self.assertTrue(actual_result == expected_result, msg + " (%s != %s)" % (actual_result, expected_result))
 
-    def _setup_reducer(self):
-        self.file_formats = ['nxs', 'spe', 'nxspe', 'ascii', 'aclimax']
-        self.file_extensions = ['.nxs', '.spe', '.nxspe', '.dat', '_aclimax.dat']
-        self.instr_name = 'TOSCA'
-        self.detector_range = [0, 139]
-        self.data_files = ['TSC15352.raw']
-        self.rebin_string = '-2.5,0.015,3,-0.005,1000'
-        self.parameter_file = self.instr_name + '_graphite_002_Parameters.xml'
-
-        reducer = IndirectReducer()
-        reducer.set_instrument_name(self.instr_name)
-        reducer.set_detector_range(self.detector_range[0],
-                                   self.detector_range[1])
-        reducer.set_sum_files(False)
-        reducer.set_parameter_file(self.parameter_file)
-        reducer.set_save_formats(self.file_formats)
-
-        for name in self.data_files:
-            reducer.append_data_file(name)
-
-        if self.rebin_string is not None:
-            reducer.set_rebin_string(self.rebin_string)
-
-        return reducer
-
     def _read_ascii_file(self, path, num_lines):
         with open(path,'rb') as file_handle:
             lines = [file_handle.readline().rstrip() for _ in xrange(num_lines)]
@@ -446,6 +428,7 @@ class ISISIndirectInelasticReductionOutput(stresstesting.MantidStressTest):
         return output_names
 
 #==============================================================================
+
 class ISISIndirectInelasticCalibration(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic calibration tests
 
@@ -488,7 +471,6 @@ class ISISIndirectInelasticCalibration(ISISIndirectInelasticBase):
 
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISCalibration(ISISIndirectInelasticCalibration):
 
     def __init__(self):
@@ -503,7 +485,6 @@ class OSIRISCalibration(ISISIndirectInelasticCalibration):
 
 #------------------------- IRIS tests ---------------------------------------
 
-
 class IRISCalibration(ISISIndirectInelasticCalibration):
 
     def __init__(self):
@@ -516,8 +497,8 @@ class IRISCalibration(ISISIndirectInelasticCalibration):
     def get_reference_files(self):
         return ["II.IRISCalibration.nxs"]
 
-
 #==============================================================================
+
 class ISISIndirectInelasticResolution(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic resolution tests
 
@@ -572,7 +553,6 @@ class ISISIndirectInelasticResolution(ISISIndirectInelasticBase):
 
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISResolution(ISISIndirectInelasticResolution):
 
     def __init__(self):
@@ -590,7 +570,6 @@ class OSIRISResolution(ISISIndirectInelasticResolution):
 
 #------------------------- IRIS tests -----------------------------------------
 
-
 class IRISResolution(ISISIndirectInelasticResolution):
 
     def __init__(self):
@@ -606,8 +585,8 @@ class IRISResolution(ISISIndirectInelasticResolution):
     def get_reference_files(self):
         return ["II.IRISResolution.nxs"]
 
-
 #==============================================================================
+
 class ISISIndirectInelasticDiagnostics(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic diagnostic tests
 
@@ -646,10 +625,8 @@ class ISISIndirectInelasticDiagnostics(ISISIndirectInelasticBase):
         if type(self.suffix) != str:
             raise RuntimeError("suffix property should be a string")
 
-
 #------------------------- IRIS tests -----------------------------------------
 
-
 class IRISDiagnostics(ISISIndirectInelasticDiagnostics):
 
     def __init__(self):
@@ -663,10 +640,8 @@ class IRISDiagnostics(ISISIndirectInelasticDiagnostics):
     def get_reference_files(self):
         return ["II.IRISDiagnostics.nxs"]
 
-
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISDiagnostics(ISISIndirectInelasticDiagnostics):
 
     def __init__(self):
@@ -680,8 +655,8 @@ class OSIRISDiagnostics(ISISIndirectInelasticDiagnostics):
     def get_reference_files(self):
         return ["II.OSIRISDiagnostics.nxs"]
 
-
 #==============================================================================
+
 class ISISIndirectInelasticMoments(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic TransformToIqt/TransformToIqtFit tests
 
@@ -715,8 +690,8 @@ class ISISIndirectInelasticMoments(ISISIndirectInelasticBase):
         if type(self.scale) != float:
             raise RuntimeError("Scale should be a float")
 
-
 #------------------------- OSIRIS tests ---------------------------------------
+
 class OSIRISMoments(ISISIndirectInelasticMoments):
 
     def __init__(self):
@@ -729,8 +704,8 @@ class OSIRISMoments(ISISIndirectInelasticMoments):
     def get_reference_files(self):
         return ['II.OSIRISMoments.nxs']
 
-
 #------------------------- IRIS tests -----------------------------------------
+
 class IRISMoments(ISISIndirectInelasticMoments):
 
     def __init__(self):
@@ -743,8 +718,8 @@ class IRISMoments(ISISIndirectInelasticMoments):
     def get_reference_files(self):
         return ['II.IRISMoments.nxs']
 
-
 #==============================================================================
+
 class ISISIndirectInelasticElwinAndMSDFit(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic Elwin/MSD Fit tests
 
@@ -810,7 +785,6 @@ class ISISIndirectInelasticElwinAndMSDFit(ISISIndirectInelasticBase):
 
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISElwinAndMSDFit(ISISIndirectInelasticElwinAndMSDFit):
 
     def __init__(self):
@@ -828,7 +802,6 @@ class OSIRISElwinAndMSDFit(ISISIndirectInelasticElwinAndMSDFit):
 
 #------------------------- IRIS tests -----------------------------------------
 
-
 class IRISElwinAndMSDFit(ISISIndirectInelasticElwinAndMSDFit):
 
     def __init__(self):
@@ -844,8 +817,8 @@ class IRISElwinAndMSDFit(ISISIndirectInelasticElwinAndMSDFit):
                 'II.IRISElwinEQ2.nxs',
                 'II.IRISMSDFit.nxs']
 
-
 #==============================================================================
+
 class ISISIndirectInelasticFuryAndFuryFit(ISISIndirectInelasticBase):
     '''
     A base class for the ISIS indirect inelastic Fury/FuryFit tests
@@ -917,7 +890,6 @@ class ISISIndirectInelasticFuryAndFuryFit(ISISIndirectInelasticBase):
 
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit):
 
     def __init__(self):
@@ -943,7 +915,6 @@ class OSIRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit):
 
 #------------------------- IRIS tests -----------------------------------------
 
-
 class IRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit):
 
     def __init__(self):
@@ -969,7 +940,6 @@ class IRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit):
 
 #==============================================================================
 
-
 class ISISIndirectInelasticFuryAndFuryFitMulti(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic Fury/FuryFit tests
 
@@ -1039,7 +1009,6 @@ class ISISIndirectInelasticFuryAndFuryFitMulti(ISISIndirectInelasticBase):
 
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti):
 
     def skipTests(self):
@@ -1068,7 +1037,6 @@ class OSIRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti):
 
 #------------------------- IRIS tests -----------------------------------------
 
-
 class IRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti):
 
     def __init__(self):
@@ -1094,7 +1062,6 @@ class IRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti):
 
 #==============================================================================
 
-
 class ISISIndirectInelasticConvFit(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic ConvFit tests
 
@@ -1149,7 +1116,6 @@ class ISISIndirectInelasticConvFit(ISISIndirectInelasticBase):
 
 #------------------------- OSIRIS tests ---------------------------------------
 
-
 class OSIRISConvFit(ISISIndirectInelasticConvFit):
 
     def __init__(self):
@@ -1172,8 +1138,8 @@ class OSIRISConvFit(ISISIndirectInelasticConvFit):
     def get_reference_files(self):
         return ['II.OSIRISConvFitSeq.nxs']
 
-
 #------------------------- IRIS tests -----------------------------------------
+
 class IRISConvFit(ISISIndirectInelasticConvFit):
 
     def __init__(self):
@@ -1199,7 +1165,6 @@ class IRISConvFit(ISISIndirectInelasticConvFit):
 
 #==============================================================================
 
-
 class ISISIndirectInelasticApplyCorrections(ISISIndirectInelasticBase):
     '''A base class for the ISIS indirect inelastic Apply Corrections tests
 
@@ -1282,7 +1247,6 @@ class IRISApplyCorrectionsWithCan(ISISIndirectInelasticApplyCorrections):
     def get_reference_files(self):
         return ['II.IRISApplyCorrectionsWithCan.nxs']
 
-
 class IRISApplyCorrectionsWithCorrectionsWS(ISISIndirectInelasticApplyCorrections):
     """ Test applying corrections with a corrections workspace """
 
@@ -1323,9 +1287,6 @@ class IRISApplyCorrectionsWithBoth(ISISIndirectInelasticApplyCorrections):
 # Transmission Monitor Test
 
 class ISISIndirectInelasticTransmissionMonitor(ISISIndirectInelasticBase):
-    '''
-    '''
-
     # Mark as an abstract class
     __metaclass__ = ABCMeta
 
@@ -1347,8 +1308,8 @@ class ISISIndirectInelasticTransmissionMonitor(ISISIndirectInelasticBase):
         if type(self.can) != str:
             raise RuntimeError("Can should be a string.")
 
-
 #------------------------- IRIS tests -----------------------------------------
+
 class IRISTransmissionMonitor(ISISIndirectInelasticTransmissionMonitor):
 
     def __init__(self):
diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/IndirectEnergyConversionTest.py b/Code/Mantid/Testing/SystemTests/tests/analysis/IndirectEnergyConversionTest.py
index b213a4662eae77cb5874619666aeb94c3e552642..b683bf46ee8c927ee7ddf8c6df63380d9c88ca77 100644
--- a/Code/Mantid/Testing/SystemTests/tests/analysis/IndirectEnergyConversionTest.py
+++ b/Code/Mantid/Testing/SystemTests/tests/analysis/IndirectEnergyConversionTest.py
@@ -12,16 +12,16 @@ class IndirectEnergyConversionTest(stresstesting.MantidStressTest):
         files = 'irs21360.raw'
         rebin_string = '-0.5,0.005,0.5'
 
-        InelasticIndirectReduction(InputFiles=files,
-                                   RebiNString=rebin_string,
-                                   DetectorRange=detector_range,
+        ISISIndirectEnergyTransfer(InputFiles=files,
+                                   RebinString=rebin_string,
+                                   SpectraRange=detector_range,
                                    Instrument=instrument,
                                    Analyser=analyser,
                                    Reflection=reflection,
-                                   OutputWorkspace='__IndirectEnergyCOnversionTest_out_group')
+                                   OutputWorkspace='__IndirectEnergyConversionTest_out_group')
 
 
     def validate(self):
         self.disableChecking.append('Instrument')
         self.disableChecking.append('SpectraMap')
-        return 'irs21360_graphite002_red', 'IndirectEnergyConversionTest.nxs'
+        return 'IRS21360_graphite002_red', 'IndirectEnergyConversionTest.nxs'
diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/reference/II.TOSCAMultiFileReduction2.nxs.md5 b/Code/Mantid/Testing/SystemTests/tests/analysis/reference/II.TOSCAMultiFileReduction2.nxs.md5
index e1bc4905088eab0399d2e77978e0d0e8fd44da2b..44c6c182cc2ce4dad9e05be1deefd9a15c64eccb 100644
--- a/Code/Mantid/Testing/SystemTests/tests/analysis/reference/II.TOSCAMultiFileReduction2.nxs.md5
+++ b/Code/Mantid/Testing/SystemTests/tests/analysis/reference/II.TOSCAMultiFileReduction2.nxs.md5
@@ -1 +1 @@
-ed6aea923444b6d1c6e5dfd810cb329f
\ No newline at end of file
+b7c86ee67f2e306c7fffd85403cba548
diff --git a/Code/Mantid/docs/source/algorithms/ISISIndirectEnergyTransfer-v1.rst b/Code/Mantid/docs/source/algorithms/ISISIndirectEnergyTransfer-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..5f295ba1884841e02812a51158544e47785d683c
--- /dev/null
+++ b/Code/Mantid/docs/source/algorithms/ISISIndirectEnergyTransfer-v1.rst
@@ -0,0 +1,42 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+Performs a reduction from raw time of flight to energy transfer for an inelastic
+indirect geometry instrument at ISIS.
+
+Usage
+-----
+
+.. include:: ../usagedata-note.txt
+
+**Example - IRIS energy conversion**
+
+.. testcode:: ExIRISReduction
+
+   ISISIndirectEnergyTransfer(InputFiles='IRS21360.raw',
+                              OutputWorkspace='IndirectReductions',
+                              Instrument='IRIS',
+                              Analyser='graphite',
+                              Reflection='002',
+                              SpectraRange=[3, 53])
+
+   reduction_workspace_names = mtd['IndirectReductions'].getNames()
+
+   for workspace_name in reduction_workspace_names:
+      print workspace_name
+
+Output:
+
+.. testoutput:: ExIRISReduction
+
+   IRS21360_graphite002_red
+
+.. categories::
diff --git a/Code/Mantid/docs/source/algorithms/InelasticIndirectReduction-v1.rst b/Code/Mantid/docs/source/algorithms/InelasticIndirectReduction-v1.rst
deleted file mode 100644
index f5290faa11a9e24551c43df04819679e35995818..0000000000000000000000000000000000000000
--- a/Code/Mantid/docs/source/algorithms/InelasticIndirectReduction-v1.rst
+++ /dev/null
@@ -1,42 +0,0 @@
-.. algorithm::
-
-.. summary::
-
-.. alias::
-
-.. properties::
-
-Description
------------
-
-Performs a reduction for an inelastic indirect geometry instrument.
-
-Usage
------
-
-.. include:: ../usagedata-note.txt
-
-**Example - IRIS energy conversion:**
-
-.. testcode:: ExIRISReduction
-
-   InelasticIndirectReduction(InputFiles='IRS21360.raw',
-      OutputWorkspace='IndirectReductions',
-      Instrument='IRIS',
-      Analyser='graphite',
-      Reflection='002',
-      DetectorRange=[3, 53],
-      SaveFormats=['nxs'])
-
-   reduction_workspace_names = mtd['IndirectReductions'].getNames()
-
-   for workspace_name in reduction_workspace_names:
-      print workspace_name
-
-Output:
-
-.. testoutput:: ExIRISReduction
-
-   irs21360_graphite002_red
-
-.. categories::