def test_peak_like(): # mu = 0 # variance = 1.0 # sigma = np.sqrt(variance) # x = np.linspace(mu - 20*sigma, mu + 20*sigma, 100.0) # y = norm.pdf(x, mu, 1) data = np.loadtxt('../examples/test_peak.dat') x = data[:, 0] y = data[:, 1] check_height_fwhm(x, y, lineshapes.voigt, models.VoigtModel()) check_height_fwhm(x, y, lineshapes.pvoigt, models.PseudoVoigtModel()) check_height_fwhm(x, y, lineshapes.pearson7, models.Pearson7Model()) check_height_fwhm(x, y, lineshapes.moffat, models.MoffatModel()) check_height_fwhm(x, y, lineshapes.students_t, models.StudentsTModel()) check_height_fwhm(x, y, lineshapes.breit_wigner, models.BreitWignerModel()) check_height_fwhm(x, y, lineshapes.damped_oscillator, models.DampedOscillatorModel()) check_height_fwhm(x, y, lineshapes.dho, models.DampedHarmonicOscillatorModel()) check_height_fwhm(x, y, lineshapes.expgaussian, models.ExponentialGaussianModel()) check_height_fwhm(x, y, lineshapes.skewed_gaussian, models.SkewedGaussianModel()) check_height_fwhm(x, y, lineshapes.donaich, models.DonaichModel()) x = x - 9 # Lognormal will only fit peaks with centers < 1 check_height_fwhm(x, y, lineshapes.lognormal, models.LognormalModel())
def test_height_fwhm_calculation(peakdata): """Test for correctness of height and FWHM calculation.""" # mu = 0 # variance = 1.0 # sigma = np.sqrt(variance) # x = np.linspace(mu - 20*sigma, mu + 20*sigma, 100.0) # y = norm.pdf(x, mu, 1) x = peakdata[0] y = peakdata[1] check_height_fwhm(x, y, lineshapes.voigt, models.VoigtModel()) check_height_fwhm(x, y, lineshapes.pvoigt, models.PseudoVoigtModel()) check_height_fwhm(x, y, lineshapes.pearson7, models.Pearson7Model()) check_height_fwhm(x, y, lineshapes.moffat, models.MoffatModel()) check_height_fwhm(x, y, lineshapes.students_t, models.StudentsTModel()) check_height_fwhm(x, y, lineshapes.breit_wigner, models.BreitWignerModel()) check_height_fwhm(x, y, lineshapes.damped_oscillator, models.DampedOscillatorModel()) check_height_fwhm(x, y, lineshapes.dho, models.DampedHarmonicOscillatorModel()) check_height_fwhm(x, y, lineshapes.expgaussian, models.ExponentialGaussianModel()) check_height_fwhm(x, y, lineshapes.skewed_gaussian, models.SkewedGaussianModel()) check_height_fwhm(x, y, lineshapes.doniach, models.DoniachModel()) x = x-9 # Lognormal will only fit peaks with centers < 1 check_height_fwhm(x, y, lineshapes.lognormal, models.LognormalModel())
def doublet_peakshape_model(mainpeakpos=120, gamma=0.15, sigma=0.35, splitting=-0.84, ratio=2, prefix='a'): """Makes lmfit model of doublet shape. Model is composed of two voigts with fixed Lorentzian and Gaussian widths and fixed splitting and peak ratios. Args: mainpeakpos: Energy (eV) position of main peak. gamma: Lorentzian width (in voigt model). sigma: Gaussian width (in voigt model). splitting: Energy gap (eV) between the two components ratio: Ratio of peak heights a1/a2 Returns: lmfit model, lmfit pars Raises: Nothing. """ prefix1 = prefix + '1_' prefix2 = prefix + '2_' mod = models.VoigtModel(prefix=prefix1)+models.VoigtModel(prefix=prefix2) pars = mod.make_params() parsdict = dict([[prefix2+'amplitude',{'expr': prefix1+'amplitude*'+str(1/ratio), 'value': 1/ratio, 'vary': False}], [prefix2+'gamma', {'expr': prefix1+'gamma', 'value': gamma, 'vary': False}], [prefix2+'center', {'expr': prefix1+'center-'+str(splitting), 'value': mainpeakpos-splitting, 'vary': False}], #[prefix2+'fraction', {'expr': '', 'value': fraction, 'vary': False}], [prefix1+'sigma', {'expr': '', 'value': sigma, 'vary': False}], [prefix1+'gamma', {'expr': '', 'value': gamma, 'vary': False}], [prefix1+'center', {'expr': '', 'value': mainpeakpos, 'vary': True}], #[prefix1+'fraction', {'expr': '', 'value': fraction, 'vary': False}], [prefix2+'sigma', {'expr': prefix1+'sigma', 'value': sigma, 'vary': False}]]) for k,v in parsdict.items(): pars[k].set(vary=v['vary'],expr=v['expr']) for k,v in parsdict.items(): pars[k].value=v['value'] return mod, pars
def get_model(model_name, model_prefix=''): if model_name == 'voigt': mdl = models.VoigtModel(prefix=model_prefix) elif model_name == 'gauss': mdl = models.GaussianModel(prefix=model_prefix) elif model_name == 'constant': mdl = models.ConstantModel(prefix=model_prefix) elif model_name == 'linear': mdl = models.LinearModel(prefix=model_prefix) elif model_name == 'exp': mdl = models.ExponentialModel(prefix=model_prefix) elif model_name == 'logistic': mdl = models.StepModel(prefix=model_prefix, form='logistic') elif model_name == 'sine': mdl = models.SineModel(prefix=model_prefix) else: raise ValueError('Model name not recognized.') return mdl
def voigt(self, oversample_multiplier=1, delta_rp=0, mz_overlay=1): ''' Legacy function for voigt lineshape analysis ''' if self.resolving_power: # full width half maximum distance self.fwhm = (self.mz_exp / (self.resolving_power + delta_rp) ) #self.resolving_power) # stardart deviation sigma = self.fwhm / 3.6013 # half width baseline distance #mz_domain = linspace(self.mz_exp - hw_base_distance, # self.mz_exp + hw_base_distance, datapoint) mz_domain = self.get_mz_domain(oversample_multiplier, mz_overlay) # gaussian_pdf = lambda x0, x, s: (1/ math.sqrt(2*math.pi*math.pow(s,2))) * math.exp(-1 * math.pow(x-x0,2) / 2*math.pow(s,2) ) #TODO derive amplitude amplitude = (sqrt(2 * pi) * sigma) * self.abundance model = models.VoigtModel() params = model.make_params(center=self.mz_exp, amplitude=amplitude, sigma=sigma, gamma=sigma) calc_abundance = model.eval(params=params, x=mz_domain) return mz_domain, calc_abundance else: raise LookupError( 'resolving power is not defined, try to use set_max_resolving_power()' )
def test_height_and_fwhm_expression_evalution_in_builtin_models(): """Assert models do not throw an ZeroDivisionError.""" mod = models.GaussianModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9) params.update_constraints() mod = models.LorentzianModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9) params.update_constraints() mod = models.SplitLorentzianModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, sigma_r=1.0) params.update_constraints() mod = models.VoigtModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, gamma=1.0) params.update_constraints() mod = models.PseudoVoigtModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, fraction=0.5) params.update_constraints() mod = models.MoffatModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, beta=0.0) params.update_constraints() mod = models.Pearson7Model() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, expon=1.0) params.update_constraints() mod = models.StudentsTModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9) params.update_constraints() mod = models.BreitWignerModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, q=0.0) params.update_constraints() mod = models.LognormalModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9) params.update_constraints() mod = models.DampedOscillatorModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9) params.update_constraints() mod = models.DampedHarmonicOscillatorModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, gamma=0.0) params.update_constraints() mod = models.ExponentialGaussianModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, gamma=0.0) params.update_constraints() mod = models.SkewedGaussianModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, gamma=0.0) params.update_constraints() mod = models.SkewedVoigtModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, gamma=0.0, skew=0.0) params.update_constraints() mod = models.DoniachModel() params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, gamma=0.0) params.update_constraints() mod = models.StepModel() for f in ('linear', 'arctan', 'erf', 'logistic'): params = mod.make_params(amplitude=1.0, center=0.0, sigma=0.9, form=f) params.update_constraints() mod = models.RectangleModel() for f in ('linear', 'arctan', 'erf', 'logistic'): params = mod.make_params(amplitude=1.0, center1=0.0, sigma1=0.0, center2=0.0, sigma2=0.0, form=f) params.update_constraints()
def test_guess_modelparams(): """Tests for the 'guess' function of built-in models.""" x = np.linspace(-10, 10, 501) mod = models.ConstantModel() y = 6.0 + x*0.005 pars = mod.guess(y) assert_allclose(pars['c'].value, 6.0, rtol=0.01) mod = models.ComplexConstantModel(prefix='f_') y = 6.0 + x*0.005 + (4.0 - 0.02*x)*1j pars = mod.guess(y) assert_allclose(pars['f_re'].value, 6.0, rtol=0.01) assert_allclose(pars['f_im'].value, 4.0, rtol=0.01) mod = models.QuadraticModel(prefix='g_') y = -0.2 + 3.0*x + 0.005*x**2 pars = mod.guess(y, x=x) assert_allclose(pars['g_a'].value, 0.005, rtol=0.01) assert_allclose(pars['g_b'].value, 3.0, rtol=0.01) assert_allclose(pars['g_c'].value, -0.2, rtol=0.01) mod = models.PolynomialModel(4, prefix='g_') y = -0.2 + 3.0*x + 0.005*x**2 - 3.3e-6*x**3 + 1.e-9*x**4 pars = mod.guess(y, x=x) assert_allclose(pars['g_c0'].value, -0.2, rtol=0.01) assert_allclose(pars['g_c1'].value, 3.0, rtol=0.01) assert_allclose(pars['g_c2'].value, 0.005, rtol=0.1) assert_allclose(pars['g_c3'].value, -3.3e-6, rtol=0.1) assert_allclose(pars['g_c4'].value, 1.e-9, rtol=0.1) mod = models.GaussianModel(prefix='g_') y = lineshapes.gaussian(x, amplitude=2.2, center=0.25, sigma=1.3) y += np.random.normal(size=len(x), scale=0.004) pars = mod.guess(y, x=x) assert_allclose(pars['g_amplitude'].value, 3, rtol=2) assert_allclose(pars['g_center'].value, 0.25, rtol=1) assert_allclose(pars['g_sigma'].value, 1.3, rtol=1) mod = models.LorentzianModel(prefix='l_') pars = mod.guess(y, x=x) assert_allclose(pars['l_amplitude'].value, 3, rtol=2) assert_allclose(pars['l_center'].value, 0.25, rtol=1) assert_allclose(pars['l_sigma'].value, 1.3, rtol=1) mod = models.SplitLorentzianModel(prefix='s_') pars = mod.guess(y, x=x) assert_allclose(pars['s_amplitude'].value, 3, rtol=2) assert_allclose(pars['s_center'].value, 0.25, rtol=1) assert_allclose(pars['s_sigma'].value, 1.3, rtol=1) assert_allclose(pars['s_sigma_r'].value, 1.3, rtol=1) mod = models.VoigtModel(prefix='l_') pars = mod.guess(y, x=x) assert_allclose(pars['l_amplitude'].value, 3, rtol=2) assert_allclose(pars['l_center'].value, 0.25, rtol=1) assert_allclose(pars['l_sigma'].value, 1.3, rtol=1) mod = models.SkewedVoigtModel(prefix='l_') pars = mod.guess(y, x=x) assert_allclose(pars['l_amplitude'].value, 3, rtol=2) assert_allclose(pars['l_center'].value, 0.25, rtol=1) assert_allclose(pars['l_sigma'].value, 1.3, rtol=1)
def fit_peak(self, mz_extend=6, delta_rp=0, model='Gaussian'): ''' Model and fit peak lineshape by defined function - using lmfit module Do not oversample/resample/interpolate data points Better to go back to time domain and perform more zero filling Models allowed: Gaussian, Lorentz, Voigt Returns the calculated mz domain, initial defined abundance profile, and the fit peak results object from lmfit module mz_extend here extends the x-axis domain so that we have sufficient points either side of the apex to fit. Takes about 10ms per peak ''' start_index = self.start_scan - mz_extend if not self.start_scan == 0 else 0 final_index = self.final_scan + mz_extend if not self.final_scan == len( self._ms_parent.mz_exp_profile) else self.final_scan # check if MSPeak contains the resolving power info if self.resolving_power: # full width half maximum distance self.fwhm = (self.mz_exp / (self.resolving_power + delta_rp)) mz_domain = self._ms_parent.mz_exp_profile[start_index:final_index] abundance_domain = self._ms_parent.abundance_profile[ start_index:final_index] if model == 'Gaussian': # stardard deviation sigma = self.fwhm / (2 * sqrt(2 * log(2))) amplitude = (sqrt(2 * pi) * sigma) * self.abundance model = models.GaussianModel() params = model.make_params(center=self.mz_exp, amplitude=amplitude, sigma=sigma) elif model == 'Lorentz': # stardard deviation sigma = self.fwhm / 2 amplitude = sigma * pi * self.abundance model = models.LorentzianModel() params = model.make_params(center=self.mz_exp, amplitude=amplitude, sigma=sigma) elif model == 'Voigt': # stardard deviation sigma = self.fwhm / 3.6013 amplitude = (sqrt(2 * pi) * sigma) * self.abundance model = models.VoigtModel() params = model.make_params(center=self.mz_exp, amplitude=amplitude, sigma=sigma, gamma=sigma) else: raise LookupError('model lineshape not known or defined') #calc_abundance = model.eval(params=params, x=mz_domain) #Same as initial fit, returned in fit_peak object fit_peak = model.fit(abundance_domain, params=params, x=mz_domain) return mz_domain, fit_peak else: raise LookupError( 'resolving power is not defined, try to use set_max_resolving_power()' )