Пример #1
0
    def test_model_nan_policy(self):
        x = np.linspace(0, 10, 201)
        np.random.seed(0)
        y = gaussian(x, 10.0, 6.15, 0.8)
        y += gaussian(x, 8.0, 6.35, 1.1)
        y += gaussian(x, 0.25, 6.00, 7.5)
        y += np.random.normal(size=len(x), scale=0.5)

        y[55] = y[91] = np.nan
        mod = PseudoVoigtModel()
        params = mod.make_params(amplitude=20, center=5.5,
                                 sigma=1, fraction=0.25)
        params['fraction'].vary = False
        # with raise, should get a ValueError
        result = lambda: mod.fit(y, params, x=x, nan_policy='raise')
        self.assertRaises(ValueError, result)

        # with propagate, should get no error, but bad results
        result = mod.fit(y, params, x=x, nan_policy='propagate')
        self.assertTrue(result.success)
        self.assertTrue(np.isnan(result.chisqr))
        self.assertTrue(np.isnan(result.aic))
        self.assertFalse(result.errorbars)
        self.assertTrue(result.params['amplitude'].stderr is None)
        self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 0.001)

        # with omit, should get good results
        result = mod.fit(y, params, x=x, nan_policy='omit')
        self.assertTrue(result.success)
        self.assertTrue(result.chisqr > 2.0)
        self.assertTrue(result.aic < -100)
        self.assertTrue(result.errorbars)
        self.assertTrue(result.params['amplitude'].stderr > 0.1)
        self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 5.0)
        self.assertTrue(abs(result.params['center'].value - 6.0) < 0.5)
Пример #2
0
    def __init__(self, type):

        self.peak = [None] * (defPar.NumPeaks)

        if type == 0:
            for i in range(0, defPar.NumPeaks):
                self.peak[i] = PseudoVoigtModel(prefix="p" + str(i) + "_")
            self.typec = "PseudoVoigt"
        elif type == 1:
            for i in range(0, defPar.NumPeaks):
                self.peak[i] = GaussianModel(prefix="p" + str(i) + "_")
            self.typec = "Gauss"
        elif type == 2:
            for i in range(0, defPar.NumPeaks):
                self.peak[i] = LorentzianModel(prefix="p" + str(i) + "_")
            self.typec = "Lorentz"
        elif type == 3:
            for i in range(0, defPar.NumPeaks):
                self.peak[i] = VoigtModel(prefix="p" + str(i) + "_")
            self.typec = "Voigt"
        else:
            print("Warning: type undefined. Using PseudoVoigt")
            for i in range(0, defPar.NumPeaks):
                self.peak[i] = PseudoVoigtModel(prefix="p" + str(i) + "_")
            self.typec = "PVoigt"
Пример #3
0
def calc_center_pseudoVoigt(vx,vy):
    mod     = PseudoVoigtModel()
    y       = vy
    pars    = mod.guess(y, x=vx)
    out     = mod.fit(y, pars, x=vx)
    center  = out.best_values['center']
    return center
Пример #4
0
def make_model(peak_positions,
               fwhm=0.05,
               max_fwhm=0.5,
               pos_range=0.5,
               amplitude=1000.):
    n_peaks = len(peak_positions)
    pars = Parameters()

    bg = LinearModel(prefix='bg_')
    pars.update(bg.make_params(slope=0, intercept=0))

    mod = bg
    #pars['bg_intercept'].set(vary=True)
    #pars['bg_slope'].set(vary=True)

    for i in range(n_peaks):
        prefix = 'pk{}_'.format(i)
        peak = PseudoVoigtModel(prefix=prefix)
        # Set this zero
        pars.update(peak.make_params())
        pars[prefix + 'center'].set(peak_positions[i],
                                    min=peak_positions[i] - pos_range,
                                    max=peak_positions[i] + pos_range,
                                    vary=True)
        pars[prefix + 'sigma'].set(fwhm, min=0., max=max_fwhm, vary=True)
        pars[prefix + 'amplitude'].set(amplitude, min=0., vary=True)
        pars[prefix + 'fraction'].set(0.0, min=0., max=1., vary=True)
        mod += peak
    return mod, pars
Пример #5
0
 def guess_params(self, peak):
     """Guesses parameters for a new peak and adds it. See add_peak()."""
     if peak.region is not self._region:
         logger.error("peak with ID {} does not belong to region ID {}"
                      "".format(peak.ID, self._region.ID))
         raise ValueError("Peak does not belong to Region")
     if peak.model_name == "PseudoVoigt":
         model = PseudoVoigtModel(prefix=peak.prefix)
         # model.set_param_hint("fraction", vary=False)
     else:
         raise NotImplementedError("Only PseudoVoigt models supported")
     other_models_cps = [0] * len(self._region.energy)
     for other_peak in self._region.peaks:
         if other_peak == peak:
             continue
         other_models_cps += self.get_peak_cps(other_peak, peak.energy)
     y = self._region.cps - self._region.background - other_models_cps
     params = model.guess(y, x=peak.energy)
     self._params += params
     fwhmname = "{}fwhm".format(peak.prefix)
     sigmaname = "{}sigma".format(peak.prefix)
     ampname = "{}amplitude".format(peak.prefix)
     centername = "{}center".format(peak.prefix)
     params[fwhmname].set(value=params[fwhmname].value, vary=True, min=0)
     params[sigmaname].set(expr="{}/2".format(fwhmname))
     params[ampname].set(min=0)
     params[centername].set(min=0)
     self._single_models[peak.prefix] = model
Пример #6
0
def voigt_mod(N):
    '''
        Returns a model consisting of N pseudo-voigt curves
    '''
    # initialize model
    model = PseudoVoigtModel(prefix='voi1_')
    # Add N-1 pseudo-voigts
    for i in range(N - 1):
        model += PseudoVoigtModel(prefix='voi' + str(i + 2) + '_')
    return model
