def test_constraints1(): def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params) pfit= result.params fit = residual(result.params, x) assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value)
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma
def residual(pars, x, data): model = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) model += lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) return (model - data)
def residual_GC(pars, x, sigma=None, data=None): yg = gaussian(x) #, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x) #, pars['amp_l'], pars['cen_l'], pars['wid_l']) slope = pars['line_slope'] offset = pars['line_off'] model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data / sigma)
def conv_rotations_pvoigt(left, right, params, **kwargs): """Convolution between the rotation model and a pseudo-Voigt profile.""" # set left to rotations component if not so if left.func.__name__ == "pvoigt": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] frac = rp["fraction_%i" % qId] lsigma = lp["sigma"] if "sigma" in lglob else lp["sigma_%i" % qId] rsigma = rp["sigma_%i" % qId] sigma_v = rsigma / np.sqrt(2 * np.log(2)) bondDist = lp["bondDist"] eisf = spherical_jn(0, bondDist * qVal) ** 2 eisf *= pvoigt(x, amplitude, center, rsigma, frac) qisf = np.sum( [ spherical_jn(i, bondDist * qVal) ** 2 * (2 * i + 1) * ( frac * voigt( x, amplitude, center, sigma_v, i * (i + 1) * lsigma ) * (1 - frac) * lorentzian( amplitude, center, rsigma + i * (i + 1) * lsigma ) ) for i in range(1, 5) ], axis=0, ) out.append(eisf + qisf) return np.array(out)
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) yl = lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) yl = lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma
def test_constraints1(): def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma': sigma, 'data': data}, scale_covar=True) myfit.prepare_fit() result = myfit.leastsq() pfit = result.params assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value)
def test_guess_from_peak(): """Regression test for guess_from_peak function (see GH #627).""" x = np.linspace(-5, 5) amplitude = 0.8 center = 1.7 sigma = 0.3 y = lineshapes.lorentzian(x, amplitude=amplitude, center=center, sigma=sigma) model = models.LorentzianModel() guess_increasing_x = model.guess(y, x=x) guess_decreasing_x = model.guess(y[::-1], x=x[::-1]) assert guess_increasing_x == guess_decreasing_x for param, value in zip(['amplitude', 'center', 'sigma'], [amplitude, center, sigma]): assert np.abs((guess_increasing_x[param].value - value)/value) < 0.5
def minimizer(): """Return the Minimizer object.""" def residual(pars, x, sigma=None, data=None): """Define objective function.""" yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return model - data return (model-data) / sigma # generate synthetic data n = 601 xmin = 0. xmax = 20.0 x = np.linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + np.random.normal(scale=0.23, size=n) + x*0.5) # create initial Parameters pars = Parameters() pars.add(name='amp_g', value=10) pars.add(name='cen_g', value=9) pars.add(name='wid_g', value=1) pars.add(name='amp_tot', value=20) pars.add(name='amp_l', expr='amp_tot - amp_g') pars.add(name='cen_l', expr='1.5+cen_g') pars.add(name='wid_l', expr='2*wid_g') pars.add(name='line_slope', value=0.0) pars.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) mini = Minimizer(residual, pars, fcn_args=(x,), fcn_kws={'sigma': sigma, 'data': data}) return mini
def lorentzian2d(x, y, amplitude=1., centerx=0., centery=0., sigmax=1., sigmay=1., rotation=0): """Return a two dimensional lorentzian. The maximum of the peak occurs at ``centerx`` and ``centery`` with widths ``sigmax`` and ``sigmay`` in the x and y directions respectively. The peak can be rotated by choosing the value of ``rotation`` in radians. """ xp = (x - centerx) * np.cos(rotation) - (y - centery) * np.sin(rotation) yp = (x - centerx) * np.sin(rotation) + (y - centery) * np.cos(rotation) R = (xp / sigmax)**2 + (yp / sigmay)**2 return 2 * amplitude * lorentzian(R) / (np.pi * sigmax * sigmay)
def conv_lorentzian_lorentzian(left, right, params, **kwargs): r"""Convolution between two Lorentzians. .. math:: a_1 \mathcal{L}_{\sigma_1, center_1} \otimes a_2 \mathcal{L}_{sigma_2, center_2} = a_1 a_2 . \mathcal{L}_{\sigma_1 + \sigma_2, center_1 + center_2} """ lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] lsigma = ( lp["sigma"] * qVal ** 2 if "sigma" in lglob else lp["sigma_%i" % qId] ) rsigma = ( rp["sigma"] * qVal ** 2 if "sigma" in rglob else lp["sigma_%i" % qId] ) out.append(lorentzian(x, amplitude, center, lsigma + rsigma)) return np.array(out)
def conv_jumpdiff_pvoigt(left, right, params, **kwargs): """Convolution between the jump diffusion model and a pseudo-Voigt profile. """ # set left to jump_diff component if not so if left.func.__name__ == "pvoigt": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] frac = rp["fraction_%i" % qId] lsigma = ( lp["sigma"] * qVal ** 2 / (1 + lp["sigma"] * qVal ** 2 * lp["tau"]) if "sigma" in lglob else lp["sigma_%i" % qId] ) rsigma = rp["sigma_%i" % qId] sigma_v = rsigma / np.sqrt(2 * np.log(2)) out.append( frac * voigt(x, amplitude, center, sigma_v, lsigma) + (1 - frac) * lorentzian(x, amplitude, center, lsigma + rsigma) ) return np.array(out)
def plot_fit(out): fig, ax = plt.subplots( 2, 1, sharex=True, figsize=(12, 6), gridspec_kw={"height_ratios": [1, 4]} ) xd = out.userkws[out.model.independent_vars[0]] xnew = np.linspace(xd[0], xd[-1], 1000) ax[0].plot(xd, out.residual, "k-", ms=3, lw=1, alpha=0.5) ax[1].plot(xd, out.data, "b+-", ms=3, lw=1, alpha=0.8) ax[1].plot(xnew, out.eval(x=xnew), "k--", lw=1.5) for i, p in enumerate(out.peak_pos): # print(out.params['p%s_']) ax[1].plot( xnew, lorentzian( xnew, amplitude=out.params["p%s_amplitude" % i], center=out.params["p%s_center" % i], sigma=out.params["p%s_sigma" % i], ), lw=0.5, ) return fig
import matplotlib.pyplot as plt import numpy as np from lmfit import Minimizer, Parameters, report_fit from lmfit.lineshapes import gaussian, lorentzian def residual(pars, x, data): model = (gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) + lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l'])) return model - data np.random.seed(0) x = np.linspace(0, 20.0, 601) data = (gaussian(x, 21, 6.1, 1.0) + lorentzian(x, 10, 9.6, 1.3) + np.random.normal(scale=0.1, size=x.size)) pfit = Parameters() # pfit.add(name='amp_g', value=10) # pfit.add(name='amp_l', value=10) # pfit.add(name='cen_g', value=5) # pfit.add(name='peak_split', value=2.5, min=0, max=5, vary=True) # pfit.add(name='cen_l', expr='peak_split+cen_g') # pfit.add(name='wid_g', value=1) # pfit.add(name='wid_l', expr='wid_g') pfit.add(name='amp_g', value=10) pfit.add(name='amp_l', value=10) pfit.add(name='cen_g', value=5) pfit.add(name='cen_l', value=10)
def test_constraints2(): """add a user-defined function to symbol table""" def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) yl = lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) def width_func(wpar): """ """ return 2*wpar myfit.params._asteval.symtable['wfun'] = width_func try: myfit.params.add(name='wid_l', expr='wfun(wid_g)') except: assert(False) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params) pfit= result.params fit = residual(result.params, x) assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value)
offset = pars['line_off'].value model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) if HASPYLAB: pylab.plot(x, data, 'r+') pfit = [Parameter(name='amp_g', value=10), Parameter(name='cen_g', value=9), Parameter(name='wid_g', value=1), Parameter(name='amp_tot', value=20), Parameter(name='amp_l', expr='amp_tot - amp_g'), Parameter(name='cen_l', expr='1.5+cen_g'), Parameter(name='wid_l', expr='2*wid_g'),
def mypvoigt(x, amp, center, fwhm, frac): sig = fwhm * 0.424660900144 return ((1 - frac) * gaussian(x, amp, center, sig) + frac * lorentzian(x, amp, center, sig))
# Test that FT{Gaussian} = Gaussian, and FT{exponential} = Lorentzian x = np.arange(-0.1, 0.5, 0.0004) # energy domain, in meV # items are (tau, beta, intensities). Assumed that tau unit is picoseconds trios = [ (20.0, 2.0, gaussian(x, amplitude=1.0, center=0.0, sigma=planck_constant / (np.sqrt(2.0) * 20.0 * np.pi))), ( 100.0, 1.0, # sigma below is actually the HWHM lorentzian(x, amplitude=1.0, center=0.0, sigma=planck_constant / (2 * np.pi * 100.0))) ] @pytest.mark.parametrize('tau, beta, y', trios) def test_lineshapes(tau, beta, y): model = StretchedExponentialFTModel() params = model.guess(y, x=None) # Stray away from optimal parameters [ params[name].set(value=val) for name, val in dict( amplitude=3.0, center=0.0002, tau=50.0, beta=1.5).items() ] r = model.fit(y, params, x=x) all_params = 'tau beta amplitude center'.split()
pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) model += lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) return (model - data) n = 601 random.seed(0) x = linspace(0, 20.0, n) data = (gaussian(x, 21, 6.1, 1.2) + lorentzian(x, 10, 9.6, 1.3) + random.normal(scale=0.1, size=n)) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='amp_l', value=10) pfit.add(name='cen_g', value=5) pfit.add(name='peak_split', value=2.5, min=0, max=5, vary=True) pfit.add(name='cen_l', expr='peak_split+cen_g') pfit.add(name='wid_g', value=1) pfit.add(name='wid_l', expr='wid_g') mini = Minimizer(residual, pfit, fcn_args=(x, data)) out = mini.leastsq() report_fit(out.params)
def test_constraints(with_plot=True): with_plot = with_plot and WITHPLOT def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) yl = lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma n = 201 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x * 0.5) if with_plot: pylab.plot(x, data, 'r+') pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x, ), fcn_kws={ 'sigma': sigma, 'data': data }, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) myfit.leastsq() print(' Nfev = ', myfit.nfev) print(myfit.chisqr, myfit.redchi, myfit.nfree) report_fit(myfit.params, min_correl=0.3) fit = residual(myfit.params, x) if with_plot: pylab.plot(x, fit, 'b-') assert (myfit.params['cen_l'].value == 1.5 + myfit.params['cen_g'].value) assert (myfit.params['amp_l'].value == myfit.params['amp_tot'].value - myfit.params['amp_g'].value) assert (myfit.params['wid_l'].value == 2 * myfit.params['wid_g'].value) # now, change fit slightly and re-run myfit.params['wid_l'].expr = '1.25*wid_g' myfit.leastsq() report_fit(myfit.params, min_correl=0.4) fit2 = residual(myfit.params, x) if with_plot: pylab.plot(x, fit2, 'k') pylab.show() assert (myfit.params['cen_l'].value == 1.5 + myfit.params['cen_g'].value) assert (myfit.params['amp_l'].value == myfit.params['amp_tot'].value - myfit.params['amp_g'].value) assert (myfit.params['wid_l'].value == 1.25 * myfit.params['wid_g'].value)
def test_constraints2(): """add a user-defined function to symbol table""" def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) yl = lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x * 0.5) pfit = [ Parameter(name='amp_g', value=10), Parameter(name='cen_g', value=9), Parameter(name='wid_g', value=1), Parameter(name='amp_tot', value=20), Parameter(name='amp_l', expr='amp_tot - amp_g'), Parameter(name='cen_l', expr='1.5+cen_g'), Parameter(name='line_slope', value=0.0), Parameter(name='line_off', value=0.0) ] sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x, ), fcn_kws={ 'sigma': sigma, 'data': data }, scale_covar=True) def width_func(wpar): """ """ return 2 * wpar myfit.params._asteval.symtable['wfun'] = width_func myfit.params.add(name='wid_l', expr='wfun(wid_g)') myfit.leastsq() print(' Nfev = ', myfit.nfev) print(myfit.chisqr, myfit.redchi, myfit.nfree) report_fit(myfit.params) pfit = myfit.params fit = residual(myfit.params, x) assert (pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert (pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert (pfit['wid_l'].value == 2 * pfit['wid_g'].value)
def residual(pars, x, data): model = (gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) + lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l'])) return model - data
out = mod.fit(yn, pars, x=xs) out2 = mod.fit(yn, pars, x=xs, fit_kws={'Dfun': dfunc_gaussian, 'col_deriv': 1}) print('lmfit without dfunc **************') print('number of function calls: ', out.nfev) print('params', out.best_values) print('lmfit with dfunc *****************') print('number of function calls: ', out2.nfev) print('params', out2.best_values) print('\n \n') out2.plot(datafmt='.') print('**********************************') print('***** Test Lorentzian ************') print('**********************************') ys = lorentzian(xs, 2.5, 0, 0.5) yn = ys + 0.1*np.random.normal(size=len(xs)) mod = LorentzianModel() pars = mod.guess(yn, xs) out = mod.fit(yn, pars, x=xs) out2 = mod.fit(yn, pars, x=xs, fit_kws={'Dfun': dfunc_lorentzian, 'col_deriv': 1}) print('lmfit without dfunc **************') print('number of function calls: ', out.nfev) print('params', out.best_values) print('lmfit with dfunc *****************') print('number of function calls: ', out2.nfev) print('params', out2.best_values) print('\n \n') out2.plot(datafmt='.')
def teixeira_water(x, amplitude=1.0, center=1.0, tau=1.0, dcf=1.0, q=1.0): dq2 = dcf * q * q hwhm = hbar * dq2 / (1 + tau * dq2) return lorentzian(x, amplitude=amplitude, center=center, sigma=hwhm)
tau = max(y) / amplitude # assumed beta==1.0 return self.make_params(amplitude=amplitude, center=center, tau=tau, beta=beta) # Test that FT{Gaussian} = Gaussian, and FT{exponential} = Lorentzian x = np.arange(-0.1, 0.5, 0.0004) # energy domain, in meV # items are (tau, beta, intensities). Assumed that tau unit is picoseconds trios = [(20.0, 2.0, gaussian(x, amplitude=1.0, center=0.0, sigma=planck_constant/(np.sqrt(2.0)*20.0*np.pi))), (100.0, 1.0, # sigma below is actually the HWHM lorentzian(x, amplitude=1.0, center=0.0, sigma=planck_constant / (2 * np.pi * 100.0))) ] @pytest.mark.parametrize('tau, beta, y', trios) def test_lineshapes(tau, beta, y): model = StretchedExponentialFTModel() params = model.guess(y, x=None) # Stray away from optimal parameters [params[name].set(value=val) for name, val in dict(amplitude=3.0, center=0.0002, tau=50.0, beta=1.5).items()] r = model.fit(y, params, x=x) all_params = 'tau beta amplitude center'.split() assert_allclose([tau, beta, 1.0, 0.0], [r.params[p].value for p in all_params], rtol=0.1, atol=0.000001)
def test_constraints(): def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma n = 201 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x * 0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x, ), fcn_kws={ 'sigma': sigma, 'data': data }, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) result = myfit.leastsq() print(' Nfev = ', result.nfev) print(result.chisqr, result.redchi, result.nfree) report_fit(result.params, min_correl=0.3) fit = residual(result.params, x) assert (result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert (result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert (result.params['wid_l'].value == 2 * result.params['wid_g'].value) # now, change fit slightly and re-run myfit.params['wid_l'].expr = '1.25*wid_g' result = myfit.leastsq() report_fit(result.params, min_correl=0.4) fit2 = residual(result.params, x) assert (result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert (result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert (result.params['wid_l'].value == 1.25 * result.params['wid_g'].value)
def test_constraints(with_plot=True): with_plot = with_plot and WITHPLOT def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma n = 201 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) if with_plot: pylab.plot(x, data, 'r+') pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params, min_correl=0.3) fit = residual(result.params, x) if with_plot: pylab.plot(x, fit, 'b-') assert(result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert(result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert(result.params['wid_l'].value == 2 * result.params['wid_g'].value) # now, change fit slightly and re-run myfit.params['wid_l'].expr = '1.25*wid_g' result = myfit.leastsq() report_fit(result.params, min_correl=0.4) fit2 = residual(result.params, x) if with_plot: pylab.plot(x, fit2, 'k') pylab.show() assert(result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert(result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert(result.params['wid_l'].value == 1.25 * result.params['wid_g'].value)
def ltz(): r"""Sample data is a Lorentzian""" x = np.arange(-0.1, 0.5, 0.0004) # energy domain, in meV params = dict(amplitude=1.0, center=0.0, sigma=0.025) y = lorentzian(x, **params) return dict(x=x, y=y, p=params)
def find_grain_diameter(X, Y, min_size, max_size, size_step, return_figure, peaks_params, is_bg_active): """ New parameters are stored in peaks_params. The old ones are still present to provide compatibility with old code. :param X: :param Y: :param min_size: :param max_size: :param size_step: :param center: :param gamma_0: :param peak_height: :param return_figure: :param sample_type: :param peaks_params: [[center, gamma_0, amplitude, from, to, is_visible, is_lorentz, is fano], ...] :return: """ best_d = -1 best_sigma = -1 best_center = -1 best_amplitude = -1 best_q = 5 X_ex = X max_y = max(Y) x_range = (X > 400) * (X < 600) lin_mod = LinearModel(prefix="background_", min=0, max=0.5 * max_y) pars = lin_mod.guess(Y, x=X) final_mod = lin_mod for ii in range(0, len(peaks_params)): if peaks_params[ii][6] == True: mod = LorentzianModel(prefix="l" + str(ii) + '_') pars.update(mod.make_params()) pars['l' + str(ii) + '_center'].set(peaks_params[ii][0], min=peaks_params[ii][3], max=peaks_params[ii][4]) pars['l' + str(ii) + '_sigma'].set(peaks_params[ii][1]) pars['l' + str(ii) + '_amplitude'].set(peaks_params[ii][2], min=0) #, max=max_y) elif peaks_params[ii][7] == True: mod = Model(fano_function) pars.update(mod.make_params()) pars['q'].set( -4, min=-20, max=0 ) #q may be negative as well as positive, the most common values for q: [-1,5] pars['center'].set(peaks_params[ii][0], vary=True) pars['sigma'].set(peaks_params[ii][1], min=0.1, vary=True) pars['amplitude'].set(peaks_params[ii][2], min=0) else: mod = Model( total_intensity_fit_func ) #total_intensity_fit_func(omega, d, N, center, gamma_0, amplitude) pars.update(mod.make_params()) pars['d'].set((max_size - min_size), min=min_size, max=max_size) pars['N'].set(100, vary=False) pars['center'].set(peaks_params[ii][0], vary=False) pars['sigma'].set(peaks_params[ii][1], vary=False) pars['amplitude'].set(peaks_params[ii][2], min=0, max=max_y) final_mod = final_mod + mod ###########PLOT & RETURN###################################### if return_figure: my_figure = plt.Figure() my_plot = my_figure.add_subplot(111) legend_labels = [] for ax in my_figure.axes: ax.set_xlabel(u'\u03C9' + ' [cm^-1]') ax.set_ylabel('Intensity [arb.]') my_plot.plot(X[x_range], Y[x_range], "ro") legend_labels.append('Data') out = final_mod.fit(Y[x_range], pars, x=X[x_range]) if not out.success: print("!!!!!!!!!!!!!FIT HAVE FAILED!!!!!!!!!!!") legend_labels = ['FIT FAILED!'] if return_figure: my_plot.legend(legend_labels) return best_d, best_sigma, best_center, best_amplitude, my_figure else: return best_d, best_sigma, best_center, best_amplitude elif not return_figure: if (peaks_params[0][6] == True): best_sigma = out.best_values['l' + str(0) + '_sigma'] best_center = out.best_values['l' + str(0) + '_center'] best_amplitude = out.best_values['l' + str(0) + '_amplitude'] return 0, best_sigma, best_center, best_amplitude elif (peaks_params[0][7] == True): best_sigma = out.best_values['sigma'] best_center = out.best_values['center'] best_amplitude = out.best_values['amplitude'] best_q = out.best_values['q'] print(best_q) return best_q, best_sigma, best_center, best_amplitude else: best_sigma = out.best_values['sigma'] best_center = out.best_values['center'] best_amplitude = out.best_values['amplitude'] best_d = out.best_values['d'] print(best_d) return best_d, best_sigma, best_center, best_amplitude else: print(out.fit_report(min_correl=0.5)) legend_labels.append('Best fit') my_plot.plot(X[x_range], out.best_fit, "b-") my_plot.plot( X[x_range], out.best_values['background_slope'] * X[x_range] + out.best_values['background_intercept'], '--') legend_labels.append('background') for jj in range(0, len(peaks_params)): if (peaks_params[jj][6] == True): sigma = out.best_values['l' + str(jj) + '_sigma'] center = out.best_values['l' + str(jj) + '_center'] amplitude = out.best_values['l' + str(jj) + '_amplitude'] legend_labels.append('l' + str(jj)) my_plot.plot( X[x_range], lorentzian(X[x_range], center=center, sigma=sigma, amplitude=amplitude), '--') elif (peaks_params[jj][7] == True): sigma = out.best_values['sigma'] center = out.best_values['center'] amplitude = out.best_values['amplitude'] q = out.best_values['q'] legend_labels.append('fano; q=' + str(q)) my_plot.plot( X[x_range], fano_function(X[x_range], q, center, sigma, amplitude), '--') else: sigma = out.best_values['sigma'] center = out.best_values['center'] amplitude = out.best_values['amplitude'] d = out.best_values['d'] N = out.best_values['N'] legend_labels.append('fc; d=' + str(d)) my_plot.plot( X[x_range], total_intensity_fit_func(X[x_range], d, N, center, sigma, amplitude), '--') if (peaks_params[0][7] == True): my_figure.suptitle( "q:{0:.1f}[nm] omega:{1:.4f}[cm^-1] sigma:{2:.4f}[cm^-1] inten:{3:.4}[arb]" .format(float(best_q), float(best_center), float(best_sigma), float(best_amplitude))) else: my_figure.suptitle( "d:{0:.1f}[nm] omega:{1:.4f}[cm^-1] sigma:{2:.4f}[cm^-1] inten:{3:.4}[arb]" .format(float(best_d), float(best_center), float(best_sigma), float(best_amplitude))) my_plot.legend(legend_labels, loc=2) return best_d, best_sigma, best_center, best_amplitude, my_figure
offset = pars['line_off'] model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma n = 601 xmin = 0. xmax = 20.0 random.seed(0) x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x * 0.5) if HASPYLAB: pylab.plot(x, data, 'r+') pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0)
model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 random.seed(0) x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) if HASPYLAB: pylab.plot(x, data, 'r+') pfit = [Parameter(name='amp_g', value=10), Parameter(name='cen_g', value=9), Parameter(name='wid_g', value=1), Parameter(name='amp_tot', value=20), Parameter(name='amp_l', expr='amp_tot - amp_g'), Parameter(name='cen_l', expr='1.5+cen_g'), Parameter(name='wid_l', expr='2*wid_g'),