def testStep(self):
        """Test fit manager on a step function with a more complex estimate
        function than the gaussian (convolution filter)"""
        for theory_name, theory_fun in (('Step Down', sum_stepdown),
                                        ('Step Up', sum_stepup)):
            # Create synthetic data with a sum of gaussian functions
            x = numpy.arange(1000).astype(numpy.float64)

            # ('Height', 'Position', 'FWHM')
            p = [1000, 439, 250]

            constantbg = 13
            y = theory_fun(x, *p) + constantbg

            # Fitting
            fit = fitmanager.FitManager()
            fit.setdata(x=x, y=y)
            fit.loadtheories(fittheories)
            fit.settheory(theory_name)
            fit.setbackground('Constant')

            fit.estimate()

            params, sigmas, infodict = fit.runfit()

            # first parameter is the constant background
            self.assertAlmostEqual(params[0], 13, places=5)
            for i, param in enumerate(params[1:]):
                self.assertAlmostEqual(param, p[i], places=5)
                self.assertAlmostEqual(
                    _order_of_magnitude(fit.fit_results[i + 1]["estimation"]),
                    _order_of_magnitude(p[i]))
Exemple #2
0
    def testFitManager(self):
        """Test fit manager on synthetic data using a gaussian function
        and a linear background"""
        # Create synthetic data with a sum of gaussian functions
        x = numpy.arange(1000).astype(numpy.float64)

        p = [1000, 100., 250,
             255, 650., 45,
             1500, 800.5, 95]
        linear_bg = 2.65 * x + 13
        y = linear_bg + sum_gauss(x, *p)

        y_with_nans = numpy.array(y)
        y_with_nans[::10] = numpy.nan

        x_with_nans = numpy.array(x)
        x_with_nans[5::15] = numpy.nan

        tests = {
            'all finite': (x, y),
            'y with NaNs': (x, y_with_nans),
            'x with NaNs': (x_with_nans, y),
            }

        for name, (xdata, ydata) in tests.items():
            with self.subTest(name=name):
                # Fitting
                fit = fitmanager.FitManager()
                fit.setdata(x=xdata, y=ydata)
                fit.loadtheories(fittheories)
                # Use one of the default fit functions
                fit.settheory('Gaussians')
                fit.setbackground('Linear')
                fit.estimate()
                fit.runfit()

                # fit.fit_results[]

                # first 2 parameters are related to the linear background
                self.assertEqual(fit.fit_results[0]["name"], "Constant")
                self.assertAlmostEqual(fit.fit_results[0]["fitresult"], 13)
                self.assertEqual(fit.fit_results[1]["name"], "Slope")
                self.assertAlmostEqual(fit.fit_results[1]["fitresult"], 2.65)

                for i, param in enumerate(fit.fit_results[2:]):
                    param_number = i // 3 + 1
                    if i % 3 == 0:
                        self.assertEqual(param["name"],
                                         "Height%d" % param_number)
                    elif i % 3 == 1:
                        self.assertEqual(param["name"],
                                         "Position%d" % param_number)
                    elif i % 3 == 2:
                        self.assertEqual(param["name"],
                                         "FWHM%d" % param_number)

                    self.assertAlmostEqual(param["fitresult"],
                                           p[i])
                    self.assertAlmostEqual(_order_of_magnitude(param["estimation"]),
                                           _order_of_magnitude(p[i]))