def fit_three_peaks(peak_data,
                    pv_1_cent=3.43,
                    pv_1_min=3.36,
                    pv_1_max=3.44,
                    pv_2_cent=3.52,
                    pv_2_min=3.42,
                    pv_2_max=3.55,
                    pv_3_cent=3.59,
                    pv_3_min=3.54,
                    pv_3_max=3.6,
                    initParams=None):
    """ Pseudo-Voigt fit to the lattice plane peak intensity for three peaks (adjust function to include more).
        Parameters for each peak also require limits and centres to be set in the case of overlapping peaks.
        Return results of the fit as an lmfit class, which contains the fitted parameters (amplitude, fwhm, etc.) 
        and the fit line calculated using the fit parameters and 100x two-theta points.
    """
    ttheta = peak_data[:, 0]
    intensity = peak_data[:, 1]

    PV_1 = PseudoVoigtModel(prefix='pv_1')
    PV_2 = PseudoVoigtModel(prefix='pv_2')
    PV_3 = PseudoVoigtModel(prefix='pv_3')

    model = PV_1 + PV_2 + PV_3 + Model(line)

    if initParams is None:
        # if reflection == '(0002),(110),(10-11)': use starting centres 3.43(min=3.36,max=3.44), 3.54(min=3.42,max=3.55), 3.59(min=3.54,max=3.6)...
        #if reflection == '(20-20),(11-22),(20-21)': use starting centres 6.32(min=6.23,max=6.33), 6.45(min=6.37,max=6.47), 6.54(min=6.46,max=6.56)...
        pars_1 = PV_1.guess(intensity, x=ttheta)
        #note, min and max values are not the same as bounds around the peak, but values that they can go up to!
        pars_1['pv_1center'].set(pv_1_cent, min=pv_1_min, max=pv_1_max)
        #pars_1['pv_1sigma'].set(min=0.001, max=0.1)
        #pars_1['pv_1amplitude'].set(min=0)
        #pars_1['pv_1height'].set(min=10)
        #pars_1['pv_1fwhm'].set(min=0.02, max=0.2)

        pars_2 = PV_2.guess(intensity, x=ttheta)
        pars_2['pv_2center'].set(pv_2_cent, min=pv_2_min, max=pv_2_max)
        #pars_2['pv_2sigma'].set(min=0.001, max=0.1)
        #pars_2['pv_2amplitude'].set(min=0)
        #pars_2['pv_2height'].set(min=10, max = 5000)
        #pars_2['pv_2fwhm'].set(min=0.02, max=0.2)

        pars_3 = PV_3.guess(intensity, x=ttheta)
        pars_3['pv_3center'].set(pv_3_cent, min=pv_3_min, max=pv_3_max)
        #pars_3['pv_3sigma'].set(min=0.001, max=0.1)
        #pars_3['pv_3amplitude'].set(min=1)
        #pars_3['pv_3height'].set(min=10)
        #pars_3['pv_3fwhm'].set(min=0.02, max=0.2)

        pars = pars_1 + pars_2 + pars_3
        pars.add("constBG", 0)

    else:
        pars = initParams
    fit_results = model.fit(intensity, pars, x=ttheta)
    fit_ttheta = np.linspace(ttheta[0], ttheta[-1], 100)
    fit_line = [fit_ttheta, model.eval(fit_results.params, x=fit_ttheta)]
    return fit_results, fit_line
Пример #8
0
def set_params(peaks):
    """
    This module takes in the list of peaks from the peak detection modules, and then uses
    that to initialize parameters for a set of Pseudo-Voigt models that are not yet fit.
    There is a single model for every peak.

    Args:
        peaks (list): A list containing the x and y-values (in tuples) of the peaks.

    Returns:
        mod (lmfit.models.PseudoVoigtModel or lmfit.model.CompositeModel): This is an array of
                        the initialized Pseudo-Voigt models. The array contains all of the values
                        that are found in `pars` that are fed to an lmfit lorentzian model class.
        pars (lmfit.parameter.Parameters): An array containing the parameters for each peak
                        that were generated through the use of a Lorentzian fit. The pars
                        array contains a center value, a height, a sigma, and an amplitude
                        value. The center value is allowed to vary +- 10 wavenumber from
                        the peak max that was detected in scipy. Some wiggle room was allowed
                        to help mitigate problems from slight issues in the peakdetect
                        algorithm for peaks that might have relatively flat maxima. The height
                        value was allowed to vary between 0 and 1, as it is assumed the y-values
                        are normalized. Sigma is set to a maximum of 500, as we found that
                        giving it an unbound maximum led to a number of peaks that were
                        unrealistic for Raman spectra (ie, they were far too broad, and shallow,
                        to correspond to real data. Finally, the amplitude for the peak was set
                        to a minimum of 0, to prevent negatives.
    """
    # handling errors in inputs
    if not isinstance(peaks, list):
        raise TypeError('Passed value of `peaks` is not a list! Instead, it is: '
                        + str(type(peaks)))
    for i, _ in enumerate(peaks):
        if not isinstance(peaks[i], tuple):
            raise TypeError("""Passed value of `peaks[{}]` is not a tuple.
             Instead, it is: """.format(i) + str(type(peaks[i])))
    peak_list = []
    for i, _ in enumerate(peaks):
        prefix = 'p{}_'.format(i+1)
        peak = PseudoVoigtModel(prefix=prefix)
        if i == 0:
            pars = peak.make_params()
        else:
            pars.update(peak.make_params())
        pars[prefix+'center'].set(peaks[i][0], vary=False)
        pars[prefix+'height'].set(peaks[i][1], vary=False)
        pars[prefix+'sigma'].set(50, min=0, max=500)
        pars[prefix+'amplitude'].set(min=0)
        peak_list.append(peak)
        if i == 0:
            mod = peak_list[i]
        else:
            mod = mod + peak_list[i]
    return mod, pars
