Esempio n. 1
0
    def test_that_create_manage_non_child_algorithm_is_called_once_in_centre_finder_new(
            self, make_algorithm_mock, load_data_mock):
        r_min = 5
        r_max = 10
        position_1_start = 300
        position_2_start = -300
        tolerance = 0.001
        find_direction = FindDirectionEnum.All
        iterations = 10
        verbose = False

        load_data_mock.return_value = {
            SANSDataType.SampleScatter: [mock.MagicMock()]
        }, {
            SANSDataType.SampleScatter: [mock.MagicMock()]
        }

        beam_centre_finder = "SANSBeamCentreFinder"
        beam_centre_finder_options = {
            "Component": 'LAB',
            "Iterations": iterations,
            "RMin": r_min / 1000,
            "RMax": r_max / 1000,
            "Position1Start": position_1_start,
            "Position2Start": position_2_start,
            "Tolerance": tolerance,
            "Direction": FindDirectionEnum.to_string(find_direction),
            "Verbose": verbose
        }

        centre_finder_new(self.state,
                          r_min=r_min,
                          r_max=r_max,
                          iterations=iterations,
                          position_1_start=position_1_start,
                          position_2_start=position_2_start,
                          tolerance=tolerance,
                          find_direction=find_direction,
                          verbose=verbose,
                          component=DetectorType.LAB)

        make_algorithm_mock.assert_called_once_with(
            beam_centre_finder, **beam_centre_finder_options)
    def test_that_create_manage_non_child_algorithm_is_called_once_in_centre_finder_new(self, make_algorithm_mock, load_data_mock):
        r_min = 5
        r_max = 10
        position_1_start = 300
        position_2_start = -300
        tolerance = 0.001
        find_direction = FindDirectionEnum.All
        iterations = 10
        verbose = False

        load_data_mock.return_value = {SANSDataType.SampleScatter: [mock.MagicMock()]}, {
            SANSDataType.SampleScatter: [mock.MagicMock()]}

        beam_centre_finder = "SANSBeamCentreFinder"
        beam_centre_finder_options = {"Component":'LAB', "Iterations": iterations, "RMin": r_min / 1000, "RMax": r_max / 1000,
                                      "Position1Start": position_1_start, "Position2Start": position_2_start,
                                      "Tolerance": tolerance, "Direction": FindDirectionEnum.to_string(find_direction),
                                      "Verbose": verbose}

        centre_finder_new(self.state, r_min=r_min, r_max=r_max, iterations=iterations, position_1_start=position_1_start
                          ,position_2_start=position_2_start, tolerance=tolerance, find_direction=find_direction
                          ,verbose=verbose, component=DetectorType.LAB)

        make_algorithm_mock.assert_called_once_with(beam_centre_finder, **beam_centre_finder_options)
