diff --git a/Framework/PythonInterface/plugins/algorithms/MRInspectData.py b/Framework/PythonInterface/plugins/algorithms/MRInspectData.py
index 21a16d26cec2fdf4152e1181417a150cdb940313..37e09844f44a50efd55dec4e4467e4c0d68cb611 100644
--- a/Framework/PythonInterface/plugins/algorithms/MRInspectData.py
+++ b/Framework/PythonInterface/plugins/algorithms/MRInspectData.py
@@ -7,7 +7,11 @@ import mantid.simpleapi
 import math
 import copy
 import numpy as np
-from scipy.optimize import curve_fit
+import scipy.optimize as opt
+
+DEAD_PIXELS = 10
+NX_PIXELS = 304
+NY_PIXELS = 256
 
 
 class MRInspectData(PythonAlgorithm):
@@ -34,10 +38,8 @@ class MRInspectData(PythonAlgorithm):
                              doc="If true, use the 2nd ROI in the meta-data for the background")
         self.declareProperty("UseTightBck", False,
                              doc="If true, use the area on each side of the peak to compute the background")
-        self.declareProperty("BckWidth", 3,
+        self.declareProperty("BckWidth", 10,
                              doc="If UseTightBck is true, width of the background on each side of the peak")
-        self.declareProperty("HuberXCut", 0.0,
-                             doc="Provide a Huber X value above which a run will be considered a direct beam")
 
         self.declareProperty("ForcePeakROI", False,
                              doc="If true, use the PeakROI property as the ROI")
@@ -66,7 +68,6 @@ class MRInspectData(PythonAlgorithm):
                              use_roi_bck=self.getProperty("UseROIBck").value,
                              use_tight_bck=self.getProperty("UseTightBck").value,
                              bck_offset=self.getProperty("BckWidth").value,
-                             huber_x_cut=self.getProperty("HuberXCut").value,
                              force_peak_roi=self.getProperty("ForcePeakROI").value,
                              peak_roi=self.getProperty("PeakROI").value,
                              force_low_res_roi=self.getProperty("ForceLowResPeakROI").value,
@@ -139,15 +140,11 @@ class DataInfo(object):
     """
         Class to hold the relevant information from a run (scattering or direct beam).
     """
-    n_x_pixel = 304
-    n_y_pixel = 256
     peak_range_offset = 0
     tolerance = 0.02
-    huber_x_cut = 4.95
 
     def __init__(self, ws, cross_section='', use_roi=True, update_peak_range=False, use_roi_bck=False,
-                 use_tight_bck=False, bck_offset=3, huber_x_cut=4.95,
-                 force_peak_roi=False, peak_roi=[0,0],
+                 use_tight_bck=False, bck_offset=3, force_peak_roi=False, peak_roi=[0,0],
                  force_low_res_roi=False, low_res_roi=[0,0],
                  force_bck_roi=False, bck_roi=[0,0], event_threshold=10000):
         self.cross_section = cross_section
@@ -158,7 +155,6 @@ class DataInfo(object):
         self.peak_range = [0,0]
         self.low_res_range = [0,0]
         self.background = [0,0]
-        self.huber_x_cut = huber_x_cut
         self.n_events_cutoff = event_threshold
 
         # ROI information
@@ -344,79 +340,15 @@ class DataInfo(object):
             logger.notice("Forcing background ROI: %s" % self.forced_bck_roi)
             self.roi_background = self.forced_bck_roi
 
-    def determine_peak_range(self, ws, specular=True, max_pixel=304):
-        """
-            Find the reflectivity peak
-            :param workspace ws: workspace to work with
-            :param bool specular: if True, we are looking for a specular peak
-            :param int max_pixel: max pixel above which to exclude peaks
-        """
-        ws_summed = mantid.simpleapi.RefRoi(InputWorkspace=ws, IntegrateY=specular,
-                                            NXPixel=self.n_x_pixel, NYPixel=self.n_y_pixel,
-                                            ConvertToQ=False,
-                                            OutputWorkspace="ws_summed")
-
-        integrated = mantid.simpleapi.Integration(ws_summed)
-        integrated = mantid.simpleapi.Transpose(integrated)
-
-        x_values = integrated.readX(0)
-        y_values = integrated.readY(0)
-        e_values = integrated.readE(0)
-        ws_short = mantid.simpleapi.CreateWorkspace(DataX=x_values[self.peak_range_offset:max_pixel],
-                                                    DataY=y_values[self.peak_range_offset:max_pixel],
-                                                    DataE=e_values[self.peak_range_offset:max_pixel])
-        try:
-            specular_peak, low_res, _ = mantid.simpleapi.LRPeakSelection(InputWorkspace=ws_short)
-        except:
-            logger.notice("Peak finding error [specular=%s]: %s" % (specular, sys.exc_info()[1]))
-            return integrated, [0,0], [0,0]
-        if specular:
-            peak = [specular_peak[0]+self.peak_range_offset, specular_peak[1]+self.peak_range_offset]
-        else:
-            # The low-resolution range finder tends to be a bit tight.
-            # Broaden it by a third.
-            #TODO: Fix the range finder algorithm
-            broadening = (low_res[1]-low_res[0])/3.0
-            peak = [low_res[0]+self.peak_range_offset-broadening,
-                    low_res[1]+self.peak_range_offset+broadening]
-
-        mantid.simpleapi.DeleteWorkspace(ws_short)
-        mantid.simpleapi.DeleteWorkspace(ws_summed)
-
-        return integrated, peak, [low_res[0]+self.peak_range_offset, low_res[1]+self.peak_range_offset]
-
-    @classmethod
-    def fit_peak(cls, signal_x, signal_y, peak):
-        """
-            Fit a Gaussian peak to a curve
-            :param array signal_x: list of x values
-            :param array signal_y: list of y values
-            :param array peak: initial guess for the peak (one-sigma min and max)
-        """
-        def gauss(x, *p):
-            A, mu, sigma, bck = p
-            if A < 0 or sigma < 5:
-                return -np.inf
-            return A*np.exp(-(x-mu)**2/(2.*sigma**2)) + bck
-
-        p0 = [np.max(signal_y), (peak[1]+peak[0])/2.0, (peak[1]-peak[0])/2.0, 0.0]
-        err_y = np.sqrt(np.fabs(signal_y))
-        # Using bounds would be great but only available with scipy>=0.17. bounds=(0, np.inf)
-        coeff, _ = curve_fit(gauss, signal_x, signal_y, sigma=err_y, p0=p0)
-        peak_position = coeff[1]
-        peak_width = math.fabs(3.0*coeff[2])
-        return peak_position, peak_width
-
     def check_direct_beam(self, ws, peak_position=None):
         """
             Determine whether this data is a direct beam
             :param workspace ws: Workspace to inspect
             :param float peak_position: reflectivity peak position
         """
-        huber_x = ws.getRun().getProperty("HuberX").getStatistics().mean
-        sangle = ws.getRun().getProperty("SANGLE").getStatistics().mean
-        self.theta_d = 180.0 / math.pi * mantid.simpleapi.MRGetTheta(ws, SpecularPixel=peak_position)
-        return not ((self.theta_d > self.tolerance or sangle > self.tolerance) and huber_x < self.huber_x_cut)
+        self.theta_d = 180.0 / math.pi * mantid.simpleapi.MRGetTheta(ws, SpecularPixel=peak_position,
+                                                                     UseSANGLE=False)
+        return not self.theta_d > self.tolerance
 
     def determine_data_type(self, ws):
         """
@@ -431,18 +363,15 @@ class DataInfo(object):
             return
 
         # Find reflectivity peak and low resolution ranges
-        # Those will be our defaults
-        integrated, peak, broad_range = self.determine_peak_range(ws, specular=True)
+        peak, low_res = fit_2d_peak(ws)
+        if self.use_tight_bck:
+            bck_range = [int(max(0.0, peak[0]-self.bck_offset)), int(min(NX_PIXELS, peak[1]+self.bck_offset))]
+        else:
+            bck_range = [int(max(0.0, peak[0]-2*self.bck_offset)), int(max(0.0, peak[0]-self.bck_offset))]
         self.found_peak = copy.copy(peak)
+        self.found_low_res = copy.copy(low_res)
         logger.notice("Run %s [%s]: Peak found %s" % (self.run_number, self.cross_section, peak))
-        signal_y = integrated.readY(0)
-        mantid.simpleapi.DeleteWorkspace(integrated)
-        signal_x = range(len(signal_y))
-
-        _, low_res, _ = self.determine_peak_range(ws, specular=False)
         logger.notice("Run %s [%s]: Low-res found %s" %(self.run_number, self.cross_section, str(low_res)))
-        self.found_low_res = low_res
-        bck_range = None
 
         # Process the ROI information
         try:
@@ -453,91 +382,34 @@ class DataInfo(object):
         # Keep track of whether we actually used the ROI
         self.use_roi_actual = False
 
-        if self.use_roi and not self.roi_peak == [0,0]:
+        # If we were asked to use the ROI but no peak is in it, use the peak we found
+        # If we were asked to use the ROI and there's a peak in it, use the ROI
+        if self.use_roi and not self.update_peak_range and not self.roi_peak == [0,0]:
+            logger.notice("Using ROI peak range: [%s %s]" % (self.roi_peak[0], self.roi_peak[1]))
+            self.use_roi_actual = True
             peak = copy.copy(self.roi_peak)
             if not self.roi_low_res == [0,0]:
                 low_res = copy.copy(self.roi_low_res)
             if not self.roi_background == [0,0]:
                 bck_range = copy.copy(self.roi_background)
-            logger.notice("Using ROI peak range: [%s %s]" % (peak[0], peak[1]))
-            self.use_roi_actual = True
-
-        # Determine reflectivity peak position (center)
-        # Crop three sigmas around the peak before fitting
-        _width = int(peak[1]-peak[0])
-        signal_y_crop = signal_y[peak[1]-_width:peak[1]+1+_width]
-        signal_x_crop = signal_x[peak[0]-_width:peak[1]+1+_width]
-
-        # Calculate a reasonable peak position
-        #peak_mean = np.average(signal_x_crop, weights=signal_y_crop)
-
-        peak_position = (peak[1]+peak[0])/2.0
-        peak_width = (peak[1]-peak[0])/2.0
-        try:
-            # Try to find the peak position within the peak range we found
-            peak_position, peak_width = self.fit_peak(signal_x_crop, signal_y_crop, peak)
-            # If we are more than two sigmas away from the middle of the range,
-            # there's clearly a problem.
-            if np.abs(peak_position - (peak[1]+peak[0])/2.0)  > np.abs(peak[1]-peak[0]):
-                logger.notice("Found peak position outside of given range [x=%s], switching to full detector" % peak_position)
-                peak_position = (peak[1]+peak[0])/2.0
-                peak_width = (peak[1]-peak[0])/2.0
-                raise RuntimeError("Bad peak position")
-        except:
-            # If we can't find a peak, try fitting over the full detector.
-            # If we do find a peak, then update the ranges rather than using
-            # what we currently have (which is probably given by the ROI).
-            logger.notice("Run %s [%s]: Could not fit a peak in the supplied peak range" %
-                          (self.run_number, self.cross_section))
-            logger.notice(str(sys.exc_info()[1]))
-            try:
-                # Define a good default that is wide enough for the fit to work
-                default_width = (self.found_peak[1]-self.found_peak[0])/2.0
-                default_width = max(default_width, 10.0)
-                default_center = (self.found_peak[1]+self.found_peak[0])/2.0
-                default_peak = [default_center-default_width, default_center+default_width]
-                logger.notice("Run %s [%s]: Broad data region %s" % (self.run_number, self.cross_section, broad_range))
-                x_min = broad_range[0]+10
-                x_max = broad_range[1]-10
-                peak_position, peak_width = self.fit_peak(signal_x[x_min:x_max], signal_y[x_min:x_max], default_peak)
-                peak = [math.floor(peak_position-peak_width), math.floor(peak_position+peak_width)]
-                #low_res = [5, self.n_x_pixel-5]
-                low_res = self.found_low_res
-                self.use_roi_actual = False
-                logger.notice("Run %s [%s]: Peak not in supplied range! Found peak: %s low: %s" %
-                              (self.run_number, self.cross_section, peak, low_res))
-                logger.notice("Run %s [%s]: Peak position: %s  Peak width: %s" %
-                              (self.run_number, self.cross_section, peak_position, peak_width))
-            except:
-                logger.notice(str(sys.exc_info()[1]))
-                logger.notice("Run %s [%s]: Gaussian fit failed to determine peak position" %
-                              (self.run_number, self.cross_section))
-
-        # Update the specular peak range if needed
-        if self.update_peak_range:
-            peak[0] = math.floor(peak_position-peak_width)
-            peak[1] = math.ceil(peak_position+peak_width)
-            logger.notice("Updating peak range to: [%s %s]" % (peak[0], peak[1]))
-            self.use_roi_actual = False
+        elif self.use_roi and self.update_peak_range and not self.roi_peak == [0,0]:
+            logger.notice("Using fit peak range: [%s %s]" % (peak[0], peak[1]))
+            if not self.roi_low_res == [0,0]:
+                low_res = copy.copy(self.roi_low_res)
+            if not self.roi_background == [0,0]:
+                bck_range = copy.copy(self.roi_background)
 
         # Store the information we found
-        self.peak_position = peak_position
-        self.peak_range = [int(max(0, peak[0])), int(min(peak[1], self.n_x_pixel))]
-        self.low_res_range = [int(max(0, low_res[0])), int(min(low_res[1], self.n_y_pixel))]
-
-        if not self.use_roi_bck or bck_range is None:
-            if self.use_tight_bck:
-                self.background = [self.peak_range[0]-self.bck_offset, self.peak_range[1]+self.bck_offset]
-            else:
-                self.background = [4, self.peak_range[0]-30]
-        else:
-            self.background = [int(bck_range[0]), int(bck_range[1])]
+        self.peak_position = (peak[1]+peak[0])/2.0
+        self.peak_range = [int(max(0, peak[0])), int(min(peak[1], NX_PIXELS))]
+        self.low_res_range = [int(max(0, low_res[0])), int(min(low_res[1], NY_PIXELS))]
+        self.background = [int(max(0, bck_range[0])), int(min(bck_range[1], NY_PIXELS))]
 
         # Computed scattering angle
-        self.calculated_scattering_angle = 180.0 / math.pi * mantid.simpleapi.MRGetTheta(ws, SpecularPixel=peak_position)
+        self.calculated_scattering_angle = 180.0 / math.pi * mantid.simpleapi.MRGetTheta(ws, SpecularPixel=self.peak_position)
 
         # Determine whether we have a direct beam
-        self.is_direct_beam = self.check_direct_beam(ws, peak_position)
+        self.is_direct_beam = self.check_direct_beam(ws, self.peak_position)
 
         # Convenient data type
         self.data_type = 0 if self.is_direct_beam else 1
@@ -546,5 +418,173 @@ class DataInfo(object):
         self.log()
 
 
+def fit_2d_peak(workspace):
+    """
+        Fit a 2D Gaussian peak
+        :param workspace: workspace to work with
+    """
+    n_x = int(workspace.getInstrument().getNumberParameter("number-of-x-pixels")[0])
+    n_y = int(workspace.getInstrument().getNumberParameter("number-of-y-pixels")[0])
+
+    # Prepare data to fit
+    _integrated = mantid.simpleapi.Integration(InputWorkspace=workspace)
+    signal = _integrated.extractY()
+    z=np.reshape(signal, (n_x, n_y))
+    x = np.arange(0, n_x)
+    y = np.arange(0, n_y)
+    _x, _y = np.meshgrid(x, y)
+    _x = _x.T
+    _y = _y.T
+
+    code = coord_to_code(_x, _y).ravel()
+    data_to_fit = z.ravel()
+    err_y = np.sqrt(np.fabs(data_to_fit))
+    err_y[err_y<1] = 1
+
+    # Use the highest data point as a starting point for a simple Gaussian fit
+    x_dist = np.sum(z, 1)
+    y_dist = np.sum(z, 0)
+    center_x = np.argmax(x_dist)
+    center_y = np.argmax(y_dist)
+
+    # Gaussian fit
+    p0 = [np.max(z), center_x, 5, center_y, 50, 0]
+    try:
+        gauss_coef, _ = opt.curve_fit(gauss_simple, code, data_to_fit, p0=p0, sigma=err_y)
+    except:
+        logger.notice("Could not fit simple Gaussian")
+        gauss_coef = p0
+
+    # Keep track of the result
+    th = gauss_simple(code, *gauss_coef)
+    th = np.reshape(th, (n_x, n_y))
+    _chi2 = chi2(th, z)
+    guess_x = gauss_coef[1]
+    guess_wx = 2.0 * gauss_coef[2]
+    guess_y = gauss_coef[3]
+    guess_wy = 2.0 * gauss_coef[4]
+    guess_chi2 = _chi2
+
+    # Fit a polynomial background, as a starting point to fitting signal + background
+    try:
+        step_coef, _ = opt.curve_fit(poly_bck, code, data_to_fit, p0=[0, 0, 0, center_x, 0], sigma=err_y)
+    except:
+        logger.notice("Could not fit polynomial background")
+        step_coef = [0, 0, 0, center_x, 0]
+    th = poly_bck(code, *step_coef)
+    th = np.reshape(th, (n_x, n_y))
+
+    # Now fit a Gaussian + background
+    # A, mu_x, sigma_x, mu_y, sigma_y, poly_a, poly_b, poly_c, center, background
+    coef = [np.max(z), center_x, 5, center_y, 50,
+            step_coef[0], step_coef[1], step_coef[2], step_coef[3], step_coef[4]]
+    try:
+        coef, _ = opt.curve_fit(poly_bck_signal, code, data_to_fit, p0=coef, sigma=err_y)
+    except:
+        logger.notice("Could not fit Gaussian + polynomial")
+    th = poly_bck_signal(code, *coef)
+    th = np.reshape(th, (n_x, n_y))
+    _chi2 = chi2(th, z)
+    if _chi2 < guess_chi2:
+        guess_x = coef[1]
+        guess_wx = 2.0 * coef[2]
+        guess_y = coef[3]
+        guess_wy = 2.0 * coef[4]
+        guess_chi2 = _chi2
+
+    # Package the best results
+    x_min = max(0, int(guess_x-np.fabs(guess_wx)))
+    x_max = min(n_x-1, int(guess_x+np.fabs(guess_wx)))
+    y_min = max(0, int(guess_y-np.fabs(guess_wy)))
+    y_max = min(n_y-1, int(guess_y+np.fabs(guess_wy)))
+
+    return [x_min, x_max], [y_min, y_max]
+
+
+def coord_to_code(x, y):
+    """ Utility function to encode pixel coordinates so we can unravel our distribution in a 1D array """
+    return 1000 * x + y
+
+
+def code_to_coord(c):
+    """ Utility function to decode encoded coordinates """
+    i_x = c / 1000
+    i_y = c % 1000
+    return i_x, i_y
+
+
+def poly_bck(value, *p):
+    """
+        Polynomial function for background fit
+
+        f = a + b*(x-center) + c*(x-center)**2 + bck
+
+        where bck is a minimum threshold that is zero when the polynomial
+        has a value greater than it.
+    """
+    coord = code_to_coord(value)
+    poly_a, poly_b, poly_c, center, background = p
+    values = poly_a + poly_b*(coord[0]-center) + poly_c*(coord[0]-center)**2
+    values[values<background] = background
+    values[coord[0]<DEAD_PIXELS] = 0
+    values[coord[0]>=NX_PIXELS-DEAD_PIXELS] = 0
+    values[coord[1]<DEAD_PIXELS] = 0
+    values[coord[1]>=NY_PIXELS-DEAD_PIXELS] = 0
+    return values
+
+
+def poly_bck_signal(value, *p):
+    """
+        Function for a polynomial + Gaussian signal
+
+        f = a + b*(x-center) + c*(x-center)**2 + Gaussian(x) + bck
+
+        where bck is a minimum threshold that is zero when the polynomial+Gaussian
+        has a value greater than it.
+    """
+    coord = code_to_coord(value)
+    A, mu_x, sigma_x, mu_y, sigma_y, poly_a, poly_b, poly_c, center, background = p
+    if A<0 or sigma_x>50:
+        return np.zeros(len(value))
+
+    values = poly_a + poly_b * (coord[0] - center) + poly_c * (coord[0] - center)**2
+    values_g = A * np.exp(-(coord[0] - mu_x)**2 / (2. * sigma_x**2)-(coord[1] - mu_y)**2 / (2. * sigma_y**2))
+    values += values_g
+    values[values<background] = background
+    values[coord[0]<DEAD_PIXELS] = 0
+    values[coord[0]>=NX_PIXELS-DEAD_PIXELS] = 0
+    values[coord[1]<DEAD_PIXELS] = 0
+    values[coord[1]>=NY_PIXELS-DEAD_PIXELS] = 0
+    return values
+
+
+def gauss_simple(value, *p):
+    """
+        Gaussian function with threshold background
+
+        f = Gaussian(x) + bck
+
+        where bck is a minimum threshold that is zero when the Gaussian
+        has a value greater than it.
+    """
+    coord = code_to_coord(value)
+    A, mu_x, sigma_x, mu_y, sigma_y, background = p
+    if A<0 or sigma_x>50:
+        return np.zeros(len(value))
+    values =  A * np.exp(-(coord[0] - mu_x)**2 / (2. * sigma_x**2) - (coord[1] - mu_y)**2 / (2. * sigma_y**2))
+    values[values<background] = background
+    values[coord[0]<DEAD_PIXELS] = 0
+    values[coord[0]>=NX_PIXELS-DEAD_PIXELS] = 0
+    values[coord[1]<DEAD_PIXELS] = 0
+    values[coord[1]>=NY_PIXELS-DEAD_PIXELS] = 0
+    return values
+
+
+def chi2(data, model):
+    """ Returns the chi^2 for a data set and model pair """
+    err = np.fabs(data.ravel())
+    err[err<=0] = 1
+    return np.sum((data.ravel() - model.ravel())**2 / err) / len(data.ravel())
+
 # Register
 AlgorithmFactory.subscribe(MRInspectData)