Пример #9
0
def voigt(x, y):

	# Voigt fit to a curve

    x_shifted = x - x.min() # Shifting to 0
    y_shifted = y - y.min() # Shifting to 0    
    mod = PseudoVoigtModel() # Setting model type
    pars = mod.guess(y_shifted, x=x_shifted) # Estimating fit
    out = mod.fit(y_shifted, pars, x=x_shifted) # Fitting fit
    # print(out.fit_report(min_correl=0.25)) # Outputting best fit results
    print("Voigt FWHM = ", out.params['fwhm'].value) # Outputting only FWHM
    out.plot() # Plotting fit
Пример #10
0
def fit_one_Psudo_Voigt(x_lst,y_lst):
    '''
    Fits one Pseudo Voigt returns the 
    results object
    '''
    mod = PseudoVoigtModel(independent_vars=['x'],nan_policy='raise')
    
    x_lst = np.asarray(x_lst)
    y_lst = np.asarray(y_lst)
    # Guess good values computer
    mod.guess(y_lst,x = x_lst)
    
    result = mod.fit(y_lst, x = x_lst)
    
    return result
Пример #11
0
def test_figure_title_using_title_keyword_argument(peakdata):
    """Test setting figure title using title keyword argument."""
    x, y = peakdata
    pvmodel = PseudoVoigtModel()
    params = pvmodel.guess(y, x=x)
    result = pvmodel.fit(y, params, x=x)

    ax = result.plot_fit(title='test')
    assert ax.axes.get_title() == 'test'

    ax = result.plot_residuals(title='test')
    assert ax.axes.get_title() == 'test'

    fig, _ = result.plot(title='test')
    assert fig.axes[0].get_title() == 'test'
    assert fig.axes[1].get_title() == ''  # no title for fit subplot
Пример #12
0
def test_figure_default_title(peakdata):
    """Test default figure title."""
    x, y = peakdata
    pvmodel = PseudoVoigtModel()
    params = pvmodel.guess(y, x=x)
    result = pvmodel.fit(y, params, x=x)

    ax = result.plot_fit()
    assert ax.axes.get_title() == 'Model(pvoigt)'

    ax = result.plot_residuals()
    assert ax.axes.get_title() == 'Model(pvoigt)'

    fig, _ = result.plot()
    assert fig.axes[0].get_title() == 'Model(pvoigt)'  # default model.name
    assert fig.axes[1].get_title() == ''  # no title for fit subplot
Пример #13
0
def center_psi(file_name):
    #print(file_name)
    psi, vx, vy = read_file(file_name)
    vy = processing_of_data(psi,vx,vy)
    legenda = file_name.split('/')[-1]
    #plt.grid()
    #plt.legend(loc=0)
    #import pdb; pdb.set_trace()
    plt.plot(vx,vy,label=legenda)
    mod = PseudoVoigtModel()
    y=vy
    pars = mod.guess(y, x=vx)
    out  = mod.fit(y, pars, x=vx)
    center =out.best_values['center']
    print('center: {} <--> psi: {}'.format(center,psi))
    return psi, center
Пример #14
0
def set_params(peaks):
    """
    This function takes in the list of peaks from the peak detection modules, and then uses
    that to initialize parameters for a set of Pseudo-Voigt models that are not yet fit.
    There is a single model for every peak.

    Args:
        peaks (list): A list containing tuples of the x_data (wavenumber) and y_data (counts)
                      values of the peaks.

    Returns:
        mod (lmfit.models.PseudoVoigtModel or lmfit.model.CompositeModel): This is an array of
                        the initialized pseudo-Voigt models. The array contains all of the values
                        that are found in `pars` that are fed to an lmfit lorentzian model class.
        pars (lmfit.parameter.Parameters): An array containing the parameters for each peak
                        that were generated through the use of a Lorentzian fit. The pars
                        array contains values for fraction, center, height, sigma, the full width
                        at half maximum (fwhm = 2*sigma), and amplitude.
    """
    # handling errors in inputs
    if not isinstance(peaks, list):
        raise TypeError(
            'Passed value of `peaks` is not a list! Instead, it is: ' +
            str(type(peaks)))
    for i, peak in enumerate(peaks):
        if not isinstance(peak, tuple):
            raise TypeError("""The {} value of `peaks` is not a tuple.
             Instead, it is: """.format(i) + str(type(peak)))
    peak_list = []
    for i, value in enumerate(peaks):
        prefix = 'p{}_'.format(i + 1)
        peak = PseudoVoigtModel(prefix=prefix)
        if i == 0:
            pars = peak.make_params()
        else:
            pars.update(peak.make_params())
        # constraints on profile desciptors
        pars[prefix + 'center'].set(value[0], vary=False)
        pars[prefix + 'height'].set(min=0.1 * value[1])
        pars[prefix + 'sigma'].set(10, min=1, max=100)
        pars[prefix + 'amplitude'].set(100 * value[1], min=0)
        peak_list.append(peak)
        if i == 0:
            mod = peak_list[i]
        else:
            mod = mod + peak_list[i]
    return mod, pars
Пример #15
0
def fit_data(x, y, xmin=None, xmax=None):

    if y is None:
        return "No spectrum! Fit not performed!"
    else:

        if xmin is None:
            xmin = x.min()
        elif xmin < x.min():
            xmin = x.min()

        if xmax is None:
            xmax = x.max()
        elif xmax < x.max():
            xmax = x.max()

        y = np.copy(y[np.logical_and(x > xmin, x < xmax)])
        x = np.copy(x[np.logical_and(x > xmin, x < xmax)])

        x, y = remove_spike(y, x=x)

        mod = (ConstantModel() + PseudoVoigtModel(prefix="peak1_") +
               PseudoVoigtModel(prefix="peak2_"))
        params = mod.make_params()

        ymax_ind = np.argmax(y)
        xmax = x[ymax_ind]

        params["c"].set(0)
        params.add("psplit", value=1.5, vary=True, min=0.5, max=2.0)

        params["peak2_center"].set(xmax, min=xmax - 0.5, max=x.max())
        params["peak2_sigma"].set(0.5, min=0.01)
        params["peak2_amplitude"].set(y[ymax_ind] * 0.5 * np.sqrt(2 * np.pi),
                                      min=0)
        params["peak2_fraction"].set(0.5, min=0, max=1)

        params["peak1_center"].set(vary=False, expr="peak2_center-psplit")
        params["peak1_sigma"].set(0.5, min=0.01)
        params["peak1_amplitude"].set(y[ymax_ind] * 0.5 * np.sqrt(2 * np.pi) /
                                      2,
                                      min=0)
        params["peak1_fraction"].set(0.5, min=0, max=1)

        fit = mod.fit(y, params, x=x)

        return fit