Esempio n. 3
0
def centre_finder_new(state, r_min = 0.06, r_max = 0.26, iterations = 10, position_1_start = 0.0, position_2_start = 0.0
                      , tolerance = 0.0001251, find_direction = FindDirectionEnum.All, verbose=False, component=DetectorType.LAB):
    """
    Finds the beam centre from a good initial guess.

    This function finds the centre of the beam by splitting the workspace up into 4 quadrants and running a reduction on
    each. The (left, right) and (up, down) reductions are then compared producing residuals which are minimised through
    repeated iteration.
    :param state: This is a sans state, to find the beam centre for.
    :param r_min: This is the inner radius of the quartile mask.
    :param r_max: This is the outer radius of the quartile mask.
    :param max_iter: This is the maximum number of iterations.
    :param position_1_start: This is the starting position of the search on the x axis.
    :param position_2_start: This is the starting position of the search on the y axis.
    :param tolerance: This is the tolerance for the search.
    :param find_direction: This is an enumerator controlling which axis or both should be searched.
    """
    # ------------------------------------------------------------------------------------------------------------------
    # Load the data
    # ------------------------------------------------------------------------------------------------------------------
    workspace_to_name = {SANSDataType.SampleScatter: "SampleScatterWorkspace",
                         SANSDataType.SampleTransmission: "SampleTransmissionWorkspace",
                         SANSDataType.SampleDirect: "SampleDirectWorkspace",
                         SANSDataType.CanScatter: "CanScatterWorkspace",
                         SANSDataType.CanTransmission: "CanTransmissionWorkspace",
                         SANSDataType.CanDirect: "CanDirectWorkspace"}

    workspace_to_monitor = {SANSDataType.SampleScatter: "SampleScatterMonitorWorkSpace",
                            SANSDataType.CanScatter: "CanScatterMonitorWorkspace"}

    workspaces, monitors = provide_loaded_data(state, False, workspace_to_name, workspace_to_monitor)

    # ------------------------------------------------------------------------------------------------------------------
    # Get reduction settings
    # Split into individual bundles which can be reduced individually. We split here if we have multiple periods or
    # sliced times for example. For the beam centre finder we only use the first period.
    # ------------------------------------------------------------------------------------------------------------------
    reduction_packages = get_reduction_packages(state, workspaces, monitors)
    reduction_package = reduction_packages[0]

    # ------------------------------------------------------------------------------------------------------------------
    # Setup the beam centre finder algorithm.
    # ------------------------------------------------------------------------------------------------------------------
    beam_centre_finder = "SANSBeamCentreFinder"
    beam_centre_finder_options = {"Iterations": iterations, "RMin": r_min/1000, "RMax": r_max/1000,
                                  "Position1Start": position_1_start, "Position2Start": position_2_start,
                                  "Tolerance": tolerance, "Direction" : FindDirectionEnum.to_string(find_direction),
                                  "Verbose": verbose, "Component": DetectorType.to_string(component)}
    beam_centre_alg = create_managed_non_child_algorithm(beam_centre_finder, **beam_centre_finder_options)
    beam_centre_alg.setChild(False)
    set_properties_for_beam_centre_algorithm(beam_centre_alg, reduction_package,
                                             workspace_to_name, workspace_to_monitor)
    # -----------------------------------
    #  Run the beam centre finder algorithm.
    # -----------------------------------
    beam_centre_alg.execute()

    # -----------------------------------
    #  Get the outputs
    # -----------------------------------
    centre1 = beam_centre_alg.getProperty("Centre1").value
    centre2 = beam_centre_alg.getProperty("Centre2").value

    return {"pos1": centre1, "pos2": centre2}
