示例#1
0
    def voigt_response(self, sigma=None, gamma=None, weights=True):
        '''
        Fit the background with a Voigt profile to determine the response
        of the spectrometer

        If you have a good, clear signal, set sigma and gamma to None (done by default)

        If your signal is poor, set sigma and gamma using a fit to a good signal, and then
        only the position of the central wavelength will be altered.
        '''
        vm = VoigtModel()
        par_v = vm.guess(self.bkgd, x=self.lamb)
        par_v['center'].set(value=532e-9, vary=True)
        if sigma is not None:  #if a width is provided, fix it.
            par_v['sigma'].set(value=sigma, vary=False)
        if gamma is not None:  #if a width is provided, fix it.
            par_v['gamma'].set(value=gamma, vary=False, expr='')
        elif gamma is None:  #vary gamma for better fit - this is not done by default
            par_v['gamma'].set(value=par_v['sigma'].value, vary=True, expr='')

        ##Fit the Voigt Model to the data
        if weights is True:
            weights = self.bkgd / self.bkgd_err
        if weights is False:
            weights = np.ones_like(self.bkgd)
        self.vm_fit = vm.fit(self.bkgd, par_v, x=self.lamb, weights=weights)
        self.l0 = self.vm_fit.best_values['center']
        self.sigma = self.vm_fit.best_values['sigma']
示例#2
0
def test_param_set():
    np.random.seed(2015)
    x = np.arange(0, 20, 0.05)
    y = gaussian(x, amplitude=15.43, center=4.5, sigma=2.13)
    y = y + 0.05 - 0.01*x + np.random.normal(scale=0.03, size=len(x))

    model  = VoigtModel()
    params = model.guess(y, x=x)

    # test #1:  gamma is constrained to equal sigma
    sigval = params['gamma'].value
    assert(params['gamma'].expr == 'sigma')
    assert_allclose(params['gamma'].value, sigval, 1e-4, 1e-4, '', True)

    # test #2: explicitly setting a param value should work, even when
    #          it had been an expression.  The value will be left as fixed
    gamval = 0.87543
    params['gamma'].set(value=gamval)
    assert(params['gamma'].expr is None)
    assert(not params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)

    # test #3: explicitly setting an expression should work
    params['gamma'].set(expr='sigma/2.0')
    assert(params['gamma'].expr is not None)
    assert(not params['gamma'].vary)
    assert_allclose(params['gamma'].value, sigval/2.0, 1e-4, 1e-4, '', True)

    # test #4: explicitly setting a param value WITH vary=True
    #          will set it to be variable
    gamval = 0.7777
    params['gamma'].set(value=gamval, vary=True)
    assert(params['gamma'].expr is None)
    assert(params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)