Пример #16
0
def fit_experimental_data_gauss(exp_x,
                                exp_y,
                                expected_peak_pos,
                                deg_of_bck_poly=5,
                                maxfev=25000):
    num_of_peaks = len(expected_peak_pos)
    mod = PolynomialModel(deg_of_bck_poly, prefix='poly_')
    for c in range(num_of_peaks):
        mod = mod + PseudoVoigtModel(prefix='p{}_'.format(c))

    params = mod.make_params()

    center = 0
    sigma = 0
    amplitude = 0
    fraction = 0
    for param in params:
        if 'center' in param:
            params[param].set(value=expected_peak_pos[center])
            params[param].set(min=expected_peak_pos[center] - 0.5)
            params[param].set(max=expected_peak_pos[center] + 0.5)
            center += 1
        if 'poly' in param:
            if param == 'poly_c0':
                params[param].set(value=50)
                params[param].set(min=-100)
                params[param].set(max=100)
                continue
            if param == 'poly_c1':
                params[param].set(value=-1)
                params[param].set(min=-100)
                params[param].set(max=100)
                continue
            params[param].set(value=0)


##            params[param].set(min = 3e-1)
##            params[param].set(max = 3e-1)
        if 'sigma' in param:
            params[param].set(value=0.5)
            params[param].set(min=0.0001)
            params[param].set(max=0.8)
            sigma += 1
        if 'amplitude' in param:
            params[param].set(value=5.5)
            params[param].set(min=0.0001)
            amplitude += 1
        if 'fraction' in param:
            params[param].set(value=0.0)
            params[param].set(min=0.000)
            params[param].set(max=0.000001)
            fraction += 1
    result = mod.fit(np.asarray(exp_y),
                     params,
                     x=np.asarray(exp_x),
                     fit_kws={'maxfev': maxfev})

    print(result.fit_report())
    return result
Пример #17
0
def methodfunciont(key):
    dic = {
        "VoigtModel": VoigtModel(),
        "PseudoVoigtModel": PseudoVoigtModel(),
        "GaussianModel": GaussianModel()
    }

    return dic[key]
Пример #18
0
 def prepare_for_fitting(self, poly_order, maxwidth, centerrange):
     """
     :param x_center: numpy array of initial x values at picked centers
     :param y_center: numpy array of initial y values at picked centers
     :param fwhm: single float number for initial fwhm value
     """
     self.set_baseline(poly_order)
     baseline_mod = PolynomialModel(poly_order, prefix='b_')
     mod = baseline_mod
     pars = baseline_mod.make_params()
     peakinfo = {}
     for i in range(poly_order + 1):
         prefix = "b_c{0:d}".format(i)
         pars[prefix].set(value=self.baseline_in_queue[i]['value'],
                          vary=self.baseline_in_queue[i]['vary'])
     i = 0
     for peak in self.peaks_in_queue:
         prefix = "p{0:d}_".format(i)
         peak_mod = PseudoVoigtModel(prefix=prefix, )
         pars.update(peak_mod.make_params())
         pars[prefix + 'center'].set(value=peak['center'],
                                     min=peak['center'] - centerrange,
                                     max=peak['center'] + centerrange,
                                     vary=peak['center_vary'])
         pars[prefix + 'sigma'].set(value=peak['sigma'],
                                    min=0.0,
                                    vary=peak['sigma_vary'],
                                    max=maxwidth)
         pars[prefix + 'amplitude'].set(value=peak['amplitude'],
                                        min=0,
                                        vary=peak['amplitude_vary'])
         pars[prefix + 'fraction'].set(value=peak['fraction'],
                                       min=0.,
                                       max=1.,
                                       vary=peak['fraction_vary'])
         peakinfo[prefix + 'phasename'] = peak['phasename']
         peakinfo[prefix + 'h'] = peak['h']
         peakinfo[prefix + 'k'] = peak['k']
         peakinfo[prefix + 'l'] = peak['l']
         mod += peak_mod
         i += 1
     self.parameters = pars
     self.peakinfo = peakinfo
     self.fit_model = mod
def fit_peak(peak_data, initParams=None):
    """ Pseudo-Voigt fit to the lattice plane peak intensity.
        Return results of the fit as an lmfit class, which contains the fitted parameters (amplitude, fwhm, etc.) 
        and the fit line calculated using the fit parameters and 100x two-theta points.
    """
    ttheta = peak_data[:, 0]
    intensity = peak_data[:, 1]
    pvModel = PseudoVoigtModel()
    model = pvModel + Model(line)
    if initParams is None:
        pars = pvModel.guess(intensity, x=ttheta)
        pars['sigma'].set(min=0.01, max=1)  #sigma is the width?
        pars['amplitude'].set(min=0.05)
        pars.add("constBG", 0)
    else:
        pars = initParams
    fit_results = model.fit(intensity, pars, x=ttheta)
    fit_ttheta = np.linspace(ttheta[0], ttheta[-1], 100)
    fit_line = [fit_ttheta, model.eval(fit_results.params, x=fit_ttheta)]
    return fit_results, fit_line