Esempio n. 4
0
def centre_finder_new(state,
                      r_min=0.06,
                      r_max=0.26,
                      iterations=10,
                      position_1_start=0.0,
                      position_2_start=0.0,
                      tolerance=0.0001251,
                      find_direction=FindDirectionEnum.All):
    """
    Finds the beam centre from a good initial guess.

    This function finds the centre of the beam by splitting the workspace up into 4 quadrants and running a reduction on
    each. The (left, right) and (up, down) reductions are then compared producing residuals which are minimised through
    repeated iteration.
    :param state: This is a sans state, to find the beam centre for.
    :param r_min: This is the inner radius of the quartile mask.
    :param r_max: This is the outer radius of the quartile mask.
    :param max_iter: This is the maximum number of iterations.
    :param position_1_start: This is the starting position of the search on the x axis.
    :param position_2_start: This is the starting position of the search on the y axis.
    :param tolerance: This is the tolerance for the search.
    :param fine_direction: This is an enumerator controlling which axis or both should be searched.
    """
    # ------------------------------------------------------------------------------------------------------------------
    # Load the data
    # ------------------------------------------------------------------------------------------------------------------
    workspace_to_name = {
        SANSDataType.SampleScatter: "SampleScatterWorkspace",
        SANSDataType.SampleTransmission: "SampleTransmissionWorkspace",
        SANSDataType.SampleDirect: "SampleDirectWorkspace",
        SANSDataType.CanScatter: "CanScatterWorkspace",
        SANSDataType.CanTransmission: "CanTransmissionWorkspace",
        SANSDataType.CanDirect: "CanDirectWorkspace"
    }

    workspace_to_monitor = {
        SANSDataType.SampleScatter: "SampleScatterMonitorWorkSpace",
        SANSDataType.CanScatter: "CanScatterMonitorWorkspace"
    }

    workspaces, monitors = provide_loaded_data(state, False, workspace_to_name,
                                               workspace_to_monitor)

    # ------------------------------------------------------------------------------------------------------------------
    # Get reduction settings
    # Split into individual bundles which can be reduced individually. We split here if we have multiple periods or
    # sliced times for example. For the beam centre finder we only use the first period.
    # ------------------------------------------------------------------------------------------------------------------
    reduction_packages = get_reduction_packages(state, workspaces, monitors)
    reduction_package = reduction_packages[0]

    # ------------------------------------------------------------------------------------------------------------------
    # Setup the beam centre finder algorithm.
    # ------------------------------------------------------------------------------------------------------------------
    beam_centre_finder = "SANSBeamCentreFinder"
    beam_centre_finder_options = {
        "Iterations": iterations,
        "RMin": r_min / 1000,
        "RMax": r_max / 1000,
        "Position1Start": position_1_start,
        "Position2Start": position_2_start,
        "Tolerance": tolerance,
        "Direction": FindDirectionEnum.to_string(find_direction)
    }
    beam_centre_alg = create_managed_non_child_algorithm(
        beam_centre_finder, **beam_centre_finder_options)
    beam_centre_alg.setChild(False)
    set_properties_for_beam_centre_algorithm(beam_centre_alg,
                                             reduction_package,
                                             workspace_to_name,
                                             workspace_to_monitor)
    # -----------------------------------
    #  Run the beam centre finder algorithm.
    # -----------------------------------
    beam_centre_alg.execute()

    # -----------------------------------
    #  Get the outputs
    # -----------------------------------
    centre1 = beam_centre_alg.getProperty("Centre1").value
    centre2 = beam_centre_alg.getProperty("Centre2").value
    create_output_table(centre1, centre2)

    return {"pos1": centre1, "pos2": centre2}
Esempio n. 5
0
    def PyInit(self):
        # ----------
        # INPUT
        # ----------
        # Workspace which is to be cropped
        self.declareProperty(
            PropertyManagerProperty('SANSState'),
            doc='A property manager which fulfills the SANSState contract.')

        self.declareProperty(MatrixWorkspaceProperty(
            "SampleScatterWorkspace",
            '',
            optional=PropertyMode.Mandatory,
            direction=Direction.Input),
                             doc='The sample scatter data')

        self.declareProperty(MatrixWorkspaceProperty(
            "SampleScatterMonitorWorkspace",
            '',
            optional=PropertyMode.Mandatory,
            direction=Direction.Input),
                             doc='The sample scatter monitor data')

        self.declareProperty(MatrixWorkspaceProperty(
            "SampleTransmissionWorkspace",
            '',
            optional=PropertyMode.Optional,
            direction=Direction.Input),
                             doc='The sample transmission data')

        self.declareProperty(MatrixWorkspaceProperty(
            "SampleDirectWorkspace",
            '',
            optional=PropertyMode.Optional,
            direction=Direction.Input),
                             doc='The sample direct data')

        self.declareProperty(MatrixWorkspaceProperty(
            "CanScatterWorkspace",
            '',
            optional=PropertyMode.Optional,
            direction=Direction.Input),
                             doc='The can scatter data')

        self.declareProperty(MatrixWorkspaceProperty(
            "CanScatterMonitorWorkspace",
            '',
            optional=PropertyMode.Optional,
            direction=Direction.Input),
                             doc='The can scatter monitor data')

        self.declareProperty(MatrixWorkspaceProperty(
            "CanTransmissionWorkspace",
            '',
            optional=PropertyMode.Optional,
            direction=Direction.Input),
                             doc='The can transmission data')

        self.declareProperty(MatrixWorkspaceProperty(
            "CanDirectWorkspace",
            '',
            optional=PropertyMode.Optional,
            direction=Direction.Input),
                             doc='The can direct data')

        # The component, i.e. HAB or LAB
        allowed_detectors = StringListValidator([
            DetectorType.to_string(DetectorType.LAB),
            DetectorType.to_string(DetectorType.HAB)
        ])
        self.declareProperty(
            "Component",
            DetectorType.to_string(DetectorType.LAB),
            validator=allowed_detectors,
            direction=Direction.Input,
            doc="The component of the instrument which is to be reduced.")

        self.declareProperty("Iterations",
                             10,
                             direction=Direction.Input,
                             doc="The maximum number of iterations.")

        self.declareProperty("RMin",
                             0.6,
                             direction=Direction.Input,
                             doc="The inner radius of the quartile mask")

        self.declareProperty('RMax',
                             0.28,
                             direction=Direction.Input,
                             doc="The outer radius of the quartile mask")

        self.declareProperty('Position1Start',
                             0.0,
                             direction=Direction.Input,
                             doc="The search start position1")

        self.declareProperty('Position2Start',
                             0.0,
                             direction=Direction.Input,
                             doc="The search start position2")

        self.declareProperty('Tolerance',
                             0.0001251,
                             direction=Direction.Input,
                             doc="The search tolerance")

        self.declareProperty(
            'Direction',
            FindDirectionEnum.to_string(FindDirectionEnum.All),
            direction=Direction.Input,
            doc=
            "The search direction is an enumerable which can be either All, LeftRight or UpDown"
        )

        self.declareProperty(
            'Verbose',
            False,
            direction=Direction.Input,
            doc="Whether to keep workspaces from each iteration in ADS.")

        # ----------
        # Output
        # ----------
        # Workspace which is to be cropped

        self.declareProperty(
            'Centre1',
            0.0,
            direction=Direction.Output,
            doc="The centre position found in the first dimension")
        self.declareProperty(
            'Centre2',
            0.0,
            direction=Direction.Output,
            doc="The centre position found in the second dimension")