def test():
    from silx.math.fit import fittheories
    from silx.math.fit import fitmanager
    from silx.math.fit import functions
    from silx.gui.plot.PlotWindow import PlotWindow
    import numpy

    a = qt.QApplication([])

    x = numpy.arange(1000)
    y1 = functions.sum_gauss(x, 100, 400, 100)

    fit = fitmanager.FitManager(x=x, y=y1)

    fitfuns = fittheories.FitTheories()
    fit.addtheory(name="Gaussian",
                  function=functions.sum_gauss,
                  parameters=("height", "peak center", "fwhm"),
                  estimate=fitfuns.estimate_height_position_fwhm)
    fit.settheory('Gaussian')
    fit.configure(
        PositiveFwhmFlag=True,
        PositiveHeightAreaFlag=True,
        AutoFwhm=True,
    )

    # Fit
    fit.estimate()
    fit.runfit()

    w = ParametersTab()
    w.show()
    w.fillFromFit(fit.fit_results, view='Gaussians')

    y2 = functions.sum_splitgauss(x, 100, 400, 100, 40, 10, 600, 50, 500, 80,
                                  850, 10, 50)
    fit.setdata(x=x, y=y2)

    # Define new theory
    fit.addtheory(name="Asymetric gaussian",
                  function=functions.sum_splitgauss,
                  parameters=("height", "peak center", "left fwhm",
                              "right fwhm"),
                  estimate=fitfuns.estimate_splitgauss)
    fit.settheory('Asymetric gaussian')

    # Fit
    fit.estimate()
    fit.runfit()

    w.fillFromFit(fit.fit_results, view='Asymetric gaussians')

    # Plot
    pw = PlotWindow(control=True)
    pw.addCurve(x, y1, "Gaussians")
    pw.addCurve(x, y2, "Asymetric gaussians")
    pw.show()

    a.exec_()
    def _testPoly(self, poly_params, theory, places=5):
        p = numpy.poly1d(poly_params)

        y = p(self.x)

        fm = fitmanager.FitManager(self.x, y)
        fm.loadbgtheories(bgtheories)
        fm.loadtheories(fittheories)
        fm.settheory(theory)
        esti_params = fm.estimate()
        fit_params = fm.runfit()[0]

        for p, pfit in zip(poly_params, fit_params):
            self.assertAlmostEqual(p, pfit, places=places)
    def testQuarticcBg(self):
        gaussian_params = [10000, 69, 25]
        poly_params = [5e-10, 0.0005, 0.005, 2, 4]
        p = numpy.poly1d(poly_params)

        y = p(self.x) + sum_gauss(self.x, *gaussian_params)

        fm = fitmanager.FitManager(self.x, y)
        fm.loadtheories(fittheories)
        fm.settheory("Gaussians")
        fm.setbackground("Degree 4 Polynomial")
        esti_params = fm.estimate()
        fit_params = fm.runfit()[0]

        for p, pfit in zip(poly_params + gaussian_params, fit_params):
            self.assertAlmostEqual(p, pfit, places=5)
    def testCubicBg(self):
        gaussian_params = [1000, 45, 8]
        poly_params = [0.0005, -0.05, 3, -4]
        p = numpy.poly1d(poly_params)

        y = p(self.x) + sum_gauss(self.x, *gaussian_params)

        fm = fitmanager.FitManager(self.x, y)
        fm.loadtheories(fittheories)
        fm.settheory("Gaussians")
        fm.setbackground("Degree 3 Polynomial")
        esti_params = fm.estimate()
        fit_params = fm.runfit()[0]

        for p, pfit in zip(poly_params + gaussian_params, fit_params):
            self.assertAlmostEqual(p, pfit)
Exemple #7
0
    def testLoadCustomFitFunction(self):
        """Test FitManager using a custom fit function defined in an external
        file and imported with FitManager.loadtheories"""
        # Create synthetic data with a sum of gaussian functions
        x = numpy.arange(100).astype(numpy.float64)

        # a, b, c are the fit parameters
        # d is a known scaling parameter that is set using configure()
        a, b, c, d = 1.5, 2.5, 3.5, 4.5
        y = (a * x**2 + b * x + c) / d

        # Fitting
        fit = fitmanager.FitManager()
        fit.setdata(x=x, y=y)

        # Create a temporary function definition file, and import it
        with temp_dir() as tmpDir:
            tmpfile = os.path.join(tmpDir, 'customfun.py')
            # custom_function_definition
            fd = open(tmpfile, "w")
            fd.write(custom_function_definition)
            fd.close()
            fit.loadtheories(tmpfile)
            tmpfile_pyc = os.path.join(tmpDir, 'customfun.pyc')
            if os.path.exists(tmpfile_pyc):
                os.unlink(tmpfile_pyc)
            os.unlink(tmpfile)

        fit.settheory('my fit theory')
        # Test configure
        fit.configure(d=4.5)
        fit.estimate()
        fit.runfit()

        self.assertEqual(fit.fit_results[0]["name"],
                         "A1")
        self.assertAlmostEqual(fit.fit_results[0]["fitresult"],
                               1.5)
        self.assertEqual(fit.fit_results[1]["name"],
                         "B1")
        self.assertAlmostEqual(fit.fit_results[1]["fitresult"],
                               2.5)
        self.assertEqual(fit.fit_results[2]["name"],
                         "C1")
        self.assertAlmostEqual(fit.fit_results[2]["fitresult"],
                               3.5)
Exemple #8
0
    def _setFitManager(self, fitinstance):
        """Initialize a :class:`FitManager` instance, to be assigned to
        :attr:`fitmanager`, or use a custom FitManager instance.

        :param fitinstance: Existing instance of FitManager, possibly
            customized by the user, or None to load a default instance."""
        if isinstance(fitinstance, fitmanager.FitManager):
            # customized
            fitmngr = fitinstance
        else:
            # initialize default instance
            fitmngr = fitmanager.FitManager()

        # initialize the default fitting functions in case
        # none is present
        if not len(fitmngr.theories):
            fitmngr.loadtheories(fittheories)

        return fitmngr