Пример #20
0
def test_figure_title_using_title_to_ax_kws(peakdata):
    """Test setting figure title by supplying ax_{fit,res}_kws."""
    x, y = peakdata
    pvmodel = PseudoVoigtModel()
    params = pvmodel.guess(y, x=x)
    result = pvmodel.fit(y, params, x=x)

    ax = result.plot_fit(ax_kws={'title': 'ax_kws'})
    assert ax.axes.get_title() == 'ax_kws'

    ax = result.plot_residuals(ax_kws={'title': 'ax_kws'})
    assert ax.axes.get_title() == 'ax_kws'

    fig, _ = result.plot(ax_res_kws={'title': 'ax_res_kws'})
    assert fig.axes[0].get_title() == 'ax_res_kws'
    assert fig.axes[1].get_title() == ''

    fig, _ = result.plot(ax_fit_kws={'title': 'ax_fit_kws'})
    assert fig.axes[0].get_title() == 'Model(pvoigt)'  # default model.name
    assert fig.axes[1].get_title() == ''  # no title for fit subplot
Пример #21
0
def test_priority_setting_figure_title(peakdata):
    """Test for setting figure title: title keyword argument has priority."""
    x, y = peakdata
    pvmodel = PseudoVoigtModel()
    params = pvmodel.guess(y, x=x)
    result = pvmodel.fit(y, params, x=x)

    ax = result.plot_fit(ax_kws={'title': 'ax_kws'}, title='test')
    assert ax.axes.get_title() == 'test'

    ax = result.plot_residuals(ax_kws={'title': 'ax_kws'}, title='test')
    assert ax.axes.get_title() == 'test'

    fig, _ = result.plot(ax_res_kws={'title': 'ax_res_kws'}, title='test')
    assert fig.axes[0].get_title() == 'test'
    assert fig.axes[1].get_title() == ''

    fig, _ = result.plot(ax_fit_kws={'title': 'ax_fit_kws'}, title='test')
    assert fig.axes[0].get_title() == 'test'
    assert fig.axes[1].get_title() == ''
Пример #22
0
    def double_voigt(self, sepPt=None, pars: list = None, bounds: list = None):
        if sepPt == None: sepPt = find_separation_point(self.x, self.y)

        x1 = self.x[self.x < sepPt]
        x2 = self.x[self.x > sepPt]
        y1 = self.y[self.x < sepPt]
        y2 = self.y[self.x > sepPt]

        mod1 = PseudoVoigtModel(prefix='v1_')
        mod2 = PseudoVoigtModel(prefix='v2_')

        if pars == None:
            pars1 = self.guess_pars(self, mod1, x1, y1, prefix='v1_')
            pars2 = self.guess_pars(self, mod2, x2, y2, prefix='v2_')

        mod = mod1 + mod2
        pars = mod.make_params()
        pars.update(pars1)
        pars.update(pars2)

        return self.finish_fit(self, mod, pars)
Пример #23
0
    def test_model_nan_policy(self):
        x = np.linspace(0, 10, 201)
        np.random.seed(0)
        y = gaussian(x, 10.0, 6.15, 0.8)
        y += gaussian(x, 8.0, 6.35, 1.1)
        y += gaussian(x, 0.25, 6.00, 7.5)
        y += np.random.normal(size=len(x), scale=0.5)

        y[55] = y[91] = np.nan
        mod = PseudoVoigtModel()
        params = mod.make_params(amplitude=20, center=5.5,
                                 sigma=1, fraction=0.25)
        params['fraction'].vary = False
        # with raise, should get a ValueError
        result = lambda: mod.fit(y, params, x=x, nan_policy='raise')
        self.assertRaises(ValueError, result)

        # with propagate, should get no error, but bad results
        result = mod.fit(y, params, x=x, nan_policy='propagate')
        self.assertTrue(result.success)
        self.assertTrue(np.isnan(result.chisqr))
        self.assertTrue(np.isnan(result.aic))
        self.assertFalse(result.errorbars)
        self.assertTrue(result.params['amplitude'].stderr is None)
        self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 0.001)

        # with omit, should get good results
        result = mod.fit(y, params, x=x, nan_policy='omit')
        self.assertTrue(result.success)
        self.assertTrue(result.chisqr > 2.0)
        self.assertTrue(result.aic < -100)
        self.assertTrue(result.errorbars)
        self.assertTrue(result.params['amplitude'].stderr > 0.1)
        self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 5.0)
        self.assertTrue(abs(result.params['center'].value - 6.0) < 0.5)
Пример #24
0
    def test_model_nan_policy(self):
        """Tests for nan_policy with NaN values in the input data."""
        x = np.linspace(0, 10, 201)
        np.random.seed(0)
        y = gaussian(x, 10.0, 6.15, 0.8)
        y += gaussian(x, 8.0, 6.35, 1.1)
        y += gaussian(x, 0.25, 6.00, 7.5)
        y += np.random.normal(size=len(x), scale=0.5)

        # with NaN values in the input data
        y[55] = y[91] = np.nan
        mod = PseudoVoigtModel()
        params = mod.make_params(amplitude=20,
                                 center=5.5,
                                 sigma=1,
                                 fraction=0.25)
        params['fraction'].vary = False

        # with raise, should get a ValueError
        result = lambda: mod.fit(y, params, x=x, nan_policy='raise')
        msg = (
            'NaN values detected in your input data or the output of your '
            'objective/model function - fitting algorithms cannot handle this!'
        )
        self.assertRaisesRegex(ValueError, msg, result)

        # with propagate, should get no error, but bad results
        result = mod.fit(y, params, x=x, nan_policy='propagate')
        self.assertTrue(result.success)
        self.assertTrue(np.isnan(result.chisqr))
        self.assertTrue(np.isnan(result.aic))
        self.assertFalse(result.errorbars)
        self.assertTrue(result.params['amplitude'].stderr is None)
        self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 0.001)

        # with omit, should get good results
        result = mod.fit(y, params, x=x, nan_policy='omit')
        self.assertTrue(result.success)
        self.assertTrue(result.chisqr > 2.0)
        self.assertTrue(result.aic < -100)
        self.assertTrue(result.errorbars)
        self.assertTrue(result.params['amplitude'].stderr > 0.1)
        self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 5.0)
        self.assertTrue(abs(result.params['center'].value - 6.0) < 0.5)

        # with 'wrong_argument', should get a ValueError
        err_msg = r"nan_policy must be 'propagate', 'omit', or 'raise'."
        with pytest.raises(ValueError, match=err_msg):
            mod.fit(y, params, x=x, nan_policy='wrong_argument')
