def test_eval_components(self): model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') model3 = models.ConstantModel(prefix='bkg_') mod = model1 + model2 + model3 pars = mod.make_params() values1 = dict(amplitude=7.10, center=1.1, sigma=2.40) values2 = dict(amplitude=12.2, center=2.5, sigma=0.5) data = (1.01 + gaussian(x=self.x, **values1) + gaussian(x=self.x, **values2) + 0.05*self.noise) pars['g1_sigma'].set(2) pars['g1_center'].set(1, max=1.5) pars['g1_amplitude'].set(3) pars['g2_sigma'].set(1) pars['g2_center'].set(2.6, min=2.0) pars['g2_amplitude'].set(1) pars['bkg_c'].set(1.88) result = mod.fit(data, params=pars, x=self.x) self.assertTrue(abs(result.params['g1_amplitude'].value - 7.1) < 1.5) self.assertTrue(abs(result.params['g2_amplitude'].value - 12.2) < 1.5) self.assertTrue(abs(result.params['g1_center'].value - 1.1) < 0.2) self.assertTrue(abs(result.params['g2_center'].value - 2.5) < 0.2) self.assertTrue(abs(result.params['bkg_c'].value - 1.0) < 0.25) comps = mod.eval_components(x=self.x) assert 'bkg_' in comps
def test_composite_has_bestvalues(self): # test that a composite model has non-empty best_values model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') mod = model1 + model2 pars = mod.make_params() values1 = dict(amplitude=7.10, center=1.1, sigma=2.40) values2 = dict(amplitude=12.2, center=2.5, sigma=0.5) data = (gaussian(x=self.x, **values1) + gaussian(x=self.x, **values2) + 0.1*self.noise) pars['g1_sigma'].set(value=2) pars['g1_center'].set(value=1, max=1.5) pars['g1_amplitude'].set(value=3) pars['g2_sigma'].set(value=1) pars['g2_center'].set(value=2.6, min=2.0) pars['g2_amplitude'].set(value=1) result = mod.fit(data, params=pars, x=self.x) self.assertTrue(len(result.best_values) == 6) self.assertTrue(abs(result.params['g1_amplitude'].value - 7.1) < 0.5) self.assertTrue(abs(result.params['g2_amplitude'].value - 12.2) < 0.5) self.assertTrue(abs(result.params['g1_center'].value - 1.1) < 0.2) self.assertTrue(abs(result.params['g2_center'].value - 2.5) < 0.2) for _, par in pars.items(): assert len(repr(par)) > 5
def test_composite_plotting(self): # test that a composite model has non-empty best_values pytest.importorskip("matplotlib") import matplotlib matplotlib.use('Agg') model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') mod = model1 + model2 pars = mod.make_params() values1 = dict(amplitude=7.10, center=1.1, sigma=2.40) values2 = dict(amplitude=12.2, center=2.5, sigma=0.5) data = (gaussian(x=self.x, **values1) + gaussian(x=self.x, **values2) + 0.1*self.noise) pars['g1_sigma'].set(2) pars['g1_center'].set(1, max=1.5) pars['g1_amplitude'].set(3) pars['g2_sigma'].set(1) pars['g2_center'].set(2.6, min=2.0) pars['g2_amplitude'].set(1) result = mod.fit(data, params=pars, x=self.x) fig, ax = result.plot(show_init=True) assert isinstance(fig, matplotlib.figure.Figure) assert isinstance(ax, matplotlib.axes.GridSpec) comps = result.eval_components(x=self.x) assert len(comps) == 2 assert 'g1_' in comps
def test_sum_of_two_gaussians(self): # two user-defined gaussians model1 = self.model f2 = lambda x, amp, cen, sig: gaussian( x, amplitude=amp, center=cen, sigma=sig) model2 = Model(f2) values1 = self.true_values() values2 = {'cen': 2.45, 'sig': 0.8, 'amp': 3.15} data = gaussian(x=self.x, **values1) + f2(x=self.x, ** values2) + self.noise / 3.0 model = self.model + model2 pars = model.make_params() pars['sigma'].set(value=2, min=0) pars['center'].set(value=1, min=0.2, max=1.8) pars['amplitude'].set(value=3, min=0) pars['sig'].set(value=1, min=0) pars['cen'].set(value=2.4, min=2, max=3.5) pars['amp'].set(value=1, min=0) true_values = dict(list(values1.items()) + list(values2.items())) result = model.fit(data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01) # user-defined models with common parameter names # cannot be added, and should raise f = lambda: model1 + model1 self.assertRaises(NameError, f) # two predefined_gaussians, using suffix to differentiate model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') model = model1 + model2 true_values = { 'g1_center': values1['center'], 'g1_amplitude': values1['amplitude'], 'g1_sigma': values1['sigma'], 'g2_center': values2['cen'], 'g2_amplitude': values2['amp'], 'g2_sigma': values2['sig'] } pars = model.make_params() pars['g1_sigma'].set(2) pars['g1_center'].set(1) pars['g1_amplitude'].set(3) pars['g2_sigma'].set(1) pars['g2_center'].set(2.4) pars['g2_amplitude'].set(1) result = model.fit(data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01) # without suffix, the names collide and Model should raise model1 = models.GaussianModel() model2 = models.GaussianModel() f = lambda: model1 + model2 self.assertRaises(NameError, f)
def trfit2G(x, y, hints): model = models.GaussianModel(prefix='one_') + models.GaussianModel( prefix='two_') parnames = model.param_names pars = model.make_params() for j, n in enumerate(parnames): pars[n].set(value=hints[j], vary=True) result = model.fit(y, pars, x=x) print(result.fit_report()) return result
def histogram(hist_data, bins, minimum, maximum): """Method for fitting a Gaussian curve to the histogram data. Arguments: hist_data (array like): list or array containing the data for which to make a histogram. bins (int): ammount of bins for the histogram. minimum (float): the minimum value to contain in the histogram. maximum (float): the maximum value to contain in the histogram. Returns: The data for the histogram plot as well as the Gaussian curve plot. """ hist_data2 = [x for x in hist_data if x <= maximum and x >= minimum] y, x = np.histogram(hist_data2, bins=bins) x_new = [((x[i] + x[i - 1]) / 2) for i in range(1, len(x))] max_freq = max(y) mean = x_new[y.argmax()] sigma = (x[1] - x[0]) * 4 gauss = models.GaussianModel() fit = gauss.fit(y, x=x_new, center=mean, amplitude=max_freq, sigma=sigma, nan_policy='omit') return x, y, x_new, fit.best_fit
def test_change_prefix(self): mod = models.GaussianModel(prefix='b') mod.prefix = 'c' params = mod.make_params() names = params.keys() all_begin_with_c = all([n.startswith('c') for n in names]) self.assertTrue(all_begin_with_c)
def make_peak_model(settings): if settings.peak_model == "GaussDerivative": return lmfit_custom_models.GaussDerivativeModel() elif settings.peak_model == "Voigt": return lmfit_models.PseudoVoigtModel() else: return lmfit_models.GaussianModel()
def test_sum_composite_models(self): # test components of composite model created adding composite model model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') model3 = models.GaussianModel(prefix='g3_') model4 = models.GaussianModel(prefix='g4_') model_total1 = (model1 + model2) + model3 for mod in [model1, model2, model3]: self.assertTrue(mod in model_total1.components) model_total2 = model1 + (model2 + model3) for mod in [model1, model2, model3]: self.assertTrue(mod in model_total2.components) model_total3 = (model1 + model2) + (model3 + model4) for mod in [model1, model2, model3, model4]: self.assertTrue(mod in model_total3.components)
def test_model_with_prefix(self): # model with prefix of 'a' and 'b' mod = models.GaussianModel(prefix='a') vals = {'center': 2.45, 'sigma': 0.8, 'amplitude': 3.15} data = gaussian(x=self.x, **vals) + self.noise/3.0 pars = mod.guess(data, x=self.x) self.assertTrue('aamplitude' in pars) self.assertTrue('asigma' in pars) out = mod.fit(data, pars, x=self.x) self.assertTrue(out.params['aamplitude'].value > 2.0) self.assertTrue(out.params['acenter'].value > 2.0) self.assertTrue(out.params['acenter'].value < 3.0) mod = models.GaussianModel(prefix='b') data = gaussian(x=self.x, **vals) + self.noise/3.0 pars = mod.guess(data, x=self.x) self.assertTrue('bamplitude' in pars) self.assertTrue('bsigma' in pars)
def fit_correlation(A, rr=None, ax=None): """ Fit a Gaussian + a constant to the horizontal and vertical cental lineout cut of A. Args: A: autocorrelation image rr: +/- number of pixel around the central point to consider. If None the entire lineout is fitted """ xx = A.shape[0] // 2 yy = A.shape[1] // 2 if rr is None: horiz = A[xx, :] vert = A[:, yy] else: horiz = A[xx, yy - rr:yy + rr] vert = A[xx - rr:xx + rr, yy] data = [vert, horiz] titles = ['vertical', 'horizontal'] if ax is None: fig, ax = plt.subplots(nrows=2, figsize=(10, 10)) for ii, dat in enumerate(data): center = np.where(np.isnan(dat))[0][0] gmodel = models.GaussianModel( nan_policy='omit') + models.ConstantModel(nan_policy='omit') params = gmodel.make_params() params['amplitude'].set(value=1.) params['sigma'].set(value=1.) params['center'].set(value=center) params['c'].set(value=1.) x = np.arange(dat.shape[0]) res = gmodel.fit( dat, params, x=x, method='leastsq') #, fit_kws={'ftol':1e-10, 'xtol':1e-10}) xfit = np.arange(0, 2 * center, 0.1) ax[ii].plot(xfit, res.eval(x=xfit), color='purple', linewidth=2, label='sigma = {:.2f} +/- {:.2f}'.format( res.params['sigma'].value, res.params['sigma'].stderr)) ax[ii].plot(dat, 'o', color='orange') ax[ii].legend(loc='upper right') ax[ii].set_title(titles[ii]) ax[ii].set_xlabel('Pixel') ax[ii].set_ylabel('Correlation') print(res.fit_report()) print('\n') plt.tight_layout() plt.show() return res
def test_change_prefix(self): "should fail" mod = models.GaussianModel(prefix='b') set_prefix_failed = None try: mod.prefix = 'c' set_prefix_failed = False except AttributeError: set_prefix_failed = True except: set_prefix_failed = None self.assertTrue(set_prefix_failed)
def test_change_prefix(self): "should pass!" mod = models.GaussianModel(prefix='b') set_prefix_failed = None try: mod.prefix = 'c' set_prefix_failed = False except AttributeError: set_prefix_failed = True except Exception: set_prefix_failed = None self.assertFalse(set_prefix_failed) new_expr = mod.param_hints['fwhm']['expr'] self.assertTrue('csigma' in new_expr) self.assertFalse('bsigma' in new_expr)
def test_hints_for_peakmodels(self): # test that height/fwhm do not cause asteval errors. x = np.linspace(-10, 10, 101) y = np.sin(x / 3) + x/100. m1 = models.LinearModel(prefix='m1_') params = m1.guess(y, x=x) m2 = models.GaussianModel(prefix='m2_') params.update(m2.make_params()) _m = m1 + m2 # noqa: F841 param_values = {name: p.value for name, p in params.items()} self.assertTrue(param_values['m1_intercept'] < -0.0) self.assertEqual(param_values['m2_amplitude'], 1)
def gaussian(self, oversample_multiplier=1, delta_rp=0, mz_overlay=1): ''' Legacy gaussian lineshape analysis function ''' # 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) ) #self.resolving_power) # stardart deviation sigma = self.fwhm / (2 * sqrt(2 * log(2))) # half width baseline distance #hw_base_distance = (3.2 * s) #match_loz_factor = 3 #n_d = hw_base_distance * match_loz_factor #mz_domain = linspace( # self.mz_exp - n_d, self.mz_exp + n_d, 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) ) #calc_abundance = norm.pdf(mz_domain, self.mz_exp, s) model = models.GaussianModel() amplitude = (sqrt(2 * pi) * sigma) * self.abundance params = model.make_params(center=self.mz_exp, amplitude=amplitude, sigma=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 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 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)
import pandas as pd import numpy as np import matplotlib.pyplot as plt from lmfit import models spectrum_cs = pd.read_csv('Cs137_spectrum.csv') spectrum_cs['y_err'] = np.sqrt(spectrum_cs['counts']) sel1 = spectrum_cs.query('pulseheight >= 1000 and pulseheight <= 1500') model = models.GaussianModel() + models.LinearModel() fit = model.fit(sel1['counts'], x=sel1['pulseheight'], weights=1/sel1['y_err'], center=1200, slope=0) # fit.plot(numpoints=100) center_cs = fit.params['center'] # print(center_cs.value, center_cs.stderr) spectrum_na = pd.read_csv('Na22_spectrum.csv') spectrum_na['y_err'] = np.sqrt(spectrum_na['counts']) sel2 = spectrum_na.query('pulseheight >= 800 and pulseheight <= 1200') fit2 = model.fit(sel2['counts'], x=sel2['pulseheight'], weights=1/sel2['y_err'], center=980, sigma=40, amplitude=1000, slope=0) # fit2.plot(numpoints=100) center_na_1 = fit2.params['center'] # print(center_na_1.value, center_na_1.stderr) sel3 = spectrum_na.query('pulseheight >= 2200 and pulseheight <= 2700') fit3 = model.fit(sel3['counts'], x=sel3['pulseheight'], weights=1/sel3['y_err'], center=2400, sigma=40, amplitude=110, slope=0) # fit3.plot(numpoints=100) center_na_2 = fit3.params['center']
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()' )
def test_model_name(self): # test setting the name for built-in models mod = models.GaussianModel(name='user_name') self.assertEqual(mod.name, "Model(user_name)")
def model_gen(V_series, dQdV_series, cd, i, cyc, thresh): """Develops initial model and parameters for battery data fitting. V_series = Pandas series of voltage data dQdV_series = Pandas series of differential capacity data cd = either 'c' for charge and 'd' for discharge. i = list of peak indices found by peak finder Output: par = lmfit parameters object mod = lmfit model object""" # generates numpy arrays for use in fitting sigx_bot, sigy_bot = cd_dataframe(V_series, dQdV_series, cd) if len(sigx_bot) > 5 and sigx_bot[5] > sigx_bot[1]: # check if the voltage values are increasing - the right order for # gaussian sigx_bot_new = sigx_bot sigy_bot_new = sigy_bot newi = i else: sigx_bot_new = sigx_bot[::-1] # reverses the order of elements in the array sigy_bot_new = sigy_bot[::-1] newi = np.array([], dtype=int) for elem in i: # append a new index, because now everything is backwards newi = np.append(newi, int(len(sigx_bot_new) - elem - 1)) if all(newi) is False or len(newi) < 1: base_mod = models.GaussianModel(prefix='base_') mod = base_mod par = mod.make_params() else: # have to convert from inputted voltages to indices of peaks within # sigx_bot user_appended_ind = [] rev_user_append = [] if not isinstance(i, list): i = i.tolist() if not isinstance(newi, list): newi = newi.tolist() count = 0 for index in newi: # generates unique parameter strings based on index of peak center, sigma, amplitude, fraction, comb = label_gen(index) # generates a pseudo voigt fitting model gaus_loop = models.PseudoVoigtModel(prefix=comb) if count == 0: mod = gaus_loop par = mod.make_params() count = count + 1 else: mod = mod + gaus_loop par.update(gaus_loop.make_params()) count = count + 1 par[center].set(sigx_bot_new[index], vary=False) par[sigma].set((np.max(sigx_bot_new) - np.min(sigx_bot_new)) / 100) par[amplitude].set((np.mean(sigy_bot_new)) / 50, min=0) par[fraction].set(.5, min=0, max=1) # then add the gaussian after the peaks base_mod = models.GaussianModel(prefix='base_') mod = mod + base_mod base_par = base_mod.make_params() base_par['base_amplitude'].set(np.mean(sigy_bot_new)) # these are initial guesses for the base base_par['base_center'].set(np.mean(sigx_bot_new)) base_par['base_sigma'].set( (np.max(sigx_bot_new) - np.min(sigx_bot_new)) / 2) par.update(base_par) return par, mod, i
def model_gen(V_series, dQdV_series, cd, i, cyc, v_toappend, thresh): """Develops initial model and parameters for battery data fitting. V_series = Pandas series of voltage data dQdV_series = Pandas series of differential capacity data cd = either 'c' for charge and 'd' for discharge. v_toappend is the list of voltages to append to the peak indices Output: par = lmfit parameters object mod = lmfit model object""" # generates numpy arrays for use in fitting sigx_bot, sigy_bot = fitters.cd_dataframe(V_series, dQdV_series, cd) if len(sigx_bot)>5 and sigx_bot[5]>sigx_bot[1]: # check if the voltage values are increasing - the right order for gaussian sigx_bot_new = sigx_bot sigy_bot_new = sigy_bot newi = i else: sigx_bot_new = sigx_bot[::-1] # reverses the order of elements in the array sigy_bot_new = sigy_bot[::-1] newi = np.array([], dtype = int) for elem in i: # append a new index, because now everything is backwards newi = np.append(newi, int(len(sigx_bot_new) - elem - 1)) # creates a polynomial fitting object # prints a notice if no peaks are found if all(newi) is False or len(newi) < 1: notice = 'Cycle ' + str(cyc) + cd + \ ' in battery ' + ' has no peaks.' print(notice) base_mod = models.GaussianModel(prefix = 'base_') mod = base_mod # changed from PolynomialModel to Gaussian on 10-10-18 # Gaussian params are A, mew, and sigma # sets polynomial parameters based on a # guess of a polynomial fit to the data with no peaks #mod.set_param_hint('base_amplitude', min = 0) #mod.set_param_hint('base_sigma', min = 0.001) par = mod.make_params() # iterates over all peak indices else: # have to convert from inputted voltages to indices of peaks within sigx_bot user_appended_ind = [] rev_user_append = [] if len(v_toappend) > 0: for vapp in v_toappend: if sigx_bot.min()<=vapp<=sigx_bot.max(): #check if voltage given is valid ind_app= np.where(np.isclose(sigx_bot, float(vapp), atol = 0.1))[0][0] user_appended_ind.append(ind_app) rev_user_app = np.where(np.isclose(sigx_bot_new, float(vapp), atol = 0.1))[0][0] rev_user_append.append(rev_user_app) # this gives a final list of user appended indices i = i.tolist() + user_appended_ind newi = newi.tolist() + rev_user_append # combine the two lists of indices to get the final set of peak locations else: i = i.tolist() newi = newi.tolist() count = 0 for index in newi: # generates unique parameter strings based on index of peak center, sigma, amplitude, fraction, comb = fitters.label_gen( index) # generates a pseudo voigt fitting model gaus_loop = models.PseudoVoigtModel(prefix=comb) if count == 0: mod = gaus_loop #mod.set_param_hint(amplitude, min = 0.001) par = mod.make_params() #par = mod.guess(sigy_bot_new, x=sigx_bot_new) count = count + 1 else: mod = mod + gaus_loop #gaus_loop.set_param_hint(amplitude, min = 0.001) par.update(gaus_loop.make_params()) count = count + 1 # uses unique parameter strings to generate parameters # with initial guesses # in this model, the center of the peak is locked at the # peak location determined from PeakUtils par[center].set(sigx_bot_new[index], vary=False) # don't allow the centers of the peaks found by peakutsils to vary par[sigma].set((np.max(sigx_bot_new)-np.min(sigx_bot_new))/100) par[amplitude].set((np.mean(sigy_bot_new))/50, min=0) par[fraction].set(.5, min=0, max=1) # then add the gaussian after the peaks base_mod = models.GaussianModel(prefix = 'base_') mod = mod + base_mod base_par = base_mod.make_params() base_par['base_amplitude'].set(np.mean(sigy_bot_new)) # these are initial guesses for the base base_par['base_center'].set(np.mean(sigx_bot_new)) base_par['base_sigma'].set((np.max(sigx_bot_new)-np.min(sigx_bot_new))/2) # changed from PolynomialModel to Gaussian on 10-10-18 # Gaussian params are A, mew, and sigma # sets polynomial parameters based on a # guess of a polynomial fit to the data with no peaks #base_mod.set_param_hint('base_amplitude', min = 0) #base_mod.set_param_hint('base_sigma', min = 0.001) par.update(base_par) #mod.set_param_hint('base_height', min = 0, max = 0.01) #par = mod.guess(sigy_bot_new, x=sigx_bot_new) #print(cyc) return par, mod, i
def fit_peak(self, roi=None, xpeak=None, sigma_guess=None, model_name='gauss-erf-const', **kwargs): """ Main routine """ # Exit if no roi if roi is None: self.fit = None self.model_name = None else: self.model_name = model_name # Start timer tic = time.time() # --------- # Setup ROI # --------- self.set_roi(roi) x = self.get_x_roi() y = self.get_y_roi() y_sig = self.get_y_sig_roi() x_widths = self.get_x_widths_roi() # --------------------------- # Guesses based on input data # --------------------------- # Set peak center to center of ROI if not given if xpeak is None: xpeak = (x[0] + x[-1]) / 2. # Guess sigma if not provided if sigma_guess is None: fwhm_guess = self.guess_fwhm(xpeak) sigma_guess = fwhm_guess / FWHM_SIG_RATIO # Heights at the sides of the ROI left_shelf_height = y[0] right_shelf_height = y[-1] # Line guess lin_slope = (y[-1] - y[0]) / (x[-1] - x[0]) lin_intercept = y[0] - lin_slope * x[0] # Two peaks guess (33 and 66 percent through ROI) xpeak0 = x[0] + (x[-1] - x[0]) * 0.33 xpeak1 = x[0] + (x[-1] - x[0]) * 0.66 # Index of at the ROI center ix_half = int(round(float(len(x)) / 2.)) # ------------------- # Setup fitting model # ------------------- if model_name == 'gauss-erf-const': # Models erf_mod = models.StepModel(form='erf', prefix='erf_') gauss_mod = models.GaussianModel(prefix='gauss_') bk_mod = models.ConstantModel(prefix='bk_') # Initialize parameters pars = erf_mod.make_params() pars.update(gauss_mod.make_params()) pars.update(bk_mod.make_params()) # Erfc (sigma and center are locked to gauss below) pars['erf_amplitude'].set(right_shelf_height - left_shelf_height, max=0.) # Gauss pars['gauss_center'].set( xpeak ) # , min=xpeak - 2 * fwhm_guess, max=xpeak + 2 * fwhm_guess) pars['gauss_sigma'].set(sigma_guess) pars['gauss_amplitude'].set(np.sum(y * x_widths), min=0) # Background pars['bk_c'].set(left_shelf_height, min=0.) # Same center and sigma pars.add('erf_center', expr='gauss_center') pars.add('erf_sigma', expr='gauss_sigma * {}'.format(FWHM_SIG_RATIO)) self.model = gauss_mod + erf_mod + bk_mod elif model_name == 'double-gauss-line': # Models lin_mod = models.LinearModel(prefix='lin_') g0_mod = models.GaussianModel(prefix='gauss0_') g1_mod = models.GaussianModel(prefix='gauss1_') # Initialize parameters pars = lin_mod.make_params() pars.update(g0_mod.make_params()) pars.update(g1_mod.make_params()) # Line (background) pars['lin_slope'].set(lin_slope, max=0.) pars['lin_intercept'].set(lin_intercept) # Gauss 0 (left) pars['gauss0_center'].set( xpeak0 ) # , min=xpeak - 2 * fwhm_guess, max=xpeak + 2 * fwhm_guess) pars['gauss0_sigma'].set(sigma_guess) pars['gauss0_amplitude'].set(np.sum(y[:ix_half] * x_widths[:ix_half]), min=0) # Gauss 1 (right) pars['gauss1_center'].set( xpeak1 ) # , min=xpeak - 2 * fwhm_guess, max=xpeak + 2 * fwhm_guess) pars['gauss1_sigma'].set(sigma_guess) pars['gauss1_amplitude'].set(np.sum(y[ix_half:] * x_widths[ix_half:]), min=0) self.model = lin_mod + g0_mod + g1_mod else: raise NotImplementedError( 'Model ({}) not recognized'.format(model_name)) # ----------- # Perform fit # ----------- try: self.fit = self.model.fit(y, pars, x=x, weights=1. / y_sig) except: print("[ERROR] Couldn't fit peak") self.fit = None if self.verbosity > 0: print('Fit time: {:.3f} seconds'.format(time.time() - tic))
def gaussian_fit(self): """Method for fitting a gaussian curve to the spectrum of possible quantum dots. Returns: A data frame containing the spectrum of a quantum dot as well as the gaussian curve plot data for that quantum dot. This method also returns a data frame with the fit statistics of all the fits. """ self.df5 = pd.DataFrame(columns=[ 'Slit Number', 'Centre', 'Centre_err', 'Sigma', 'Sigma_err', 'FWHM', 'FWHM_err', 'Height', 'Height_err' ]) QDot_slits = self.QDot_detection() if len(QDot_slits) > 0: self.plot_data = pd.DataFrame(columns=[f"{QDot_slits[0]}"], index=self.energies) else: self.plot_data = pd.DataFrame(index=self.energies) for slit_number in QDot_slits: sel = self.df4[f'{slit_number}'] self.plot_data[f'{slit_number}'] = sel # Makes a good first guess for the fit values of the gaussian max_intensity = max(sel) central_energy = sel[sel == max_intensity].index.values central_energy = central_energy[0] # Fits a gaussian model to the selected data and shows the output gauss = models.GaussianModel() fit = gauss.fit(sel, x=self.energies, weights=1 / np.sqrt(sel), center=central_energy, amplitude=max_intensity, sigma=1, nan_policy='omit') self.plot_data[f'{slit_number} best fit'] = fit.best_fit # Appends the fit data for the variables to a new dataframe and shows the fit results with errors fit_variables = [slit_number] for key in fit.params: if key in ['center', 'sigma', 'fwhm', 'height']: fit_variables.append(fit.params[key].value) fit_variables.append(fit.params[key].stderr) self.df5 = self.df5.append( { 'Slit Number': fit_variables[0], 'Centre': fit_variables[1], 'Centre_err': fit_variables[2], 'Sigma': fit_variables[3], 'Sigma_err': fit_variables[4], 'FWHM': fit_variables[5], 'FWHM_err': fit_variables[6], 'Height': fit_variables[7], 'Height_err': fit_variables[8] }, ignore_index=True) return self.plot_data, self.df5
def fit_gaussian(data, bins, ax, labels=True, basecolor='red', xy=(0, 0.9), gamma=-0.5): ########################################### """ Fit a Gaussian distribution to wind speed data paramters: data - input wind speed data to fit ax - axis to plot onto bins - x locations of bins from histogram """ colors = utils.get_nrelcolors() if basecolor == 'red': pcolor = colors['red'][1] elif basecolor is 'blue': pcolor = colors['blue'][0] else: pcolor = 'k' # get x and y data yvals, xvals = np.histogram(data, bins=bins) # center x values xvals = np.array([(xvals[i] + xvals[i + 1]) / 2 for i in range(len(xvals) - 1)]) model = lmfmodels.GaussianModel() # set initial parameter values params = model.make_params(amplitude=10, center=data.mean(), sigma=data.std(), gamma=gamma) # adjust parameters to best fit data. result = model.fit(yvals, params, x=xvals) fitdat = result.best_fit / len(data) ax.plot(xvals, result.best_fit * 1.0 / float(len(data)), color=pcolor, linewidth=2.5) if labels is True: # gamma = np.round(result.params['gamma'].value,2) sigma = np.round(result.params['sigma'].value, 2) center = np.round(result.params['center'].value, 2) amp = np.round(result.params['amplitude'].value, 2) if gamma > 0: xcoord = 0.95 else: xcoord = 0.05 if xy[0] > 1: xcoord = 0 xy = (xcoord + xy[0], xy[1]) ax.annotate( s='$A = {}$\n$\mu = {}$\n$\gamma = {}$\n$\sigma = {}$'.format( amp, center, gamma, sigma), xy=xy, xycoords='axes fraction', ha='right', va='top')
lCounts = np.array([]) lEnergy = np.array([]) lPicked = np.array([]) scanNo = 6386 date = 20 picked = 0 #marcroFilename = "C:\\Users\\wvx67826\\Desktop\\beam8 data\\MapNight2.txt" energyCalFilename = "C:\\Users\\wvx67826\\Desktop\\beam8 data\\energycalibration_Ru.dat" backgroundFilename = "C:\\Users\\wvx67826\\Desktop\\beam8 data\\backgound_Flux.dat" folderName = "C:\\Users\\wvx67826\\Desktop\\beam8 data\\2019 12 %s\\" %date metaFilename = folderName +"CCD Scan %i\\C_%i-AI.txt" %(scanNo,scanNo) Rd.read_file(metaFilename, metaStopKey = str(scanNo)) metaData = Rd.get_data() from lmfit import models model_1 = models.GaussianModel(prefix='peak_') model_2 = models.LinearModel(prefix='background_') model = model_1 + model_2 #print np.full((1,50),macroData["BL 8 Energy"][0]) def onpick(event): thisline = event.artist xdata = thisline.get_xdata() ydata = thisline.get_ydata() ind = event.ind points = np.array([xdata[ind]]) global lPicked
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 fitData(x, y): peaks, _ = signal.find_peaks(y, height=0.01, width=5) print peaks model_1 = models.GaussianModel(prefix='m1_') model_2 = models.GaussianModel(prefix='m2_') model_3 = models.GaussianModel(prefix='m3_') model_4 = models.LinearModel(prefix='l3_') model_5 = models.LorentzianModel(prefix='m4_') model = model_1 + model_2 + model_3 + model_4 + model_5 model_1.set_param_hint("amplitude", min=0.002, max=0.1) model_1.set_param_hint("sigma", min=0.00, max=0.025) model_1.set_param_hint("center", min=x[peaks[1]] - 0.05, max=x[peaks[1]] + 0.05) params_1 = model_1.make_params(amplitude=0.05, center=x[peaks[1]], sigma=0.01) model_2.set_param_hint("amplitude", min=1e-5, max=1e-3) model_2.set_param_hint("sigma", min=0.0005, max=0.08) model_2.set_param_hint("center", min=x[peaks[2]] - 0.075, max=x[peaks[2]] + 0.075) params_2 = model_2.make_params(amplitude=0.005, center=x[peaks[2]], sigma=0.03) model_3.set_param_hint("amplitude", min=1e-6, max=1e-2) model_3.set_param_hint("sigma", min=0.005, max=0.08) model_3.set_param_hint("center", min=x[peaks[1]] - 0.05, max=x[peaks[1]] + 0.1) params_3 = model_3.make_params(amplitude=1e-3, center=x[peaks[1]] + 0.040, sigma=0.04) """ model_4.set_param_hint("intercept", min = 1e-15, max = np.min(y)*1.5) model_4.set_param_hint("slope", min = 1e-16)""" params_4 = model_4.make_params(slope=1e-9, intercept=np.min(y)) model_5.set_param_hint("amplitude", min=1e-6, max=0.06) model_5.set_param_hint("sigma", min=0.00, max=0.025) model_5.set_param_hint("center", min=x[peaks[0]] - 0.05, max=x[peaks[0]] + 0.05) params_5 = model_5.make_params(amplitude=0.05, center=x[peaks[0]], sigma=0.01) params_1.update(params_2) params_1.update(params_3) params_1.update(params_4) params_1.update(params_5) params = params_1 output = model.fit(y, params, x=x) print output.fit_report() output.plot(data_kws={'markersize': 1}) plt.plot(x, y) plt.semilogy() plt.show(block=False) return output