def main(args):
    from silx.math.fit import fittheories
    from silx.math.fit import fitmanager
    try:
        from PyMca5 import PyMcaDataDir
    except ImportError:
        raise ImportError("This demo requires PyMca data. Install PyMca5.")
    import numpy
    import os
    app = qt.QApplication(args)
    tab = Parameters(paramlist=['Height', 'Position', 'FWHM'])
    tab.showGrid()
    tab.configureLine(name='Height', estimation='1234', group=0)
    tab.configureLine(name='Position', code='FIXED', group=1)
    tab.configureLine(name='FWHM', group=1)

    y = numpy.loadtxt(
        os.path.join(PyMcaDataDir.PYMCA_DATA_DIR, "XRFSpectrum.mca"))  # FIXME

    x = numpy.arange(len(y)) * 0.0502883 - 0.492773
    fit = fitmanager.FitManager()
    fit.setdata(x=x, y=y, xmin=20, xmax=150)

    fit.loadtheories(fittheories)

    fit.settheory('ahypermet')
    fit.configure(Yscaling=1.,
                  PositiveFwhmFlag=True,
                  PositiveHeightAreaFlag=True,
                  FwhmPoints=16,
                  QuotedPositionFlag=1,
                  HypermetTails=1)
    fit.setbackground('Linear')
    fit.estimate()
    fit.runfit()
    tab.fillFromFit(fit.fit_results)
    tab.show()
    app.exec_()
    def testAddTheory(self, estimate=True):
        """Test FitManager using a custom fit function imported with
        FitManager.addtheory"""
        # Create synthetic data with a sum of gaussian functions
        x = numpy.arange(100).astype(numpy.float64)

        # a, b, c are the fit parameters
        # d is a known scaling parameter that is set using configure()
        a, b, c, d = -3.14, 1234.5, 10000, 4.5
        y = (a * x**2 + b * x + c) / d

        # Fitting
        fit = fitmanager.FitManager()
        fit.setdata(x=x, y=y)

        # Define and add the fit theory
        CONFIG = {'d': 1.}

        def myfun(x_, a_, b_, c_):
            """"Model function"""
            return (a_ * x_**2 + b_ * x_ + c_) / CONFIG['d']

        def myesti(x_, y_):
            """"Initial parameters for iterative fit:
                 (a, b, c) = (1, 1, 1)
            Constraints all set to 0 (FREE)"""
            return (1., 1., 1.), ((0, 0, 0), (0, 0, 0), (0, 0, 0))

        def myconfig(d_=1., **kw):
            """This function can modify CONFIG"""
            CONFIG["d"] = d_
            return CONFIG

        def myderiv(x_, parameters, index):
            """Custom derivative"""
            pars_plus = numpy.array(parameters, copy=True)
            pars_plus[index] *= 1.001

            pars_minus = numpy.array(parameters, copy=True)
            pars_minus[index] *= 0.999

            delta_fun = myfun(x_, *pars_plus) - myfun(x_, *pars_minus)
            delta_par = parameters[index] * 0.001 * 2

            return delta_fun / delta_par

        fit.addtheory(
            "polynomial",
            FitTheory(function=myfun,
                      parameters=["A", "B", "C"],
                      estimate=myesti if estimate else None,
                      configure=myconfig,
                      derivative=myderiv))

        fit.settheory('polynomial')
        fit.configure(d_=4.5)
        fit.estimate()
        params1, sigmas, infodict = fit.runfit()

        self.assertEqual(fit.fit_results[0]["name"], "A1")
        self.assertAlmostEqual(fit.fit_results[0]["fitresult"], -3.14)
        self.assertEqual(fit.fit_results[1]["name"], "B1")
        # params1[1] is the same as fit.fit_results[1]["fitresult"]
        self.assertAlmostEqual(params1[1], 1234.5)
        self.assertEqual(fit.fit_results[2]["name"], "C1")
        self.assertAlmostEqual(params1[2], 10000)

        # change configuration scaling factor and check that the fit returns
        # different values
        fit.configure(d_=5.)
        fit.estimate()
        params2, sigmas, infodict = fit.runfit()
        for p1, p2 in zip(params1, params2):
            self.assertFalse(
                numpy.array_equal(p1, p2),
                "Fit parameters are equal even though the " +
                "configuration has been changed")