Пример #25
0
    def fitXY(self):
        #self.analyze ()
        #self.amplitude1 = self.maxval - self.minval
        #self.amplitude2 = .6 * self.amplitude1

        peak1 = PseudoVoigtModel(prefix='p1_')
        peak2 = PseudoVoigtModel(prefix='p2_')
        basef = LinearModel()
        model = peak1 + peak2 + basef
        params = model.make_params(p1_center=self.sample_position,
                                   p2_center=self.sample_position - 1.5,
                                   p1_amplitude=self.amplitude1,
                                   p2_amplitude=self.amplitude1 * 0.6,
                                   p1_sigma=0.25,
                                   p2_sigma=0.25,
                                   p1_fraction=0.8,
                                   p2_fraction=0.8,
                                   slope=0,
                                   intercept=self.minval)
        result = model.fit(self.ydata, x=self.wave, **params)
        self.modelFit = result.best_fit
        bfd = result.best_values
        self.fitParams = [
            bfd['p1_amplitude'], bfd['p1_center'], bfd['p1_sigma'],
            bfd['p1_fraction'], bfd['p2_amplitude'], bfd['p2_center'],
            bfd['p2_sigma'], bfd['p2_fraction'], bfd['slope'], bfd['intercept']
        ]
        self.oparams1[0] = bfd['p1_amplitude']
        self.oparams1[1] = bfd['p1_center']
        self.oparams1[2] = bfd['p1_sigma']
        self.oparams1[3] = bfd['p1_fraction']
        self.oparams2[0] = bfd['p2_amplitude']
        self.oparams2[1] = bfd['p2_center']
        self.oparams2[2] = bfd['p2_sigma']
        self.oparams2[3] = bfd['p2_fraction']
        self.oparams3[0] = bfd['slope']
        self.oparams3[1] = bfd['intercept']

        self.fitDone.emit()
Пример #26
0
 def add_peak(self, peak):
     """Adds a new Peak to the Model list."""
     if peak.region is not self._region:
         logger.error("peak with ID {} does not belong to region ID {}"
                      "".format(peak.ID, self._region.ID))
         raise ValueError("Peak does not belong to Region")
     if peak.model_name == "PseudoVoigt":
         model = PseudoVoigtModel(prefix=peak.prefix)
         model.set_param_hint("fraction", vary=False, value=0.2)
         params = model.make_params()
     else:
         raise NotImplementedError("Only PseudoVoigt models supported")
     self._params += params
     fwhmname = "{}fwhm".format(peak.prefix)
     sigmaname = "{}sigma".format(peak.prefix)
     ampname = "{}amplitude".format(peak.prefix)
     centername = "{}center".format(peak.prefix)
     params[fwhmname].set(value=params[fwhmname].value, vary=True, min=0)
     params[sigmaname].set(expr="{}/2".format(fwhmname))
     params[ampname].set(min=0)
     params[centername].set(min=0)
     self._single_models[peak.prefix] = model
Пример #27
0
def fit_voigt(xp: XPS_experiment,
              region: str,
              prefix: str = 'v_',
              pars: list = None,
              bounds: list = None,
              ax=None,
              flag_plot: bool = True):
    """General method for fitting voigt model
        Input
        ----------
        xp : class XPS_experiment
            XPS data
        region : str
            core level name
        pars, bounds : list
            initial guess of the fit parameters and bounds. If unspecified, guessed automatically
        Returns
        -----------
        fitv : lmfit.model
            fit result to Voigt model
    """
    from lmfit.models import PseudoVoigtModel, GaussianModel

    x = xp.dfx[region].dropna().energy
    y = xp.dfx[region].dropna().counts

    mod = PseudoVoigtModel(prefix=prefix)
    if pars == None:
        pars = mod.guess(y, x=x)
        pars[prefix + 'sigma'].set(value=1)  # Usually guessed wrong anyway
        pars[prefix + 'fraction'].set(value=0.2, min=0.15, max=0.20)

    fitv = mod.fit(y, pars, x=x)
    xp.fit.update({region: fitv})

    if flag_plot:
        hatchplot_fit(xp, region, fitv, ax=ax, plot_comps=True)
    return fitv
def prepareFittingModels(roiCoordsList, modelType):
    modelList = []
    paramList = []
    index = 1
    for region in roiCoordsList:
        individualModelsList = []
        individualParamsList = []
        if isinstance(region, dict):
            # If the region is just a single region, make it a list so the for loops pulls a dict rather than a dict entry
            region = [region]
        for entry in region:
            prefixName = 'v' + str(index) + '_'
            index += 1
            # pull info out of region dict
            selectedXVals = entry['x']
            selectedYVals = entry['y']

            mod = None
            if modelType.lower() == 'voigt':
                mod = VoigtModel(prefix=prefixName)
            elif modelType.lower() == 'psuedovoigt':
                mod = PseudoVoigtModel(prefix=prefixName)
            elif modelType.lower() == 'lorentzian':
                mod = LorentzianModel(prefix=prefixName)
            elif modelType.lower() == 'gaussian':
                mod = GaussianModel(prefix=prefixName)
            elif modelType.lower() == 'pearsonvii':
                mod = Pearson7Model(prefix=prefixName)

            assert mod, "Entered model type is not supported"
            individualModelsList.append(mod)
            pars = mod.guess(selectedYVals, x=selectedXVals, negative=False)
            pars[prefixName + 'center'].set(min=min(selectedXVals), max=max(selectedXVals))
            pars[prefixName + 'amplitude'].set(min=0)
            pars[prefixName + 'sigma'].set(min=0)
            if modelType.lower() == 'voigt':
                pars[prefixName + 'gamma'].set(value=0.3, vary=True, expr='', min=0)
            individualParamsList.append(pars)
        combinedModel = individualModelsList[0]
        combinedParams = individualParamsList[0]
        if len(individualModelsList) > 1:
            for model, params in zip(individualModelsList[1:], individualParamsList[1:]):
                combinedModel += model
                combinedParams += params
        modelList.append(combinedModel)
        paramList.append(combinedParams)
    return modelList, paramList