Esempio n. 6
0
    def PyExec(self):
        state = self._get_state()
        state_serialized = state.property_manager
        logger = Logger("CentreFinder")
        logger.notice("Starting centre finder routine...")
        progress = self._get_progress()
        self.scale_1 = 1000
        self.scale_2 = 1000
        verbose = self.getProperty('Verbose').value
        x_start = self.getProperty("Position1Start").value
        y_start = self.getProperty("Position2Start").value

        sample_scatter = self._get_cloned_workspace("SampleScatterWorkspace")
        sample_scatter_monitor = self._get_cloned_workspace(
            "SampleScatterMonitorWorkspace")
        sample_transmission = self._get_cloned_workspace(
            "SampleTransmissionWorkspace")
        sample_direct = self._get_cloned_workspace("SampleDirectWorkspace")

        instrument = sample_scatter.getInstrument()
        if instrument.getName() == 'LARMOR':
            self.scale_1 = 1.0

        can_scatter = self._get_cloned_workspace("CanScatterWorkspace")
        can_scatter_monitor = self._get_cloned_workspace(
            "CanScatterMonitorWorkspace")
        can_transmission = self._get_cloned_workspace(
            "CanTransmissionWorkspace")
        can_direct = self._get_cloned_workspace("CanDirectWorkspace")

        component = self.getProperty("Component").value
        tolerance = self.getProperty("Tolerance").value
        max_iterations = self.getProperty("Iterations").value

        r_min = self.getProperty("RMin").value
        r_max = self.getProperty("RMax").value

        instrument_file = get_instrument_paths_for_sans_file(
            state.data.sample_scatter)
        position_1_step = get_named_elements_from_ipf_file(
            instrument_file[1], "centre-finder-step-size",
            float)['centre-finder-step-size']
        try:
            position_2_step = get_named_elements_from_ipf_file(
                instrument_file[1], "centre-finder-step-size2",
                float)['centre-finder-step-size2']
        except:
            position_2_step = position_1_step

        find_direction = self.getProperty("Direction").value
        if find_direction == FindDirectionEnum.to_string(
                FindDirectionEnum.Left_Right):
            position_2_step = 0.0
        elif find_direction == FindDirectionEnum.to_string(
                FindDirectionEnum.Up_Down):
            position_1_step = 0.0
        centre1 = x_start
        centre2 = y_start
        residueLR = []
        residueTB = []
        centre_1_hold = x_start
        centre_2_hold = y_start
        for j in range(0, max_iterations + 1):
            if (j != 0):
                centre1 += position_1_step
                centre2 += position_2_step

            progress.report("Reducing ... Pos1 " + str(centre1) + " Pos2 " +
                            str(centre2))
            sample_quartiles = self._run_quartile_reduction(
                sample_scatter, sample_transmission, sample_direct, "Sample",
                sample_scatter_monitor, component, state_serialized, centre1,
                centre2, r_min, r_max)

            if can_scatter:
                can_quartiles = self._run_quartile_reduction(
                    can_scatter, can_transmission, can_direct, "Can",
                    can_scatter_monitor, component, state_serialized, centre1,
                    centre2, r_min, r_max)
                for key in sample_quartiles:
                    sample_quartiles[key] = perform_can_subtraction(
                        sample_quartiles[key], can_quartiles[key], self)

            if mantidplot:
                output_workspaces = self._publish_to_ADS(sample_quartiles)
                if verbose:
                    self._rename_and_group_workspaces(j, output_workspaces)

            residueLR.append(
                self._calculate_residuals(
                    sample_quartiles[MaskingQuadrant.Left],
                    sample_quartiles[MaskingQuadrant.Right]))
            residueTB.append(
                self._calculate_residuals(
                    sample_quartiles[MaskingQuadrant.Top],
                    sample_quartiles[MaskingQuadrant.Bottom]))
            if (j == 0):
                logger.notice("Itr " + str(j) + ": (" +
                              str(self.scale_1 * centre1) + ", " +
                              str(self.scale_2 * centre2) + ")  SX=" +
                              str(residueLR[j]) + "  SY=" + str(residueTB[j]))
                if mantidplot:
                    self._plot_quartiles(output_workspaces,
                                         state.data.sample_scatter)

            else:
                # have we stepped across the y-axis that goes through the beam center?
                if residueLR[j] > residueLR[j - 1]:
                    # yes with stepped across the middle, reverse direction and half the step size
                    position_1_step = -position_1_step / 2
                if residueTB[j] > residueTB[j - 1]:
                    position_2_step = -position_2_step / 2

                logger.notice("Itr " + str(j) + ": (" +
                              str(self.scale_1 * centre1) + ", " +
                              str(self.scale_2 * centre2) + ")  SX=" +
                              str(residueLR[j]) + "  SY=" + str(residueTB[j]))

                if (residueLR[j] + residueTB[j]) < (
                        residueLR[j - 1] + residueTB[j - 1]
                ) or state.compatibility.use_compatibility_mode:
                    centre_1_hold = centre1
                    centre_2_hold = centre2

                if abs(position_1_step) < tolerance and abs(
                        position_2_step) < tolerance:
                    # this is the success criteria, we've close enough to the center
                    logger.notice(
                        "Converged - check if stuck in local minimum! ")
                    break

            if j == max_iterations:
                logger.notice(
                    "Out of iterations, new coordinates may not be the best")

        self.setProperty("Centre1", centre_1_hold)
        self.setProperty("Centre2", centre_2_hold)

        logger.notice("Centre coordinates updated: [{}, {}]".format(
            centre_1_hold * self.scale_1, centre_2_hold * self.scale_2))
    def PyInit(self):
        # ----------
        # INPUT
        # ----------
        # Workspace which is to be cropped
        self.declareProperty(PropertyManagerProperty('SANSState'),
                             doc='A property manager which fulfills the SANSState contract.')

        self.declareProperty(MatrixWorkspaceProperty("SampleScatterWorkspace", '',
                                                     optional=PropertyMode.Mandatory, direction=Direction.Input),
                             doc='The sample scatter data')

        self.declareProperty(MatrixWorkspaceProperty("SampleScatterMonitorWorkspace", '',
                                                     optional=PropertyMode.Mandatory, direction=Direction.Input),
                             doc='The sample scatter monitor data')

        self.declareProperty(MatrixWorkspaceProperty("SampleTransmissionWorkspace", '',
                                                     optional=PropertyMode.Optional, direction=Direction.Input),
                             doc='The sample transmission data')

        self.declareProperty(MatrixWorkspaceProperty("SampleDirectWorkspace", '',
                                                     optional=PropertyMode.Optional, direction=Direction.Input),
                             doc='The sample direct data')

        self.declareProperty(MatrixWorkspaceProperty("CanScatterWorkspace", '',
                                                     optional=PropertyMode.Optional, direction=Direction.Input),
                             doc='The can scatter data')

        self.declareProperty(MatrixWorkspaceProperty("CanScatterMonitorWorkspace", '',
                                                     optional=PropertyMode.Optional, direction=Direction.Input),
                             doc='The can scatter monitor data')

        self.declareProperty(MatrixWorkspaceProperty("CanTransmissionWorkspace", '',
                                                     optional=PropertyMode.Optional, direction=Direction.Input),
                             doc='The can transmission data')

        self.declareProperty(MatrixWorkspaceProperty("CanDirectWorkspace", '',
                                                     optional=PropertyMode.Optional, direction=Direction.Input),
                             doc='The can direct data')

        # The component, i.e. HAB or LAB
        allowed_detectors = StringListValidator([DetectorType.to_string(DetectorType.LAB),
                                                 DetectorType.to_string(DetectorType.HAB)])
        self.declareProperty("Component", DetectorType.to_string(DetectorType.LAB),
                             validator=allowed_detectors, direction=Direction.Input,
                             doc="The component of the instrument which is to be reduced.")

        self.declareProperty("Iterations", 10, direction=Direction.Input, doc="The maximum number of iterations.")

        self.declareProperty("RMin", 0.6, direction=Direction.Input, doc="The inner radius of the quartile mask")

        self.declareProperty('RMax', 0.28, direction=Direction.Input, doc="The outer radius of the quartile mask")

        self.declareProperty('Position1Start', 0.0, direction=Direction.Input, doc="The search start position1")

        self.declareProperty('Position2Start', 0.0, direction=Direction.Input, doc="The search start position2")

        self.declareProperty('Tolerance', 0.0001251, direction=Direction.Input, doc="The search tolerance")

        self.declareProperty('Direction', FindDirectionEnum.to_string(FindDirectionEnum.All), direction=Direction.Input,
                             doc="The search direction is an enumerable which can be either All, LeftRight or UpDown")

        self.declareProperty('Verbose', False, direction=Direction.Input,
                             doc="Whether to keep workspaces from each iteration in ADS.")

        # ----------
        # Output
        # ----------
        # Workspace which is to be cropped

        self.declareProperty('Centre1', 0.0, direction=Direction.Output,
                             doc="The centre position found in the first dimension")
        self.declareProperty('Centre2', 0.0, direction=Direction.Output,
                             doc="The centre position found in the second dimension")
    def PyExec(self):
        state = self._get_state()
        state_serialized = state.property_manager
        logger = Logger("CentreFinder")
        logger.notice("Starting centre finder routine...")
        progress = self._get_progress()
        self.scale_1 = 1000
        self.scale_2 = 1000
        verbose = self.getProperty('Verbose').value
        x_start = self.getProperty("Position1Start").value
        y_start = self.getProperty("Position2Start").value

        sample_scatter = self._get_cloned_workspace("SampleScatterWorkspace")
        sample_scatter_monitor = self._get_cloned_workspace("SampleScatterMonitorWorkspace")
        sample_transmission = self._get_cloned_workspace("SampleTransmissionWorkspace")
        sample_direct = self._get_cloned_workspace("SampleDirectWorkspace")

        instrument = sample_scatter.getInstrument()
        if instrument.getName() == 'LARMOR':
            self.scale_1 = 1.0

        can_scatter = self._get_cloned_workspace("CanScatterWorkspace")
        can_scatter_monitor = self._get_cloned_workspace("CanScatterMonitorWorkspace")
        can_transmission = self._get_cloned_workspace("CanTransmissionWorkspace")
        can_direct = self._get_cloned_workspace("CanDirectWorkspace")

        component = self.getProperty("Component").value
        tolerance = self.getProperty("Tolerance").value
        max_iterations = self.getProperty("Iterations").value

        r_min = self.getProperty("RMin").value
        r_max = self.getProperty("RMax").value

        instrument_file = get_instrument_paths_for_sans_file(state.data.sample_scatter)
        position_1_step = get_named_elements_from_ipf_file(
            instrument_file[1], ["centre-finder-step-size"], float)['centre-finder-step-size']
        try:
            position_2_step = get_named_elements_from_ipf_file(
                instrument_file[1], ["centre-finder-step-size2"], float)['centre-finder-step-size2']
        except:
            position_2_step = position_1_step

        find_direction = self.getProperty("Direction").value
        if find_direction == FindDirectionEnum.to_string(FindDirectionEnum.Left_Right):
            position_2_step = 0.0
        elif find_direction == FindDirectionEnum.to_string(FindDirectionEnum.Up_Down):
            position_1_step = 0.0
        centre1 = x_start
        centre2 = y_start
        residueLR = []
        residueTB = []
        centre_1_hold = x_start
        centre_2_hold = y_start
        for j in range(0, max_iterations + 1):
            if(j != 0):
                centre1 += position_1_step
                centre2 += position_2_step

            progress.report("Reducing ... Pos1 " + str(centre1) + " Pos2 " + str(centre2))
            sample_quartiles = self._run_quartile_reduction(sample_scatter, sample_transmission, sample_direct,
                                                            "Sample", sample_scatter_monitor, component,
                                                            state_serialized, centre1, centre2, r_min, r_max)

            if can_scatter:
                can_quartiles = self._run_quartile_reduction(can_scatter, can_transmission, can_direct, "Can",
                                                             can_scatter_monitor, component, state_serialized, centre1,
                                                             centre2, r_min, r_max)
                for key in sample_quartiles:
                    sample_quartiles[key] = perform_can_subtraction(sample_quartiles[key], can_quartiles[key], self)

            if mantidplot:
                output_workspaces = self._publish_to_ADS(sample_quartiles)
                if verbose:
                    self._rename_and_group_workspaces(j, output_workspaces)

            residueLR.append(self._calculate_residuals(sample_quartiles[MaskingQuadrant.Left],
                                                       sample_quartiles[MaskingQuadrant.Right]))
            residueTB.append(self._calculate_residuals(sample_quartiles[MaskingQuadrant.Top],
                                                       sample_quartiles[MaskingQuadrant.Bottom]))
            if(j == 0):
                logger.notice("Itr {0}: ( {1}, {2} )  SX={3:.5g}  SY={4:.5g}".
                              format(j, self.scale_1 * centre1, self.scale_2 * centre2, residueLR[j], residueTB[j]))
                if mantidplot:
                    self._plot_quartiles(output_workspaces, state.data.sample_scatter)

            else:
                # have we stepped across the y-axis that goes through the beam center?
                if residueLR[j] > residueLR[j-1]:
                    # yes with stepped across the middle, reverse direction and half the step size
                    position_1_step = - position_1_step / 2
                if residueTB[j] > residueTB[j-1]:
                    position_2_step = - position_2_step / 2

                logger.notice("Itr {0}: ( {1}, {2} )  SX={3:.5g}  SY={4:.5g}".
                              format(j, self.scale_1 * centre1, self.scale_2 * centre2, residueLR[j], residueTB[j]))

                if (residueLR[j]+residueTB[j]) < (residueLR[j-1]+residueTB[j-1]) or state.compatibility.use_compatibility_mode:
                    centre_1_hold = centre1
                    centre_2_hold = centre2

                if abs(position_1_step) < tolerance and abs(position_2_step) < tolerance:
                    # this is the success criteria, we've close enough to the center
                    logger.notice("Converged - check if stuck in local minimum! ")
                    break

            if j == max_iterations:
                logger.notice("Out of iterations, new coordinates may not be the best")

        self.setProperty("Centre1", centre_1_hold)
        self.setProperty("Centre2", centre_2_hold)

        logger.notice("Centre coordinates updated: [{}, {}]".format(centre_1_hold*self.scale_1, centre_2_hold*self.scale_2))