def test_fit_cost_contains_correct_numbers(self):
        peak_table, refit_peak_table, fit_cost = FitGaussianPeaks(
            InputWorkspace=self.data_ws,
            PeakGuessTable=self.peak_guess_table,
            EstimatedPeakSigma=5,
            MinPeakSigma=3,
            MaxPeakSigma=12,
            GeneralFitTolerance=1)
        chi2 = fit_cost.column(0)[0]
        poisson = fit_cost.column(1)[0]

        peak1 = peak_table.row(0)
        peak2 = peak_table.row(1)
        yvals = self.gaussian(self.x_values, peak1['centre'], peak1['height'],
                              peak1['sigma'])
        yvals += self.gaussian(self.x_values, peak2['centre'], peak2['height'],
                               peak2['sigma'])

        real_chi2 = self.alg_instance.function_difference(
            self.y_values, yvals, np.sqrt(self.y_values))
        real_poisson = self.alg_instance.poisson_cost(
            self.y_values + self.background, yvals + self.background)

        self.assertAlmostEqual(real_chi2, chi2, 3)
        self.assertAlmostEqual(real_poisson, poisson, 3)
    def test_algorithm_estimates_fit_window(self):
        x_val = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
        y_val = [0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 10, 7]
        ws = CreateWorkspace(x_val * 2, y_val + [0] * len(y_val), NSpec=2)

        table = CreateEmptyTableWorkspace()
        table.addColumn("float", "Centre")
        table.addRow([20])
        with mock.patch(
                'plugins.algorithms.WorkflowAlgorithms.FitGaussianPeaks.FitGaussianPeaks.'
                'estimate_single_parameters') as mock_estimate_params:
            mock_estimate_params.return_value = None
            FitGaussianPeaks(InputWorkspace=ws,
                             PeakGuessTable=table,
                             EstimateFitWindow=True,
                             FitWindowSize=11)

            centre_index = 10
            """
                win_size in this case is calculated from EstimatePeakSigma and is estimated to be 2 and FitWindowSize
                is ignored
            """
            win_size = 2
            arguements = mock_estimate_params.call_args_list[0][0]
            self.assertSequenceEqual(list(arguements[0]), x_val)
            self.assertSequenceEqual(list(arguements[1]), y_val)
            self.assertEqual(arguements[2], centre_index)
            self.assertEqual(arguements[3], win_size)
            self.assertEqual(len(arguements), 4)
    def test_algorithm_uses_right_fit_window(self):
        x_val = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
        y_val = [0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 10, 7]
        ws = CreateWorkspace(x_val * 2, y_val + [0] * len(y_val), NSpec=2)

        table = CreateEmptyTableWorkspace()
        table.addColumn("float", "Centre")
        table.addRow([20])
        with mock.patch(
                'plugins.algorithms.WorkflowAlgorithms.FitGaussianPeaks.FitGaussianPeaks.'
                'estimate_single_parameters') as mock_estimate_params:
            mock_estimate_params.return_value = None
            FitGaussianPeaks(InputWorkspace=ws,
                             PeakGuessTable=table,
                             EstimateFitWindow=False,
                             FitWindowSize=11)
            centre_index = 10
            # win_size is ( FitWindowSize -1)/2 as method estimate_single_parameters expects in this form
            win_size = 5
            arguements = mock_estimate_params.call_args_list[0][0]
            self.assertSequenceEqual(list(arguements[0]), x_val)
            self.assertSequenceEqual(list(arguements[1]), y_val)
            self.assertEqual(arguements[2], centre_index)
            self.assertEqual(arguements[3], win_size)
            self.assertEqual(len(arguements), 4)
    def test_peak_parameters_are_correct(self):
        peak_table, refit_peak_table, fit_cost = FitGaussianPeaks(
            InputWorkspace=self.data_ws,
            PeakGuessTable=self.peak_guess_table,
            EstimatedPeakSigma=5,
            MinPeakSigma=3,
            MaxPeakSigma=12,
            GeneralFitTolerance=1)

        peak1 = peak_table.row(0)
        peak2 = peak_table.row(1)
        centre1, height1, sigma1 = peak1['centre'], peak1['height'], peak1[
            'sigma']
        centre2, height2, sigma2 = peak2['centre'], peak2['height'], peak2[
            'sigma']

        self.assertAlmostEqual(centre1, self.centre[0])
        self.assertAlmostEqual(centre2, self.centre[1])
        self.assertAlmostEqual(height1, self.height[0])
        self.assertAlmostEqual(height2, self.height[1])
        self.assertAlmostEqual(sigma1, self.width[0])
        self.assertAlmostEqual(sigma2, self.width[1])
    def test_algorithm_does_not_throw_an_error_when_no_valid_peaks_fitted(
            self):
        x_val = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
        y_val = [0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 10, 7]
        ws = CreateWorkspace(x_val * 2, y_val + [0] * len(y_val), NSpec=2)
        table = CreateEmptyTableWorkspace()
        table.addColumn("float", "Centre")
        table.addRow([20])

        FitGaussianPeaks(InputWorkspace=ws, PeakGuessTable=table)

        self.assertEqual(mtd["peak_table"].rowCount(), 0)
        self.assertEqual(mtd["refit_peak_table"].rowCount(), 0)
    def test_algorithm_creates_correct_tables(self):
        FitGaussianPeaks(InputWorkspace=self.data_ws,
                         PeakGuessTable=self.peak_guess_table)

        self.assertIn('peak_table', mtd)
        self.assertIn('refit_peak_table', mtd)
        self.assertIn('fit_cost', mtd)

        self.assertEqual(list(mtd['peak_table'].getColumnNames()),
                         self.peak_table_header)
        self.assertEqual(list(mtd['refit_peak_table'].getColumnNames()),
                         self.peak_table_header)
        self.assertEqual(list(mtd['fit_cost'].getColumnNames()),
                         ['Chi2', 'Poisson'])
    def test_algorithm_skips_invalid_peak(self):
        ws = CreateWorkspace([0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22] * 2,
                             [0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 10, 7] + [0] * 12,
                             NSpec=2)
        table = CreateEmptyTableWorkspace()
        table.addColumn("float", "Centre")
        table.addRow([10])
        table.addRow([20])

        FitGaussianPeaks(InputWorkspace=ws, PeakGuessTable=table)

        peak_table = mtd["peak_table"]
        row = peak_table.row(0)

        self.assertEqual(mtd["peak_table"].rowCount(), 1)
        self.assertEqual(mtd["refit_peak_table"].rowCount(), 0)
        self.assertAlmostEqual(row["centre"], 9.641, places=3)
        self.assertAlmostEqual(row["error centre"], 0.225, places=3)
        self.assertAlmostEqual(row["height"], 7.7, places=3)
        self.assertAlmostEqual(row["error height"], 0.02242, places=3)
        self.assertAlmostEqual(row["sigma"], 0.8087, places=3)
        self.assertAlmostEqual(row["error sigma"], 0.1898, places=3)
        self.assertAlmostEqual(row["area"], 15.6085, places=3)
        self.assertAlmostEqual(row["error area"], 0.2347, places=3)
    def find_good_peaks(self, xvals, peakids, acceptance, bad_peak_to_consider,
                        use_poisson, fit_ws, peak_width_estimate):
        prog_reporter = Progress(self,
                                 start=0.1,
                                 end=1.0,
                                 nreports=2 + len(peakids))

        actual_peaks = []
        skipped = 0
        cost_idx = 1 if use_poisson else 0
        prog_reporter.report('Starting fit')
        logger.notice('Fitting null hypothesis')
        peak_table, refit_peak_table, cost = FitGaussianPeaks(
            InputWorkspace=fit_ws,
            PeakGuessTable=self.generate_peak_guess_table(xvals, []),
            CentreTolerance=1.0,
            EstimatedPeakSigma=peak_width_estimate,
            MinPeakSigma=self._min_sigma,
            MaxPeakSigma=self._max_sigma,
            GeneralFitTolerance=0.1,
            RefitTolerance=0.001,
            StoreInADS=False)
        old_cost = cost.column(cost_idx)[0]

        for idx, peak_idx in enumerate(peakids):
            peak_table, refit_peak_table, cost = FitGaussianPeaks(
                InputWorkspace=fit_ws,
                PeakGuessTable=self.generate_peak_guess_table(
                    xvals, actual_peaks + [peak_idx]),
                CentreTolerance=1.0,
                EstimatedPeakSigma=peak_width_estimate,
                MinPeakSigma=self._min_sigma,
                MaxPeakSigma=self._max_sigma,
                GeneralFitTolerance=0.1,
                RefitTolerance=0.001,
                StoreInADS=False)
            new_cost = cost.column(cost_idx)[0]
            if use_poisson:
                # if p_new > p_old, but uses logs
                cost_change = new_cost - old_cost
                good_peak_condition = cost_change > np.log(acceptance)
            else:
                cost_change = abs(new_cost - old_cost) / new_cost
                good_peak_condition = (new_cost <= old_cost) and (cost_change >
                                                                  acceptance)

            if skipped > bad_peak_to_consider:
                break
            msg = ''
            if good_peak_condition:
                msg = '** peak found, '
                skipped = 0
                actual_peaks.append(peak_idx)
                old_cost = new_cost
            else:
                skipped += 1
            prog_reporter.report('Iteration {}, {} peaks found'.format(
                idx + 1, len(actual_peaks)))
            msg += '{} peaks in total. cost={:.2}, cost change={:.5}'
            logger.information(
                msg.format(len(actual_peaks), new_cost, cost_change))

        peak_table, refit_peak_table, cost = FitGaussianPeaks(
            InputWorkspace=fit_ws,
            PeakGuessTable=self.generate_peak_guess_table(xvals, actual_peaks),
            CentreTolerance=1.0,
            EstimatedPeakSigma=peak_width_estimate,
            MinPeakSigma=self._min_sigma,
            MaxPeakSigma=self._max_sigma,
            GeneralFitTolerance=0.1,
            RefitTolerance=0.001,
            StoreInADS=False)
        prog_reporter.report('Fitting done')
        logger.notice(
            'Fitting done, {} good peaks and {} refitted peak found'.format(
                peak_table.rowCount(), refit_peak_table.rowCount()))
        return actual_peaks, peak_table, refit_peak_table
    def test_algorithm_does_not_need_refitting_when_given_good_data(self):
        peak_table, refit_peak_table, fit_cost = FitGaussianPeaks(
            InputWorkspace=self.data_ws, PeakGuessTable=self.peak_guess_table)

        self.assertEqual(0, refit_peak_table.rowCount())
        self.assertEqual(2, peak_table.rowCount())
 def test_algorithm_with_negative_refit_tolerance_throws(self):
     with self.assertRaises(Exception):
         FitGaussianPeaks(InputWorkspace=self.data_ws,
                          PeakGuessTable=self.peak_guess_table,
                          RefitTolerance=-1.0)
 def test_algorithm_with_negative_max_peak_sigma_throws(self):
     with self.assertRaises(Exception):
         FitGaussianPeaks(InputWorkspace=self.data_ws,
                          PeakGuessTable=self.peak_guess_table,
                          MaxPeakSigma=-1.0)
 def test_algorithm_with_bad_input_workspace_throws(self):
     with self.assertRaises(Exception):
         FitGaussianPeaks(InputWorkspace='ws-that-does-not-exist')
 def test_algorithm_with_negative_general_fit_tolerance_throws(self):
     with self.assertRaises(ValueError):
         FitGaussianPeaks(InputWorkspace=self.data_ws,
                          PeakGuessTable=self.peak_guess_table,
                          GeneralFitTolerance=-1.0)
 def test_algorithm_with_float_fit_window_throws(self):
     with self.assertRaises(TypeError):
         FitGaussianPeaks(InputWorkspace=self.data_ws,
                          PeakGuessTable=self.peak_guess_table,
                          FitWindowSize=5.5)
 def test_algorithm_with_fit_window_lower_than_5_throws(self):
     with self.assertRaises(ValueError):
         FitGaussianPeaks(InputWorkspace=self.data_ws,
                          PeakGuessTable=self.peak_guess_table,
                          FitWindowSize=3)
 def test_algorithm_with_negative_min_peak_sigma_throws(self):
     with self.assertRaises(ValueError):
         FitGaussianPeaks(InputWorkspace=self.data_ws,
                          PeakGuessTable=self.peak_guess_table,
                          MinPeakSigma=-1.0)