Пример #29
0
 def test_param_hint_explicit_value(self):
     # tests Github Issue 384
     pmod = PseudoVoigtModel()
     params = pmod.make_params(sigma=2, fraction=0.77)
     assert_allclose(params['fraction'].value, 0.77, rtol=0.01)
Пример #30
0
def fitMo3d(filename, groupNo, regionNo, E_b_min, E_b_max, doplot=False):
    """Fit a Moly 3d signal using elemental and oxide components (two for each peak, 3/2 and 5/2).
    A shirley background is subtracted first.
    The elemental Mo components are fittet to the PseudoVoigt line shape.
    Oxide components are fitted to a Gaussian line shape.

    Parameters
    ----------
    filename : string
        location of the data file, expects an SpecsLab xml file.
    groupNo : int
        index of the group of spectra (from 0)
    regionNo : int
        index of the spectrum that should be fitted (from 0)
    E_b_min : float
        region boundary
    E_b_max : float
        region boundary
    doplot : bool
        wether or not to plot the fit and components (default False)
    """

    #load data from SpecsLab xml file and select region
    region = get_region(filename, groupNo, regionNo)

    # determine index of left and right boundary
    index1 = np.where(abs(region.x_be - (E_b_min)) < 1e-10)
    index2 = np.where(abs(region.x_be - (E_b_max)) < 1e-10)

    E = region.x_be[index1[0][0]:index2[0][0]]  #binding energy scale
    s = region.y_avg_counts_mcd[index1[0][0]:index2[0][0]]  #signal

    #signal with background substacted
    epsilon, sb, B = remove_shirley_background(s, E, 3, 1e-6)

    ######################
    # set up model components and set constraints for the fit
    ######################

    pre11 = 'Mo3d_32_1_'
    mod11 = PseudoVoigtModel(prefix=pre11)
    pars = mod11.make_params()
    pars.add('delta', value=3, min=2, max=4)
    pars[pre11 + 'amplitude'].set(9000, min=500, max=100000)
    pars[pre11 + 'center'].set(-231.2, min=-231.4, max=-231)
    pars[pre11 + 'sigma'].set(0.3, min=0.1, max=0.4)
    pars[pre11 + 'fraction'].set(0.5, min=0.1, max=1)

    mod21 = PseudoVoigtModel(prefix='Mo3d_52_1_')
    pars.update(mod21.make_params())
    pars['Mo3d_52_1_amplitude'].set(
        expr='3/2*Mo3d_32_1_amplitude')  #(12000, min=500, max=100000)
    pars['Mo3d_52_1_center'].set(expr='Mo3d_32_1_center+delta'
                                 )  #same distance between 3/2 and 5/2 peaks
    #pars['Mo3d_52_1_sigma'    ].set(expr='1.0*Mo3d_32_1_sigma') #all have same sigma value
    pars['Mo3d_52_1_fraction'].set(
        expr='1.0*Mo3d_32_1_fraction')  #(0.5, min=0.2, max=1)

    pre12 = 'MoO23d_32_2_'
    mod12 = GaussianModel(prefix=pre12)
    pars.update(mod12.make_params())
    pars[pre12 + 'amplitude'].set(2050, min=500, max=100000)
    pars[pre12 + 'center'].set(-234.5, min=-236, max=-234)
    pars[pre12 + 'sigma'].set(0.3, min=0.2, max=2)

    pre22 = 'MoO23d_52_2_'
    mod22 = GaussianModel(prefix=pre22)
    pars.update(mod22.make_params())
    pars[pre22 + 'amplitude'].set(
        expr='3/2*MoO23d_32_2_amplitude')  #(1050, min=500, max=100000)
    pars[pre22 + 'center'].set(expr='MoO23d_32_2_center+delta'
                               )  #same distance between 3/2 and 5/2 peaks
    pars[pre22 + 'sigma'].set(
        expr='1.0*MoO23d_32_2_sigma')  #all have same sigma value

    pre13 = 'MoO23d_32_3_'
    mod13 = GaussianModel(prefix=pre13)
    pars.update(mod13.make_params())
    pars[pre13 + 'amplitude'].set(2050, min=500, max=100000)
    pars[pre13 + 'center'].set(-235.5, min=-237, max=-234)
    pars[pre13 + 'sigma'].set(0.3, min=0.2, max=2)

    pre23 = 'MoO23d_52_3_'
    mod23 = GaussianModel(prefix=pre23)
    pars.update(mod23.make_params())
    pars[pre23 + 'amplitude'].set(
        expr='3/2*MoO23d_32_3_amplitude')  #(1050, min=500, max=100000)
    pars[pre23 + 'center'].set(expr='MoO23d_32_3_center+delta'
                               )  #same distance between 3/2 and 5/2 peaks
    pars[pre23 + 'sigma'].set(
        expr='1.0*MoO23d_32_3_sigma')  #all have same sigma value

    #composite model is a sum of the components
    mod = mod11 + mod21 + mod12 + mod22 + mod13 + mod23
    #perform the fit
    out = mod.fit(sb, pars, x=E)
    print(out.fit_report(min_correl=0.25))

    if (doplot):
        fig = plt.figure(None, figsize=(6, 4))
        #plot individual components
        comps = mod.eval_components(params=out.params, x=E)

        labels = [
            'Mo', 'Mo', 'MoO$_3$', 'MoO$_3$', 'MoO$_2$', 'MoO$_2$', 'MoO$_2$',
            'MoO$_2$'
        ]

        for n, key in enumerate(comps):
            if ((n % 2) == 0):
                plt.plot(-E,
                         comps[key] / 10**3,
                         color=colors[n],
                         label=labels[n])
            else:
                plt.plot(-E, comps[key] / 10**3, color=colors[n - 1])
                #plt.fill_between(-E, 0.0, comps[key]/10**3, facecolor=colors[int(i/2)], alpha=0.5)

        #plot measured signal (dots) and best fit (sum of components)
        plt.plot(-E, sb / 10**3, 'k.', label='measurement')
        #plt.plot( -E , s/10**3 , 'k-')
        #plt.plot( -E , B/10**3 , 'k--')
        plt.plot(-E, out.best_fit / 10**3, color=colors[1], label='total fit')
        ax = mpl.pyplot.gca()
        ax.set_xlim(241, -E_b_max)
        plt.xlabel('binding energy (eV)')
        plt.ylabel('counts (arb. u.)')

        print(out.best_values['MoO23d_32_2_center'] -
              out.best_values['Mo3d_32_1_center'])
        print(out.best_values['MoO23d_32_3_center'] -
              out.best_values['Mo3d_32_1_center'])

        ## reference : also plot pure Mo signal
        #load data from SpecsLab xml file and select region
        region = get_region(filename, 3, 2)

        # determine index of left and right boundary
        index1 = np.where(abs(region.x_be - (-235)) < 1e-10)
        index2 = np.where(abs(region.x_be - (E_b_max)) < 1e-10)

        E = region.x_be[index1[0][0]:index2[0][0]]  #binding energy scale
        s = region.y_avg_counts_mcd[index1[0][0]:index2[0][0]]  #signal

        epsilon, sb, B = remove_shirley_background(s, E, 3, 1e-6)
        plt.plot(-E, sb / (6 * 10**3), 'k--', label='pure Mo')
        plt.legend()

        fig.tight_layout()