示例#3
0
def test_numdifftools_calc_covar_false():
    pytest.importorskip("numdifftools")
    # load data to be fitted
    data = np.loadtxt(
        os.path.join(os.path.dirname(__file__), '..', 'examples',
                     'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['sigma'].set(min=-np.inf)

    # do fit, with leastsq and nelder
    result = mod.fit(y, params, x=x, method='leastsq')
    result_ndt = mod.fit(y, params, x=x, method='nelder', calc_covar=False)

    # assert that fit converged to the same result
    vals = [result.params[p].value for p in result.params.valuesdict()]
    vals_ndt = [
        result_ndt.params[p].value for p in result_ndt.params.valuesdict()
    ]
    assert_allclose(vals_ndt, vals, rtol=5e-3)
    assert_allclose(result_ndt.chisqr, result.chisqr)

    assert result_ndt.covar is None
    assert result_ndt.errorbars is False
示例#4
0
def test_bounds_expression():
    # load data to be fitted
    data = np.loadtxt(os.path.join(os.path.dirname(__file__), '..', 'examples',
                                   'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['amplitude'].set(min=0, max=100)
    params['center'].set(min=5, max=10)

    # do fit, here with leastsq model
    result = mod.fit(y, params, x=x)

    # assert that stderr and correlations are correct [cf. lmfit v0.9.10]
    assert_almost_equal(result.params['sigma'].stderr, 0.00368468, decimal=6)
    assert_almost_equal(result.params['center'].stderr, 0.00505496, decimal=6)
    assert_almost_equal(result.params['amplitude'].stderr, 0.13861506,
                        decimal=6)
    assert_almost_equal(result.params['gamma'].stderr, 0.00368468, decimal=6)
    assert_almost_equal(result.params['fwhm'].stderr, 0.00806917, decimal=6)
    assert_almost_equal(result.params['height'].stderr, 0.03009459, decimal=6)

    assert_almost_equal(result.params['sigma'].correl['center'],
                        -4.6623973788006615e-05, decimal=6)
    assert_almost_equal(result.params['sigma'].correl['amplitude'],
                        0.651304091954038, decimal=6)
    assert_almost_equal(result.params['center'].correl['amplitude'],
                        -4.390334984618851e-05, decimal=6)
    def get_model(self):

        self.x = np.array([0, 1, 2, 6, 12, 24])
        self.y = np.array(self.norm_vals)

        # Compound model with Voigt curve.
        self.background = ExponentialModel(prefix='b_')
        self.pars = self.background.guess(self.y, x=self.x)
        self.peak = VoigtModel(prefix='p_')
        self.pars += self.peak.guess(self.y, x=self.x)
        self.comp_mod = self.peak + self.background
        self.init = self.comp_mod.eval(self.pars, x=self.x)
        self.comp_out = self.comp_mod.fit(
            self.y, x=self.x,
            fit_kws={'nan_policy': 'propagate'
                     })  # instead of 'omit', it keeps up the zero vals.
        self.comp_list = self.comp_out.fit_report().split('\n')
        self.comp_chisq = float(self.comp_list[6][-5:])

        self.out = self.comp_out
        self.chisq = float(self.comp_list[6][-5:])
        self.usedmod = self.comp_mod
        self.model_flag = "composite (exponential+Voigt)"

        return self.comp_out, self.comp_chisq, self.out, self.chisq, self.usedmod, self.model_flag
示例#6
0
def test_bounds_expression():
    # load data to be fitted
    data = np.loadtxt(os.path.join(os.path.dirname(__file__), '..', 'examples',
                                   'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['amplitude'].set(min=0, max=100)
    params['center'].set(min=5, max=10)

    # do fit, here with leastsq model
    result = mod.fit(y, params, x=x)

    # assert that stderr and correlations are correct [cf. lmfit v0.9.10]
    assert_almost_equal(result.params['sigma'].stderr, 0.00368468, decimal=6)
    assert_almost_equal(result.params['center'].stderr, 0.00505496, decimal=6)
    assert_almost_equal(result.params['amplitude'].stderr, 0.13861506,
                        decimal=6)
    assert_almost_equal(result.params['gamma'].stderr, 0.00368468, decimal=6)
    assert_almost_equal(result.params['fwhm'].stderr, 0.00806917, decimal=6)
    assert_almost_equal(result.params['height'].stderr, 0.03009459, decimal=6)

    assert_almost_equal(result.params['sigma'].correl['center'],
                        -4.6623973788006615e-05, decimal=6)
    assert_almost_equal(result.params['sigma'].correl['amplitude'],
                        0.651304091954038, decimal=6)
    assert_almost_equal(result.params['center'].correl['amplitude'],
                        -4.390334984618851e-05, decimal=6)
示例#7
0
def test_numdifftools_calc_covar_false():
    pytest.importorskip("numdifftools")
    # load data to be fitted
    data = np.loadtxt(os.path.join(os.path.dirname(__file__), '..', 'examples',
                                   'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['sigma'].set(min=-np.inf)

    # do fit, with leastsq and nelder
    result = mod.fit(y, params, x=x, method='leastsq')
    result_ndt = mod.fit(y, params, x=x, method='nelder', calc_covar=False)

    # assert that fit converged to the same result
    vals = [result.params[p].value for p in result.params.valuesdict()]
    vals_ndt = [result_ndt.params[p].value for p in result_ndt.params.valuesdict()]
    assert_allclose(vals_ndt, vals, rtol=5e-3)
    assert_allclose(result_ndt.chisqr, result.chisqr)

    assert result_ndt.covar is None
    assert result_ndt.errorbars is False
示例#8
0
def test_saveload_usersyms():
    """Test save/load of modelresult with non-trivial user symbols,
    this example uses a VoigtModel, wheree `wofz()` is used in a
    constraint expression"""
    x = np.linspace(0, 20, 501)
    y = gaussian(x, 1.1, 8.5, 2) + lorentzian(x, 1.7, 8.5, 1.5)
    np.random.seed(20)
    y = y + np.random.normal(size=len(x), scale=0.025)

    model = VoigtModel()
    pars = model.guess(y, x=x)
    result = model.fit(y, pars, x=x)

    savefile = 'tmpvoigt_modelresult.sav'
    save_modelresult(result, savefile)

    assert_param_between(result.params['sigma'], 0.7, 2.1)
    assert_param_between(result.params['center'], 8.4, 8.6)
    assert_param_between(result.params['height'], 0.2, 1.0)

    time.sleep(0.25)
    result2 = load_modelresult(savefile)

    assert_param_between(result2.params['sigma'], 0.7, 2.1)
    assert_param_between(result2.params['center'], 8.4, 8.6)
    assert_param_between(result2.params['height'], 0.2, 1.0)
示例#9
0
def call_voigt(x, y, cen, count, pars):
	label='v'+str(count)+'_'
	voigt = VoigtModel(prefix=label)
	pars.update(voigt.make_params())
	pars[label+'center'].set(cen, min=cen-0.01, max=cen+0.01)
	pars[label+'amplitude'].set(-0.5, min=-10., max=0.0001)
	pars[label+'sigma'].set(0.1, min=0.005, max=0.25)
	pars[label+'gamma'].set(value=0.7, vary=True, expr='')
	return voigt
示例#10
0
def call_voigt(x, y, cen, count, pars):
	label='v'+str(count)+'_'
	voigt = VoigtModel(prefix=label)
	pars.update(voigt.make_params())
	pars[label+'center'].set(cen, min=cen-0.01, max=cen+0.01)
	pars[label+'amplitude'].set(0, min=-(max(y)-min(y))*1.5, max=0.0001)
	pars[label+'sigma'].set(fw_set/4, min=0.005, max=fw_set/2.3548)
	pars[label+'gamma'].set(value=fw_set/4, vary=True, expr='')
	return voigt
示例#11
0
def test_numdifftools_with_bounds(fit_method):
    pytest.importorskip("numdifftools")
    if fit_method in ['shgo', 'dual_annealing']:
        pytest.importorskip("scipy", minversion="1.2")

    # load data to be fitted
    data = np.loadtxt(
        os.path.join(os.path.dirname(__file__), '..', 'examples',
                     'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['amplitude'].set(min=25, max=70)
    params['sigma'].set(max=1)
    params['center'].set(min=5, max=15)

    # do fit, here with leastsq model
    result = mod.fit(y, params, x=x, method='leastsq')

    result_ndt = mod.fit(y, params, x=x, method=fit_method)

    # assert that fit converged to the same result
    vals = [result.params[p].value for p in result.params.valuesdict()]
    vals_ndt = [
        result_ndt.params[p].value for p in result_ndt.params.valuesdict()
    ]
    assert_allclose(vals_ndt, vals, rtol=0.1)
    assert_allclose(result_ndt.chisqr, result.chisqr, rtol=1e-5)

    # assert that parameter uncertaintes from leastsq and calculated from
    # the covariance matrix using numdifftools are very similar
    stderr = [result.params[p].stderr for p in result.params.valuesdict()]
    stderr_ndt = [
        result_ndt.params[p].stderr for p in result_ndt.params.valuesdict()
    ]

    perr = np.array(stderr) / np.array(vals)
    perr_ndt = np.array(stderr_ndt) / np.array(vals_ndt)
    assert_almost_equal(perr_ndt, perr, decimal=3)

    # assert that parameter correlatations from leastsq and calculated from
    # the covariance matrix using numdifftools are very similar
    for par1 in result.var_names:
        cor = [
            result.params[par1].correl[par2]
            for par2 in result.params[par1].correl.keys()
        ]
        cor_ndt = [
            result_ndt.params[par1].correl[par2]
            for par2 in result_ndt.params[par1].correl.keys()
        ]
        assert_almost_equal(cor_ndt, cor, decimal=2)
示例#12
0
def curve_fitting_voigt(dref, pars=None):
    xdata = dref.index.to_numpy()
    ydata = dref.to_numpy()

    mod = VoigtModel()
    if pars is None:
        pars = mod.guess(ydata, x=xdata)

    out = mod.fit(ydata, pars, x=xdata)

    return out
示例#13
0
def test_least_squares_solver_options(peakdata, capsys):
    """Test least_squares algorithm, pass options to solver."""
    x = peakdata[0]
    y = peakdata[1]
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    solver_kws = {'verbose': 2}
    mod.fit(y, params, x=x, method='least_squares', fit_kws=solver_kws)
    captured = capsys.readouterr()

    assert 'Iteration' in captured.out
    assert 'final cost' in captured.out
示例#14
0
def test_least_squares_solver_options(peakdata, capsys):
    """Test least_squares algorithm, pass options to solver."""
    x = peakdata[0]
    y = peakdata[1]
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    solver_kws = {'verbose': 2}
    mod.fit(y, params, x=x, method='least_squares', fit_kws=solver_kws)
    captured = capsys.readouterr()

    assert 'Iteration' in captured.out
    assert 'final cost' in captured.out
示例#15
0
def singleline(x, y, tipo, arquivo):
    ##    pdb.set_trace()
    mod = VoigtModel()
    pars = mod.guess(y, x=x)
    pars['gamma'].set(value=0.7, vary=True, expr='')
    ##    pars['sigma'].set(value=0.7, vary=True, expr='')
    out = mod.fit(y, pars, x=x)

    gamma = out.best_values['gamma']
    sigma = out.best_values['sigma']
    center = out.best_values['center']
    calcsingleline(gamma, sigma, center, tipo, arquivo)
示例#16
0
def test_numdifftools_no_bounds():
    numdifftools = pytest.importorskip("numdifftools")
    # load data to be fitted
    data = np.loadtxt(
        os.path.join(os.path.dirname(__file__), '..', 'examples',
                     'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['sigma'].set(min=-np.inf)

    # do fit, here with leastsq model
    result = mod.fit(y, params, x=x, method='leastsq')

    for fit_method in ['nelder', 'basinhopping', 'ampgo']:
        result_ndt = mod.fit(y, params, x=x, method=fit_method)

        # assert that fit converged to the same result
        vals = [result.params[p].value for p in result.params.valuesdict()]
        vals_ndt = [
            result_ndt.params[p].value for p in result_ndt.params.valuesdict()
        ]
        assert_allclose(vals_ndt, vals, rtol=5e-3)
        assert_allclose(result_ndt.chisqr, result.chisqr)

        # assert that parameter uncertaintes from leastsq and calculated from
        # the covariance matrix using numdifftools are very similar
        stderr = [result.params[p].stderr for p in result.params.valuesdict()]
        stderr_ndt = [
            result_ndt.params[p].stderr
            for p in result_ndt.params.valuesdict()
        ]

        perr = np.array(stderr) / np.array(vals)
        perr_ndt = np.array(stderr_ndt) / np.array(vals_ndt)
        assert_almost_equal(perr_ndt, perr, decimal=4)

        # assert that parameter correlatations from leastsq and calculated from
        # the covariance matrix using numdifftools are very similar
        for par1 in result.var_names:
            cor = [
                result.params[par1].correl[par2]
                for par2 in result.params[par1].correl.keys()
            ]
            cor_ndt = [
                result_ndt.params[par1].correl[par2]
                for par2 in result_ndt.params[par1].correl.keys()
            ]
            assert_almost_equal(cor_ndt, cor, decimal=2)
示例#17
0
def correlate_spectra(obs_flx, obs_wvl, ref_flx, ref_wvl):

    # convert spectra sampling to logspace
    obs_flux_res_log, _ = spectra_logspace(obs_flx, obs_wvl)
    ref_flux_sub_log, wvl_log = spectra_logspace(ref_flx, ref_wvl)
    wvl_step = ref_wvl[1] - ref_wvl[0]

    # correlate the two spectra
    min_flux = 0.95
    ref_flux_sub_log[ref_flux_sub_log > min_flux] = 0.
    obs_flux_res_log[obs_flux_res_log > min_flux] = 0.
    corr_res = correlate(ref_flux_sub_log, obs_flux_res_log, mode='same', method='fft')

    # plt.plot(corr_res)
    # plt.show()
    # plt.close()

    # create a correlation subset that will actually be analysed
    corr_w_size = 100
    corr_c_off = np.int64(len(corr_res) / 2.)
    corr_pos_min = corr_c_off - corr_w_size
    corr_pos_max = corr_c_off + corr_w_size
    # print corr_pos_min, corr_pos_max
    corr_res_sub = corr_res[corr_pos_min:corr_pos_max]
    corr_res_sub -= np.median(corr_res_sub)
    corr_res_sub_x = np.arange(len(corr_res_sub))

    # analyze correlation function by fitting gaussian/voigt/lorentzian distribution to it
    fit_model = VoigtModel()
    parameters = fit_model.guess(corr_res_sub, x=corr_res_sub_x)
    corr_fit_res = fit_model.fit(corr_res_sub, parameters, x=corr_res_sub_x)
    corr_center = corr_fit_res.params['center'].value

    # plt.plot(corr_res_sub)
    # plt.axvline(corr_center)
    # plt.show()
    # plt.close()

    # determine the actual shift
    idx_no_shift = np.int32(len(corr_res) / 2.)
    idx_center = corr_c_off - corr_w_size + corr_center
    log_shift_px = idx_no_shift - idx_center
    log_shift_wvl = log_shift_px * wvl_step

    wvl_log_new = wvl_log - log_shift_wvl
    rv_shifts = (wvl_log_new[1:] - wvl_log_new[:-1]) / wvl_log_new[:-1] * 299792.458 * log_shift_px

    if log_shift_wvl < 2:
        return np.nanmedian(rv_shifts)
    else:
        # something went wrong
        return np.nan
示例#18
0
def fit_peak_1d(
    xdata: np.ndarray,
    ydata: np.ndarray,
    engine: str = 'lmfit',
) -> np.ndarray:
    """
    Description
    -----------
    Perform 1D peak fitting using Voigt function

    Parameters
    ----------
    xdata: np.ndarray
        independent var array
    ydata: np.ndarray
        dependent var array
    engien: str
        engine name, [lmfit, tomoproc]
    
    Returns
    -------
    dict
        dictionary of peak parameters

    NOTE
    ----
    Return dictionary have different entries.
    """
    if engine.lower() in ['lmfit', 'external']:
        mod = VoigtModel()
        pars = mod.guess(ydata, x=xdata)
        out = mod.fit(ydata, pars, x=xdata)
        return out.best_values
    else:
        popt, pcov = curve_fit(
            voigt1d,
            xdata,
            ydata,
            maxfev=int(1e6),
            p0=[ydata.max(), xdata.mean(), 1, 1],
            bounds=([0, xdata.min(), 0, 0], [
                ydata.max() * 10,
                xdata.max(),
                xdata.max() - xdata.min(), np.inf
            ]),
        )
        return {
            'amplitude': popt[0],
            'center': popt[1],
            'fwhm': popt[2],
            'shape': popt[3],
        }
示例#19
0
def fitsample(data, theta_initial, theta_final):        
    
    
    x = data[:,0]
    y = data[:,1]
    m = (x > theta_initial) & (x < theta_final)
    x_fit = x[m]
    y_fit = y[m]

    

    pseudovoigt1 = VoigtModel(prefix = 'pv1_')    
    pars= pseudovoigt1.make_params()
    pars['pv1_center'].set(13.5, min = 13.4, max = 13.6)
    pars['pv1_sigma'].set(0.05, min= 0.01, max = 0.1)
    pars['pv1_amplitude'].set(70, min = 1, max = 100)
    #pars['pv1_fraction'].set(0.5)
    

    lorentz2 = LorentzianModel(prefix = 'lor2_')
    pars.update(lorentz2.make_params())
    pars['lor2_center'].set(13.60, min = 13.4, max = 13.9)
    pars['lor2_sigma'].set(0.1, min= 0.01)
    pars['lor2_amplitude'].set(10, min = 1, max = 50 )
    #pars['lor2_fraction'].set(0.5)
    
    line1 = LinearModel(prefix ='l1_')
    pars.update(line1.make_params())
    pars['l1_slope'].set(0)
    pars['l1_intercept'].set(240, min = 200, max = 280)

    
    
    mod = pseudovoigt1 + lorentz2 + line1
    v = pars.valuesdict()
     
    result = mod.fit(y_fit, pars, x=x_fit)    

    #print(result.fit_report())    
    pv1_pos = result.params['pv1_center'].value
    pv1_height = result.params['pv1_height'].value
    lor2_pos = result.params['lor2_center'].value
    lor2_height = result.params['lor2_height'].value
    #peak_area = pars['gau1_fwhm'].value*peak_amp
    #plt.xlim([theta_initial, theta_final])
    #plt.ylim([100, 500])
    #plt.semilogy(x_fit, y_fit, 'bo')
    
    #plt.semilogy (x_fit, result.init_fit, 'k--')    
    #plt.semilogy(x_fit, result.best_fit, 'r-')
    #plt.show()
    return pv1_pos, pv1_height, lor2_pos, lor2_height
示例#20
0
def test_least_squares_cov_x(peakdata, bounds):
    """Test calculation of cov. matrix from Jacobian, with/without bounds."""
    x = peakdata[0]
    y = peakdata[1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)

    if bounds:
        params['amplitude'].set(min=25, max=70)
        params['sigma'].set(min=0, max=1)
        params['center'].set(min=5, max=15)
    else:
        params['sigma'].set(min=-np.inf)

    # do fit with least_squares and leastsq algorithm
    result = mod.fit(y, params, x=x, method='least_squares')
    result_lsq = mod.fit(y, params, x=x, method='leastsq')

    # assert that fit converged to the same result
    vals = [result.params[p].value for p in result.params.valuesdict()]
    vals_lsq = [
        result_lsq.params[p].value for p in result_lsq.params.valuesdict()
    ]
    assert_allclose(vals, vals_lsq, rtol=1e-5)
    assert_allclose(result.chisqr, result_lsq.chisqr)

    # assert that parameter uncertaintes obtained from the leastsq method and
    # those from the covariance matrix estimated from the Jacbian matrix in
    # least_squares are similar
    stderr = [result.params[p].stderr for p in result.params.valuesdict()]
    stderr_lsq = [
        result_lsq.params[p].stderr for p in result_lsq.params.valuesdict()
    ]
    assert_allclose(stderr, stderr_lsq, rtol=1e-4)

    # assert that parameter correlations obtained from the leastsq method and
    # those from the covariance matrix estimated from the Jacbian matrix in
    # least_squares are similar
    for par1 in result.var_names:
        cor = [
            result.params[par1].correl[par2]
            for par2 in result.params[par1].correl.keys()
        ]
        cor_lsq = [
            result_lsq.params[par1].correl[par2]
            for par2 in result_lsq.params[par1].correl.keys()
        ]
        assert_allclose(cor, cor_lsq, rtol=1e-2)
示例#21
0
def voigtFit(filename, xloc=0, yloc=1, stats=False, plot=False):
    # Read Data
    df = pd.read_csv(filename, header=None)
    # Remove bad pixel
    df.drop(df.index[446], inplace=True)
    df.fillna(method='bfill', inplace=True)
    # Narrow region for later delays
    if 'd5' in filename:
        df = df[(df.iloc[:, xloc] > 287.75) & (df.iloc[:, xloc] < 288.6)]

    if 'd4' in filename and ('m1r' or 'm2' in filename):
        df = df[(df.iloc[:, xloc] > 287.75) & (df.iloc[:, xloc] < 288.6)]

    x = np.array(df.iloc[:, xloc])
    y = np.array(df.iloc[:, yloc])

    # Set Voigt fit parameters
    mod = VoigtModel()
    pars = mod.guess(y, x=x)
    pars['gamma'].set(value=0.7, vary=True, expr='')
    # Perform Voigt fit
    out = mod.fit(y, pars, x=x)

    # Print fit statistics
    if stats:
        print(out.fit_report(min_correl=0.25, show_correl=False))

    # Plot Voigt fit
    if plot:
        plt.plot(x, y, 'o', markersize=2.0, c='blue')
        plt.plot(x, out.best_fit, 'r-')
        dely = out.eval_uncertainty(sigma=5)
        plt.fill_between(x,
                         out.best_fit - dely,
                         out.best_fit + dely,
                         color="#bc8f8f")
        plt.xlabel = 'Wavelength (nm)'
        plt.ylabel = 'Intensity (a.u.)'
        plt.xlim((287, 289.5))
        plt.show()

    # Save fit statistics
    for par_name, param in out.params.items():
        if par_name == 'gamma':
            return pd.DataFrame({
                'fid': [filename],
                'fwhm_L': [2 * param.value],
                'error': [2 * param.stderr],
                'R^2': [out.redchi]
            })
def xrdCalculationProcessing(spectrumData, centerXValsList, heightList, axs, setupOptions):
    proposedUserSubstrateTwoTheta = centerXValsList[heightList.index(max(heightList))]
    substrateModel = VoigtModel()
    params = substrateModel.guess(spectrumData.bgSubIntensity, x=spectrumData.xVals, negative=False)
    out = substrateModel.fit(spectrumData.bgSubIntensity, params, x=spectrumData.xVals)
    fullModelSubstrateTwoTheta = out.best_values['center']
    if abs(fullModelSubstrateTwoTheta - proposedUserSubstrateTwoTheta) <= 0.1:
        # looks like the user selected the substrate as a peak, use their value
        substrateTwoTheta = proposedUserSubstrateTwoTheta
    else:
        # Looks like the user did not select the substrate as a peak, use a global value from fitting all data
        substrateTwoTheta = fullModelSubstrateTwoTheta

    literatureSubstrateTwoTheta = calculateTwoTheta(snContentPercent=0)  # Reusing Sn content to 2theta equation
    twoThetaOffset = substrateTwoTheta - literatureSubstrateTwoTheta
    offsetCorrectedCenterTwoThetaList = np.asarray(centerXValsList) - twoThetaOffset
    for centerTwoTheta in offsetCorrectedCenterTwoThetaList:
        michaelSnContent = round(calculateXRDSnContent(centerTwoTheta), 1)
        print("Michael Comp:", michaelSnContent)
        print("Zach Comp:", round(calculateXRDSnContent_Zach(centerTwoTheta), 1))
        if abs(centerTwoTheta - literatureSubstrateTwoTheta) > 0.05:  # Don't draw one for the substrate
            _, centerIndex = closestNumAndIndex(spectrumData.xVals, centerTwoTheta + twoThetaOffset)
            if setupOptions.isLogPlot:
                basePlot = spectrumData.lnIntensity
                subtractedPlot = spectrumData.lnBgSubIntensity
            else:
                basePlot = spectrumData.intensity
                subtractedPlot = spectrumData.bgSubIntensity
            if setupOptions.doBackgroundSubtraction:

                an0 = axs[0].annotate(str(abs(michaelSnContent)),
                                      xy=(centerTwoTheta + twoThetaOffset, basePlot[centerIndex]),
                                      xycoords='data', xytext=(0, 72), textcoords='offset points',
                                      arrowprops=dict(arrowstyle="->", shrinkA=10, shrinkB=5, patchA=None,
                                                      patchB=None))
                an0.draggable()

                an1 = axs[1].annotate(str(abs(michaelSnContent)), xy=(
                    centerTwoTheta + twoThetaOffset, subtractedPlot[centerIndex]), xycoords='data',
                                      xytext=(0, 72), textcoords='offset points',
                                      arrowprops=dict(arrowstyle="->", shrinkA=10, shrinkB=5, patchA=None,
                                                      patchB=None))
                an1.draggable()
            else:
                an0 = axs.annotate(str(abs(michaelSnContent)),
                                   xy=(centerTwoTheta + twoThetaOffset, subtractedPlot[centerIndex]),
                                   xycoords='data', xytext=(0, 72), textcoords='offset points',
                                   arrowprops=dict(arrowstyle="->", shrinkA=10, shrinkB=5, patchA=None,
                                                   patchB=None))
                an0.draggable()
示例#23
0
def test_cov_x_with_bounds():
    # load data to be fitted
    data = np.loadtxt(
        os.path.join(os.path.dirname(__file__), '..', 'examples',
                     'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['amplitude'].set(min=25, max=70)
    params['sigma'].set(min=0, max=1)
    params['center'].set(min=5, max=15)

    # do fit, here with leastsq model
    result = mod.fit(y, params, x=x, method='least_squares')
    result_lsq = mod.fit(y, params, x=x, method='leastsq')

    # assert that fit converged to the same result
    vals = [result.params[p].value for p in result.params.valuesdict()]
    vals_lsq = [
        result_lsq.params[p].value for p in result_lsq.params.valuesdict()
    ]
    assert_allclose(vals_lsq, vals, rtol=1e-5)
    assert_allclose(result_lsq.chisqr, result.chisqr)

    # assert that parameter uncertaintes obtained from the leastsq method and
    # those from the covariance matrix estimated from the Jacbian matrix in
    # least_squares are similar
    stderr = [result.params[p].stderr for p in result.params.valuesdict()]
    stderr_lsq = [
        result_lsq.params[p].stderr for p in result_lsq.params.valuesdict()
    ]
    assert_almost_equal(stderr_lsq, stderr, decimal=6)

    # assert that parameter correlations obtained from the leastsq method and
    # those from the covariance matrix estimated from the Jacbian matrix in
    # least_squares are similar
    for par1 in result.var_names:
        cor = [
            result.params[par1].correl[par2]
            for par2 in result.params[par1].correl.keys()
        ]
        cor_lsq = [
            result_lsq.params[par1].correl[par2]
            for par2 in result_lsq.params[par1].correl.keys()
        ]
        assert_almost_equal(cor_lsq, cor, decimal=6)
示例#24
0
    def ChoosePeakType(self, peaktype, i):
        """
        This function helps to create the `CompositeModel() <https://lmfit.github.io/lmfit-py/model.html#lmfit.model.CompositeModel>`_ .
        Implemented models are:
        `GaussianModel() <https://lmfit.github.io/lmfit-py/builtin_models.html#lmfit.models.GaussianModel>`_  ,
        `LorentzianModel() <https://lmfit.github.io/lmfit-py/builtin_models.html#lmfit.models.LorentzianModel>`_  ,
        `VoigtModel() <https://lmfit.github.io/lmfit-py/builtin_models.html#lmfit.models.VoigtModel>`_  ,
        `BreitWignerModel() <https://lmfit.github.io/lmfit-py/builtin_models.html#lmfit.models.BreitWignerModel>`_  .

        Parameters
        ----------
        peaktype : string
            Possible line shapes of the peaks to fit are
            'breit_wigner', 'lorentzian', 'gaussian', and 'voigt'.
        i : int
            Integer between 0 and (N-1) to distinguish between N peaks of the
            same peaktype. It is used in the prefix.

        Returns
        -------
        lmfit.models.* : class
            Returns either VoigtModel(), BreitWignerModel(), LorentzianModel(),
            or GaussianModel() depending on the peaktype with
            *Model(prefix = prefix, nan_policy = 'omit').
            The prefix contains the peaktype and i.
        """
        prefix = peaktype + '_p' + str(i + 1) + '_'
        if peaktype == 'voigt':
            return VoigtModel(prefix=prefix, nan_policy='omit')
        elif peaktype == 'breit_wigner':
            return BreitWignerModel(prefix=prefix, nan_policy='omit')
        elif peaktype == 'lorentzian':
            return LorentzianModel(prefix=prefix, nan_policy='omit')
        elif peaktype == 'gaussian':
            return GaussianModel(prefix=prefix, nan_policy='omit')
示例#25
0
def fit_voigt_over_linear(q,
                          I,
                          cen=1,
                          sig=0.002,
                          sigmin=1e-4,
                          sigmax=0.01,
                          amplmin=0,
                          amplmax=500,
                          trim=0.06,
                          plot=False):

    trim = logical_and(q < cen + trim, q > cen - trim)
    q = q[trim]
    I = I[trim]

    mod = LinearModel()
    mod.set_param_hint('slope', value=-20)
    mod.set_param_hint('intercept', value=10)
    lineout = mod.fit(I, x=q)
    pars = lineout.params

    mod += VoigtModel()
    pars.add('center', value=cen)
    pars.add('sigma', value=sig, max=sigmax, min=sigmin)
    pars.add('amplitude',
             value=amplmin / 2 + amplmax / 2,
             min=amplmin,
             max=amplmax)
    out = mod.fit(I, pars, x=q)

    return out
示例#26
0
    def fit(self, xx, yy, fitType):
        xx = np.asarray(xx)
        yy = np.asarray(yy)
        print("XX", xx)
        print("YY", yy)
        print(len(xx))
        print(len(yy))
        print("XX", xx)
        x1 = xx[0]
        x2 = xx[-1]
        y1 = yy[0]
        y2 = yy[-1]
        m = (y2 - y1) / (x2 - x1)
        b = y2 - m * x2

        if fitType == "Gaussian":
            mod = GaussianModel()
        elif fitType == "Lorentzian":
            mod = LorentzianModel()
        else:
            mod = VoigtModel()

        pars = mod.guess(yy, x=xx, slope=m)
        print(pars)
        mod = mod + LinearModel()
        pars.add('intercept', value=b, vary=True)
        pars.add('slope', value=m, vary=True)
        out = mod.fit(yy, pars, x=xx)

        return out.best_fit
示例#27
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"
示例#28
0
def methodfunciont(key):
    dic = {
        "VoigtModel": VoigtModel(),
        "PseudoVoigtModel": PseudoVoigtModel(),
        "GaussianModel": GaussianModel()
    }

    return dic[key]
示例#29
0
    def fit(self):
        x = self.energies_eV
        y = self.intensities

        model = VoigtModel()

        init_parameters = model.guess(y, x=x)
        self.fit_results = model.fit(y, init_parameters, x=x)

        values = self.fit_results.params.valuesdict()

        self.fit_results_position_eV = values['center']
        self.fit_results_fwhm_eV = values['fwhm']
        self.fit_results_sigma_eV = values['sigma']
        self.fit_results_gamma_eV = values['gamma']
        self.fit_results_area = values['amplitude']
        self.fit_results_height = values['height']
示例#30
0
def test_numdifftools_with_bounds(fit_method):
    pytest.importorskip("numdifftools")
    if fit_method == 'shgo':
        pytest.importorskip("scipy", minversion="1.2")

    # load data to be fitted
    data = np.loadtxt(os.path.join(os.path.dirname(__file__), '..', 'examples',
                                   'test_peak.dat'))
    x = data[:, 0]
    y = data[:, 1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)
    params['amplitude'].set(min=25, max=70)
    params['sigma'].set(max=1)
    params['center'].set(min=5, max=15)

    # do fit, here with leastsq model
    result = mod.fit(y, params, x=x, method='leastsq')

    result_ndt = mod.fit(y, params, x=x, method=fit_method)

    # assert that fit converged to the same result
    vals = [result.params[p].value for p in result.params.valuesdict()]
    vals_ndt = [result_ndt.params[p].value for p in result_ndt.params.valuesdict()]
    assert_allclose(vals_ndt, vals, rtol=0.1)
    assert_allclose(result_ndt.chisqr, result.chisqr, rtol=1e-5)

    # assert that parameter uncertaintes from leastsq and calculated from
    # the covariance matrix using numdifftools are very similar
    stderr = [result.params[p].stderr for p in result.params.valuesdict()]
    stderr_ndt = [result_ndt.params[p].stderr for p in result_ndt.params.valuesdict()]

    perr = np.array(stderr) / np.array(vals)
    perr_ndt = np.array(stderr_ndt) / np.array(vals_ndt)
    assert_almost_equal(perr_ndt, perr, decimal=3)

    # assert that parameter correlatations from leastsq and calculated from
    # the covariance matrix using numdifftools are very similar
    for par1 in result.var_names:
        cor = [result.params[par1].correl[par2] for par2 in
               result.params[par1].correl.keys()]
        cor_ndt = [result_ndt.params[par1].correl[par2] for par2 in
                   result_ndt.params[par1].correl.keys()]
        assert_almost_equal(cor_ndt, cor, decimal=2)
示例#31
0
def peakfit(xvals, yvals, yerrors=None):
    """
    Fit peak to scans
    """

    peak_mod = VoigtModel()
    # peak_mod = GaussianModel()
    bkg_mod = LinearModel()

    pars = peak_mod.guess(yvals, x=xvals)
    pars += bkg_mod.make_params(intercept=np.min(yvals), slope=0)
    # pars['gamma'].set(value=0.7, vary=True, expr='') # don't fix gamma

    mod = peak_mod + bkg_mod
    out = mod.fit(yvals, pars, x=xvals, weights=yerrors)

    return out
示例#32
0
def test_least_squares_cov_x(peakdata, bounds):
    """Test calculation of cov. matrix from Jacobian, with/without bounds."""
    x = peakdata[0]
    y = peakdata[1]

    # define the model and initialize parameters
    mod = VoigtModel()
    params = mod.guess(y, x=x)

    if bounds:
        params['amplitude'].set(min=25, max=70)
        params['sigma'].set(min=0, max=1)
        params['center'].set(min=5, max=15)
    else:
        params['sigma'].set(min=-np.inf)

    # do fit with least_squares and leastsq algorithm
    result = mod.fit(y, params, x=x, method='least_squares')
    result_lsq = mod.fit(y, params, x=x, method='leastsq')

    # assert that fit converged to the same result
    vals = [result.params[p].value for p in result.params.valuesdict()]
    vals_lsq = [result_lsq.params[p].value for p in
                result_lsq.params.valuesdict()]
    assert_allclose(vals, vals_lsq, rtol=1e-5)
    assert_allclose(result.chisqr, result_lsq.chisqr)

    # assert that parameter uncertaintes obtained from the leastsq method and
    # those from the covariance matrix estimated from the Jacbian matrix in
    # least_squares are similar
    stderr = [result.params[p].stderr for p in result.params.valuesdict()]
    stderr_lsq = [result_lsq.params[p].stderr for p in
                  result_lsq.params.valuesdict()]
    assert_allclose(stderr, stderr_lsq, rtol=1e-4)

    # assert that parameter correlations obtained from the leastsq method and
    # those from the covariance matrix estimated from the Jacbian matrix in
    # least_squares are similar
    for par1 in result.var_names:
        cor = [result.params[par1].correl[par2] for par2 in
               result.params[par1].correl.keys()]
        cor_lsq = [result_lsq.params[par1].correl[par2] for par2 in
                   result_lsq.params[par1].correl.keys()]
        assert_allclose(cor, cor_lsq, rtol=1e-2)
示例#33
0
    def voigt_response(self, sigma=None, gamma=None):
        '''
        Fit the background with a Voigt profile to determine the response
        of the spectrometer

        If you have a good, clear signal, set sigma and gamma to None (done by default)

        If your signal is poor, set sigma and gamma using a fit to a good signal, and then
        only the position of the central wavelength will be altered.
        '''
        vm = VoigtModel()
        par_v = vm.guess(self.bkgd, x=self.lamb)
        par_v['center'].set(value=532e-9, vary=True)
        err = (self.bkgd_ferr * self.shot)
        if sigma is not None:  #if a width is provided, fix it.
            par_v['sigma'].set(value=sigma, vary=False)
        if gamma is not None:  #if a width is provided, fix it.
            par_v['gamma'].set(value=gamma, vary=False, expr='')
        elif gamma is None:  #vary gamma for better fit - this is not done by default
            par_v['gamma'].set(value=par_v['sigma'].value, vary=True, expr='')

        ##Fit the Voigt Model to the data
        vm_fit = vm.fit(self.bkgd, par_v, x=self.lamb)
        self.vm_fit = vm_fit
        #now crop the data so that the response is symmetric for the convolution to work
        l0 = vm_fit.best_values['center']
        self.sigma = vm_fit.best_values['sigma']
        self.l0 = l0
        l0_i = find_nearest(self.lamb, l0)
        l_size = self.lamb.size
        take_l = min(
            l0_i, l_size -
            l0_i)  #trim the shortest distance from the central wavelength
        low_i = l0_i - take_l
        high_i = l0_i + take_l
        self.lamb = self.lamb[low_i:high_i]
        self.bkgd = self.bkgd[low_i:high_i]
        self.shot = self.shot[low_i:high_i]
        self.shot_ferr = self.shot_ferr[low_i:high_i]
        self.bkgd_ferr = self.bkgd_ferr[low_i:high_i]
        #the response is taken from the model so it is nice and smooth
        self.response = vm_fit.best_fit[low_i:high_i]
        self.shift = self.lamb - l0  #this is useful for plotting data
示例#34
0
def fit_one_Voigt(x_lst,y_lst, pre):
    '''
    Fits one Pseudo Voigt returns the 
    results object
    '''
    x_lst = np.asarray(x_lst)
    y_lst = np.asarray(y_lst)
    
    mod = VoigtModel(prefix = pre, independent_vars=['x'],nan_policy='raise')
    
    # here we set up the peak fitting guess. Then the peak fitter will make a parameter object out of them
    mod.set_param_hint(pre+'amplitude', value = 4 * np.max(y_lst), min = 3*np.max(y_lst), max = 7*np.max(y_lst), vary=True)
    # mod.set_param_hint(prefp+'center', value = x_max, min = x_max*(1-wiggle_room), max = x_max*(1+wiggle_room),vary=True)
    mod.set_param_hint(pre+'center', value = x_lst[np.argmax(y_lst)], vary=True)
    # Basically FWHM/3.6
    w_guess = 2
    mod.set_param_hint(pre+'sigma', value = w_guess, min = 0, max = 5*w_guess,vary=True)
    
    result = mod.fit(y_lst, x = x_lst, params = mod.make_params())
    
    return result
示例#35
0
def test_param_set():
    np.random.seed(2015)
    x = np.arange(0, 20, 0.05)
    y = gaussian(x, amplitude=15.43, center=4.5, sigma=2.13)
    y = y + 0.05 - 0.01 * x + np.random.normal(scale=0.03, size=len(x))

    model = VoigtModel()
    params = model.guess(y, x=x)

    # test #1:  gamma is constrained to equal sigma
    assert (params['gamma'].expr == 'sigma')
    params.update_constraints()
    sigval = params['gamma'].value
    assert_allclose(params['gamma'].value, sigval, 1e-4, 1e-4, '', True)

    # test #2: explicitly setting a param value should work, even when
    #          it had been an expression.  The value will be left as fixed
    gamval = 0.87543
    params['gamma'].set(value=gamval)
    assert (params['gamma'].expr is None)
    assert (not params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)

    # test #3: explicitly setting an expression should work
    # Note, the only way to ensure that **ALL** constraints are up to date
    # is to call params.update_constraints(). This is because the constraint
    # may have multiple dependencies.
    params['gamma'].set(expr='sigma/2.0')
    assert (params['gamma'].expr is not None)
    assert (not params['gamma'].vary)
    params.update_constraints()
    assert_allclose(params['gamma'].value, sigval / 2.0, 1e-4, 1e-4, '', True)

    # test #4: explicitly setting a param value WITH vary=True
    #          will set it to be variable
    gamval = 0.7777
    params['gamma'].set(value=gamval, vary=True)
    assert (params['gamma'].expr is None)
    assert (params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)
    def __init__(self, ModelString):

        self.NumModels = {}
        self.NumModels['Total'] = len(ModelString)
        self.NumModels['Linear'] = len(re.findall('L', ModelString))
        self.NumModels['Gaussian'] = len(re.findall('G', ModelString))
        self.NumModels['Voigt'] = len(re.findall('V', ModelString))
        if self.NumModels['Total'] != self.NumModels['Linear'] + self.NumModels[
                'Gaussian'] + self.NumModels['Voigt']:
            print(
                'Warning: Number of total functions does not equal number of summed functions'
            )
        ModelCounter = 0
        i = 0
        while i < self.NumModels['Linear']:
            if ModelCounter == 0:
                self.Model = LinearModel(prefix='L' + str(i + 1) + '_')
            else:
                self.Model = self.Model + LinearModel(prefix='L' + str(i + 1) +
                                                      '_')
            ModelCounter = ModelCounter + 1
            i += 1
        i = 0
        while i < self.NumModels['Gaussian']:
            if ModelCounter == 0:
                self.Model = GaussianModel(prefix='G' + str(i + 1) + '_')
            else:
                self.Model = self.Model + GaussianModel(prefix='G' +
                                                        str(i + 1) + '_')
            ModelCounter = ModelCounter + 1
            i += 1
        i = 0
        while i < self.NumModels['Voigt']:
            if ModelCounter == 0:
                self.Model = VoigtModel(prefix='V' + str(i + 1) + '_')
            else:
                self.Model = self.Model + VoigtModel(prefix='V' + str(i + 1) +
                                                     '_')
            ModelCounter = ModelCounter + 1
            i += 1
示例#37
0
def test_param_set():
    np.random.seed(2015)
    x = np.arange(0, 20, 0.05)
    y = gaussian(x, amplitude=15.43, center=4.5, sigma=2.13)
    y = y + 0.05 - 0.01*x + np.random.normal(scale=0.03, size=len(x))

    model  = VoigtModel()
    params = model.guess(y, x=x)

    # test #1:  gamma is constrained to equal sigma
    assert(params['gamma'].expr == 'sigma')
    params.update_constraints()
    sigval = params['gamma'].value
    assert_allclose(params['gamma'].value, sigval, 1e-4, 1e-4, '', True)

    # test #2: explicitly setting a param value should work, even when
    #          it had been an expression.  The value will be left as fixed
    gamval = 0.87543
    params['gamma'].set(value=gamval)
    assert(params['gamma'].expr is None)
    assert(not params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)

    # test #3: explicitly setting an expression should work
    # Note, the only way to ensure that **ALL** constraints are up to date
    # is to call params.update_constraints(). This is because the constraint
    # may have multiple dependencies.
    params['gamma'].set(expr='sigma/2.0')
    assert(params['gamma'].expr is not None)
    assert(not params['gamma'].vary)
    params.update_constraints()
    assert_allclose(params['gamma'].value, sigval/2.0, 1e-4, 1e-4, '', True)

    # test #4: explicitly setting a param value WITH vary=True
    #          will set it to be variable
    gamval = 0.7777
    params['gamma'].set(value=gamval, vary=True)
    assert(params['gamma'].expr is None)
    assert(params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)
示例#38
0
def fit_voigt(ax, spectra, args):
    fit_range = args.pl_range
    wl = spectra[:, 0]
    sp = spectra[:, 2]

    wl_fit = wl[(wl > fit_range[0]) & (wl < fit_range[1])]
    sp_fit = sp[(wl > fit_range[0]) & (wl < fit_range[1])]

    mod = VoigtModel() + ConstantModel()
    pars = mod.make_params(amplitude=np.max(sp_fit),
                           center=wl_fit[np.argmax(sp_fit)],
                           sigma=10,
                           gamma=10,
                           c=0)

    out = mod.fit(sp_fit, pars, x=wl_fit)

    ax.plot(wl_fit, out.best_fit, 'k--', alpha=0.8)
    print(f'Peak center = {out.params["center"].value:.2f} nm \n'
          f'FWHM = {out.params["fwhm"].value:.2f} nm')

    return out.params['center'].value, out.params['fwhm'].value,
示例#39
0
data = loadtxt('test_peak.dat')
x = data[:, 0]
y = data[:, 1]

gmodel = GaussianModel()
gmodel.guess_starting_values(y, x=x)
gresult = gmodel.fit(y, x=x)

print 'With Gaussian: '
print fit_report(gresult.params, min_correl=0.25)
print 'Chi-square = %.3f, Reduced Chi-square = %.3f' % (gresult.chisqr, gresult.redchi)
plt.plot(x, y,         'k')
plt.plot(x, 10*(y-gresult.best_fit), 'r-')


vmodel = VoigtModel()
vmodel.guess_starting_values(y, x=x)
vresult = vmodel.fit(y, x=x)

print 'With Voigt: '
print fit_report(vresult.params, min_correl=0.25)
print 'Chi-square = %.3f, Reduced Chi-square = %.3f' % (vresult.chisqr, vresult.redchi)

plt.plot(x, 10*(y-vresult.best_fit), 'b-')


vmodel.params['gamma'].vary = True
vmodel.params['gamma'].expr = None

vresult2 = vmodel.fit(y, x=x)
示例#40
0
def pre_edge_baseline(energy, norm=None, group=None, form='lorentzian',
                      emin=None, emax=None, elo=None, ehi=None,
                      with_line=True, _larch=None):
    """remove baseline from main edge over pre edge peak region

    This assumes that pre_edge() has been run successfully on the spectra
    and that the spectra has decent pre-edge subtraction and normalization.

    Arguments
    ----------
    energy:    array of x-ray energies, in eV, or group (see note 1)
    norm:      array of normalized mu(E)
    group:     output group
    elo:       low energy of pre-edge peak region to not fit baseline [e0-20]
    ehi:       high energy of pre-edge peak region ot not fit baseline [e0-10]
    emax:      max energy (eV) to use for baesline fit [e0-5]
    emin:      min energy (eV) to use for baesline fit [e0-40]
    form:      form used for baseline (see note 2)  ['lorentzian']
    with_line: whether to include linear component in baseline ['True']


    Returns
    -------
      None

    A group named 'prepeaks' will be created in the output group, with the following
    attributes:
        energy        energy array for pre-edge peaks = energy[emin:emax]
        baseline      fitted baseline array over pre-edge peak energies
        norm          spectrum over pre-edge peak energies
        peaks         baseline-subtraced spectrum over pre-edge peak energies
        centroid      estimated centroid of pre-edge peaks (see note 3)
        peak_energies list of predicted peak energies (see note 4)
        fit_details   details of fit to extract pre-edge peaks.

    (if the output group is None, _sys.xafsGroup will be written to)

    Notes
    -----
     1 If the first argument is a Group, it must contain 'energy' and 'norm'.
       See First Argrument Group in Documentation

     2 A function will be fit to the input mu(E) data over the range between
       [emin:elo] and [ehi:emax], ignorng the pre-edge peaks in the
       region [elo:ehi].  The baseline function is specified with the `form`
       keyword argument, which can be one of
           'lorentzian', 'gaussian', or 'voigt',
       with 'lorentzian' the default.  In addition, the `with_line` keyword
       argument can be used to add a line to this baseline function.

     3 The value calculated for `prepeaks.centroid`  will be found as
         (prepeaks.energy*prepeaks.peaks).sum() / prepeaks.peaks.sum()
     4 The values in the `peak_energies` list will be predicted energies
       of the peaks in `prepeaks.peaks` as found by peakutils.

    """
    energy, norm, group = parse_group_args(energy, members=('energy', 'norm'),
                                           defaults=(norm,), group=group,
                                           fcn_name='pre_edge_baseline')

    prepeaks_setup(energy, norm=norm, group=group, emin=emin, emax=emax,
                   elo=elo, ehi=ehi, _larch=_larch)

    emin = group.prepeaks.emin
    emax = group.prepeaks.emax
    elo = group.prepeaks.elo
    ehi = group.prepeaks.ehi

    dele = 1.e-13 + min(np.diff(energy))/5.0

    imin = index_of(energy, emin+dele)
    ilo  = index_of(energy, elo+dele)
    ihi  = index_of(energy, ehi+dele)
    imax = index_of(energy, emax+dele)

    # build xdat, ydat: dat to fit (skipping pre-edge peaks)
    xdat = np.concatenate((energy[imin:ilo+1], energy[ihi:imax+1]))
    ydat = np.concatenate((norm[imin:ilo+1], norm[ihi:imax+1]))


    # build fitting model: note that we always include
    # a LinearModel but may fix slope and intercept
    form = form.lower()
    if form.startswith('voig'):
        model = VoigtModel()
    elif form.startswith('gaus'):
        model = GaussianModel()
    else:
        model = LorentzianModel()

    model += LinearModel()
    params = model.make_params(amplitude=1.0, sigma=2.0,
                               center=emax,
                               intercept=0, slope=0)
    params['amplitude'].min =  0.0
    params['sigma'].min     =  0.25
    params['sigma'].max     = 50.0
    params['center'].max    = emax + 25.0
    params['center'].min    = emax - 25.0

    if not with_line:
        params['slope'].vary = False
        params['intercept'].vary = False

    result = model.fit(ydat, params, x=xdat)

    cen = dcen = 0.
    peak_energies = []

    # energy including pre-edge peaks, for output
    edat = energy[imin: imax+1]
    norm = norm[imin:imax+1]
    bline = peaks = dpeaks = norm*0.0

    # get baseline and resulting norm over edat range
    if result is not None:
        bline = result.eval(result.params, x=edat)
        peaks = norm-bline

        # estimate centroid
        cen = (edat*peaks).sum() / peaks.sum()

        # uncertainty in norm includes only uncertainties in baseline fit
        # and uncertainty in centroid:
        try:
            dpeaks = result.eval_uncertainty(result.params, x=edat)
        except:
            dbpeaks = 0.0

        cen_plus = (edat*(peaks+dpeaks)).sum()/ (peaks+dpeaks).sum()
        cen_minus = (edat*(peaks-dpeaks)).sum()/ (peaks-dpeaks).sum()
        dcen = abs(cen_minus - cen_plus) / 2.0

        # locate peak positions
        if HAS_PEAKUTILS:
            peak_ids = peakutils.peak.indexes(peaks, thres=0.05, min_dist=2)
            peak_energies = [edat[pid] for pid in peak_ids]

    group = set_xafsGroup(group, _larch=_larch)
    group.prepeaks = Group(energy=edat, norm=norm, baseline=bline,
                           peaks=peaks, delta_peaks=dpeaks,
                           centroid=cen, delta_centroid=dcen,
                           peak_energies=peak_energies,
                           fit_details=result,
                           emin=emin, emax=emax, elo=elo, ehi=ehi,
                           form=form, with_line=with_line)
    return
示例#41
0
def test_param_set():
    np.random.seed(2015)
    x = np.arange(0, 20, 0.05)
    y = gaussian(x, amplitude=15.43, center=4.5, sigma=2.13)
    y = y + 0.05 - 0.01*x + np.random.normal(scale=0.03, size=len(x))

    model  = VoigtModel()
    params = model.guess(y, x=x)

    # test #1:  gamma is constrained to equal sigma
    assert(params['gamma'].expr == 'sigma')
    params.update_constraints()
    sigval = params['sigma'].value
    assert_allclose(params['gamma'].value, sigval, 1e-4, 1e-4, '', True)

    # test #2: explicitly setting a param value should work, even when
    #          it had been an expression.  The value will be left as fixed
    gamval = 0.87543
    params['gamma'].set(value=gamval)
    assert(params['gamma'].expr is None)
    assert(not params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)

    # test #3: explicitly setting an expression should work
    # Note, the only way to ensure that **ALL** constraints are up to date
    # is to call params.update_constraints(). This is because the constraint
    # may have multiple dependencies.
    params['gamma'].set(expr='sigma/2.0')
    assert(params['gamma'].expr is not None)
    assert(not params['gamma'].vary)
    params.update_constraints()
    assert_allclose(params['gamma'].value, sigval/2.0, 1e-4, 1e-4, '', True)

    # test #4: explicitly setting a param value WITH vary=True
    #          will set it to be variable
    gamval = 0.7777
    params['gamma'].set(value=gamval, vary=True)
    assert(params['gamma'].expr is None)
    assert(params['gamma'].vary)
    assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)

    # test 5: make sure issue #389 is fixed: set boundaries and make sure
    #         they are kept when changing the value
    amplitude_vary = params['amplitude'].vary
    amplitude_expr = params['amplitude'].expr
    params['amplitude'].set(min=0.0, max=100.0)
    params.update_constraints()
    assert_allclose(params['amplitude'].min, 0.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True)
    params['amplitude'].set(value=40.0)
    params.update_constraints()
    assert_allclose(params['amplitude'].value, 40.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].min, 0.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True)
    assert(params['amplitude'].expr == amplitude_expr)
    assert(params['amplitude'].vary == amplitude_vary)
    assert(not params['amplitude'].brute_step)

    # test for possible regressions of this fix (without 'expr'):
    # the set function should only change the requested attribute(s)
    params['amplitude'].set(value=35.0)
    params.update_constraints()
    assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].min, 0.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True)
    assert(params['amplitude'].vary == amplitude_vary)
    assert(params['amplitude'].expr == amplitude_expr)
    assert(not params['amplitude'].brute_step)

    # set minimum
    params['amplitude'].set(min=10.0)
    params.update_constraints()
    assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True)
    assert(params['amplitude'].vary == amplitude_vary)
    assert(params['amplitude'].expr == amplitude_expr)
    assert(not params['amplitude'].brute_step)

    # set maximum
    params['amplitude'].set(max=110.0)
    params.update_constraints()
    assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].max, 110.0, 1e-4, 1e-4, '', True)
    assert(params['amplitude'].vary == amplitude_vary)
    assert(params['amplitude'].expr == amplitude_expr)
    assert(not params['amplitude'].brute_step)

    # set vary
    params['amplitude'].set(vary=False)
    params.update_constraints()
    assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].max, 110.0, 1e-4, 1e-4, '', True)
    assert(params['amplitude'].vary == False)
    assert(params['amplitude'].expr == amplitude_expr)
    assert(not params['amplitude'].brute_step)

    # set brute_step
    params['amplitude'].set(brute_step=0.1)
    params.update_constraints()
    assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['amplitude'].max, 110.0, 1e-4, 1e-4, '', True)
    assert(params['amplitude'].vary == False)
    assert(params['amplitude'].expr == amplitude_expr)
    assert_allclose(params['amplitude'].brute_step, 0.1, 1e-4, 1e-4, '', True)

    # test for possible regressions of this fix for variables WITH 'expr':
    height_value = params['height'].value
    height_min = params['height'].min
    height_max = params['height'].max
    height_vary = params['height'].vary
    height_expr = params['height'].expr
    height_brute_step = params['height'].brute_step

    # set vary=True should remove expression
    params['height'].set(vary=True)
    params.update_constraints()
    assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].min, height_min, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True)
    assert(params['height'].vary == True)
    assert(params['height'].expr == None)
    assert(params['height'].brute_step == height_brute_step)

    # setting an expression should set vary=False
    params['height'].set(expr=height_expr)
    params.update_constraints()
    assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].min, height_min, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True)
    assert(params['height'].vary == False)
    assert(params['height'].expr == height_expr)
    assert(params['height'].brute_step == height_brute_step)

    # changing min/max should not remove expression
    params['height'].set(min=0)
    params.update_constraints()
    assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True)
    assert(params['height'].vary == height_vary)
    assert(params['height'].expr == height_expr)
    assert(params['height'].brute_step == height_brute_step)

    # changing brute_step should not remove expression
    params['height'].set(brute_step=0.1)
    params.update_constraints()
    assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True)
    assert(params['height'].vary == height_vary)
    assert(params['height'].expr == height_expr)
    assert_allclose(params['amplitude'].brute_step, 0.1, 1e-4, 1e-4, '', True)

    # changing the value should remove expression and keep vary=False
    params['height'].set(brute_step=0)
    params['height'].set(value=10.0)
    params.update_constraints()
    assert_allclose(params['height'].value, 10.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True)
    assert(params['height'].vary == False)
    assert(params['height'].expr == None)
    assert(params['height'].brute_step == height_brute_step)

    # passing expr='' should only remove the expression
    params['height'].set(expr=height_expr) # first restore the original expr
    params.update_constraints()
    params['height'].set(expr='')
    params.update_constraints()
    assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True)
    assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True)
    assert(params['height'].vary == False)
    assert(params['height'].expr == None)
    assert(params['height'].brute_step == height_brute_step)