Пример #31
0
def fitpureMo3d(filename, groupNo, regionNo, E_b_min, E_b_max, doplot=False):
    """Fit a Moly 3d signal using elemental and oxide components (two for each peak, 3/2 and 5/2).
    A shirley background is subtracted first.
    The elemental Mo components are fittet to the PseudoVoigt line shape.
    Oxide components are fitted to a Gaussian line shape.

    Parameters
    ----------
    filename : string
        location of the data file, expects an SpecsLab xml file.
    groupNo : int
        index of the group of spectra (from 0)
    regionNo : int
        index of the spectrum that should be fitted (from 0)
    E_b_min : float
        region boundary
    E_b_max : float
        region boundary
    doplot : bool
        wether or not to plot the fit and components (default False)
    """

    #load data from SpecsLab xml file and select region
    region = get_region(filename, groupNo, regionNo)

    #Sb = VAMAS.VAMASExperiment('P006_Sb_surveyf.vms');
    #regions = [data[0][2], data[1][1], data[2][1]]
    print(region.x_be)

    # determine index of left and right boundary
    index1 = np.where(abs(region.x_be - (E_b_min)) < 1e-10)
    index2 = np.where(abs(region.x_be - (E_b_max)) < 1e-10)

    E = region.x_be[index1[0][0]:index2[0][0]]  #binding energy scale
    s = region.y_avg_counts_mcd[index1[0][0]:index2[0][0]]  #signal

    #signal with background substacted
    epsilon, sb, B = remove_shirley_background(s, E, 3, 1e-6)

    ######################
    # set up model components and set constraints for the fit
    ######################

    pre11 = 'Mo3d_32_1_'
    mod11 = PseudoVoigtModel(prefix=pre11)
    pars = mod11.make_params()
    pars.add('delta', value=3, min=2, max=5)
    pars[pre11 + 'amplitude'].set(9000, min=500, max=100000)
    pars[pre11 + 'center'].set(-231, min=-231, max=-230)
    pars[pre11 + 'sigma'].set(0.3, min=0.2, max=1)
    pars[pre11 + 'fraction'].set(0.5, min=0.2, max=1)

    mod21 = PseudoVoigtModel(prefix='Mo3d_52_1_')
    pars.update(mod21.make_params())
    pars['Mo3d_52_1_amplitude'].set(
        expr='3/2*Mo3d_32_1_amplitude')  #(12000, min=500, max=100000)
    pars['Mo3d_52_1_center'].set(expr='Mo3d_32_1_center+delta'
                                 )  #same distance between 3/2 and 5/2 peaks
    #pars['Mo3d_52_1_sigma'    ].set(expr='1.0*Mo3d_32_1_sigma') #all have same sigma value
    pars['Mo3d_52_1_fraction'].set(
        expr='1.0*Mo3d_32_1_fraction')  #(0.5, min=0.2, max=1)

    #composite model is a sum of the components
    mod = mod11 + mod21
    #perform the fit
    out = mod.fit(sb, pars, x=E)

    if (doplot):
        plt.figure()
        #plot individual components
        comps = mod.eval_components(params=out.params, x=E)
        i = 0
        for key in comps:
            plt.plot(E, comps[key] / 10**3, color=colors[i], label=key)
            plt.fill_between(E,
                             0.0,
                             comps[key] / 10**3,
                             facecolor=colors[i],
                             alpha=0.5)
            i = i + 1

        #plot measured signal (dots) and best fit (sum of components)
        plt.plot(E, sb / 10**3, 'k.')
        plt.plot(E, s / 10**3, 'k-')
        plt.plot(E, B / 10**3, 'k--')
        plt.plot(E, out.best_fit / 10**3, color=colors[1])
        plt.legend()
        ax = mpl.pyplot.gca()
        ax.set_xlim(E_b_min, E_b_max)
        plt.xlabel('binding energy (eV)')
        plt.ylabel('cps ($10^3$)')
    print(out.fit_report(min_correl=0.25))
Пример #32
0
 def test_param_hint_explicit_value(self):
     # tests Github Issue 384
     pmod = PseudoVoigtModel()
     params = pmod.make_params(sigma=2, fraction=0.77)
     assert_allclose(params['fraction'].value, 0.77, rtol=0.01)