def fit_three_peaks(peak_data, pv_1_cent=3.43, pv_1_min=3.36, pv_1_max=3.44, pv_2_cent=3.52, pv_2_min=3.42, pv_2_max=3.55, pv_3_cent=3.59, pv_3_min=3.54, pv_3_max=3.6, initParams=None): """ Pseudo-Voigt fit to the lattice plane peak intensity for three peaks (adjust function to include more). Parameters for each peak also require limits and centres to be set in the case of overlapping peaks. Return results of the fit as an lmfit class, which contains the fitted parameters (amplitude, fwhm, etc.) and the fit line calculated using the fit parameters and 100x two-theta points. """ ttheta = peak_data[:, 0] intensity = peak_data[:, 1] PV_1 = PseudoVoigtModel(prefix='pv_1') PV_2 = PseudoVoigtModel(prefix='pv_2') PV_3 = PseudoVoigtModel(prefix='pv_3') model = PV_1 + PV_2 + PV_3 + Model(line) if initParams is None: # if reflection == '(0002),(110),(10-11)': use starting centres 3.43(min=3.36,max=3.44), 3.54(min=3.42,max=3.55), 3.59(min=3.54,max=3.6)... #if reflection == '(20-20),(11-22),(20-21)': use starting centres 6.32(min=6.23,max=6.33), 6.45(min=6.37,max=6.47), 6.54(min=6.46,max=6.56)... pars_1 = PV_1.guess(intensity, x=ttheta) #note, min and max values are not the same as bounds around the peak, but values that they can go up to! pars_1['pv_1center'].set(pv_1_cent, min=pv_1_min, max=pv_1_max) #pars_1['pv_1sigma'].set(min=0.001, max=0.1) #pars_1['pv_1amplitude'].set(min=0) #pars_1['pv_1height'].set(min=10) #pars_1['pv_1fwhm'].set(min=0.02, max=0.2) pars_2 = PV_2.guess(intensity, x=ttheta) pars_2['pv_2center'].set(pv_2_cent, min=pv_2_min, max=pv_2_max) #pars_2['pv_2sigma'].set(min=0.001, max=0.1) #pars_2['pv_2amplitude'].set(min=0) #pars_2['pv_2height'].set(min=10, max = 5000) #pars_2['pv_2fwhm'].set(min=0.02, max=0.2) pars_3 = PV_3.guess(intensity, x=ttheta) pars_3['pv_3center'].set(pv_3_cent, min=pv_3_min, max=pv_3_max) #pars_3['pv_3sigma'].set(min=0.001, max=0.1) #pars_3['pv_3amplitude'].set(min=1) #pars_3['pv_3height'].set(min=10) #pars_3['pv_3fwhm'].set(min=0.02, max=0.2) pars = pars_1 + pars_2 + pars_3 pars.add("constBG", 0) else: pars = initParams fit_results = model.fit(intensity, pars, x=ttheta) fit_ttheta = np.linspace(ttheta[0], ttheta[-1], 100) fit_line = [fit_ttheta, model.eval(fit_results.params, x=fit_ttheta)] return fit_results, fit_line
def fit_one_Psudo_Voigt(x_lst,y_lst): ''' Fits one Pseudo Voigt returns the results object ''' mod = PseudoVoigtModel(independent_vars=['x'],nan_policy='raise') x_lst = np.asarray(x_lst) y_lst = np.asarray(y_lst) # Guess good values computer mod.guess(y_lst,x = x_lst) result = mod.fit(y_lst, x = x_lst) return result
def guess_params(self, peak): """Guesses parameters for a new peak and adds it. See add_peak().""" if peak.region is not self._region: logger.error("peak with ID {} does not belong to region ID {}" "".format(peak.ID, self._region.ID)) raise ValueError("Peak does not belong to Region") if peak.model_name == "PseudoVoigt": model = PseudoVoigtModel(prefix=peak.prefix) # model.set_param_hint("fraction", vary=False) else: raise NotImplementedError("Only PseudoVoigt models supported") other_models_cps = [0] * len(self._region.energy) for other_peak in self._region.peaks: if other_peak == peak: continue other_models_cps += self.get_peak_cps(other_peak, peak.energy) y = self._region.cps - self._region.background - other_models_cps params = model.guess(y, x=peak.energy) self._params += params fwhmname = "{}fwhm".format(peak.prefix) sigmaname = "{}sigma".format(peak.prefix) ampname = "{}amplitude".format(peak.prefix) centername = "{}center".format(peak.prefix) params[fwhmname].set(value=params[fwhmname].value, vary=True, min=0) params[sigmaname].set(expr="{}/2".format(fwhmname)) params[ampname].set(min=0) params[centername].set(min=0) self._single_models[peak.prefix] = model
def calc_center_pseudoVoigt(vx,vy): mod = PseudoVoigtModel() y = vy pars = mod.guess(y, x=vx) out = mod.fit(y, pars, x=vx) center = out.best_values['center'] return center
def voigt(x, y): # Voigt fit to a curve x_shifted = x - x.min() # Shifting to 0 y_shifted = y - y.min() # Shifting to 0 mod = PseudoVoigtModel() # Setting model type pars = mod.guess(y_shifted, x=x_shifted) # Estimating fit out = mod.fit(y_shifted, pars, x=x_shifted) # Fitting fit # print(out.fit_report(min_correl=0.25)) # Outputting best fit results print("Voigt FWHM = ", out.params['fwhm'].value) # Outputting only FWHM out.plot() # Plotting fit
def center_psi(file_name): #print(file_name) psi, vx, vy = read_file(file_name) vy = processing_of_data(psi,vx,vy) legenda = file_name.split('/')[-1] #plt.grid() #plt.legend(loc=0) #import pdb; pdb.set_trace() plt.plot(vx,vy,label=legenda) mod = PseudoVoigtModel() y=vy pars = mod.guess(y, x=vx) out = mod.fit(y, pars, x=vx) center =out.best_values['center'] print('center: {} <--> psi: {}'.format(center,psi)) return psi, center
def test_figure_title_using_title_keyword_argument(peakdata): """Test setting figure title using title keyword argument.""" x, y = peakdata pvmodel = PseudoVoigtModel() params = pvmodel.guess(y, x=x) result = pvmodel.fit(y, params, x=x) ax = result.plot_fit(title='test') assert ax.axes.get_title() == 'test' ax = result.plot_residuals(title='test') assert ax.axes.get_title() == 'test' fig, _ = result.plot(title='test') assert fig.axes[0].get_title() == 'test' assert fig.axes[1].get_title() == '' # no title for fit subplot
def test_figure_default_title(peakdata): """Test default figure title.""" x, y = peakdata pvmodel = PseudoVoigtModel() params = pvmodel.guess(y, x=x) result = pvmodel.fit(y, params, x=x) ax = result.plot_fit() assert ax.axes.get_title() == 'Model(pvoigt)' ax = result.plot_residuals() assert ax.axes.get_title() == 'Model(pvoigt)' fig, _ = result.plot() assert fig.axes[0].get_title() == 'Model(pvoigt)' # default model.name assert fig.axes[1].get_title() == '' # no title for fit subplot
def test_priority_setting_figure_title(peakdata): """Test for setting figure title: title keyword argument has priority.""" x, y = peakdata pvmodel = PseudoVoigtModel() params = pvmodel.guess(y, x=x) result = pvmodel.fit(y, params, x=x) ax = result.plot_fit(ax_kws={'title': 'ax_kws'}, title='test') assert ax.axes.get_title() == 'test' ax = result.plot_residuals(ax_kws={'title': 'ax_kws'}, title='test') assert ax.axes.get_title() == 'test' fig, _ = result.plot(ax_res_kws={'title': 'ax_res_kws'}, title='test') assert fig.axes[0].get_title() == 'test' assert fig.axes[1].get_title() == '' fig, _ = result.plot(ax_fit_kws={'title': 'ax_fit_kws'}, title='test') assert fig.axes[0].get_title() == 'test' assert fig.axes[1].get_title() == ''
def test_figure_title_using_title_to_ax_kws(peakdata): """Test setting figure title by supplying ax_{fit,res}_kws.""" x, y = peakdata pvmodel = PseudoVoigtModel() params = pvmodel.guess(y, x=x) result = pvmodel.fit(y, params, x=x) ax = result.plot_fit(ax_kws={'title': 'ax_kws'}) assert ax.axes.get_title() == 'ax_kws' ax = result.plot_residuals(ax_kws={'title': 'ax_kws'}) assert ax.axes.get_title() == 'ax_kws' fig, _ = result.plot(ax_res_kws={'title': 'ax_res_kws'}) assert fig.axes[0].get_title() == 'ax_res_kws' assert fig.axes[1].get_title() == '' fig, _ = result.plot(ax_fit_kws={'title': 'ax_fit_kws'}) assert fig.axes[0].get_title() == 'Model(pvoigt)' # default model.name assert fig.axes[1].get_title() == '' # no title for fit subplot
def fit_peak(peak_data, initParams=None): """ Pseudo-Voigt fit to the lattice plane peak intensity. Return results of the fit as an lmfit class, which contains the fitted parameters (amplitude, fwhm, etc.) and the fit line calculated using the fit parameters and 100x two-theta points. """ ttheta = peak_data[:, 0] intensity = peak_data[:, 1] pvModel = PseudoVoigtModel() model = pvModel + Model(line) if initParams is None: pars = pvModel.guess(intensity, x=ttheta) pars['sigma'].set(min=0.01, max=1) #sigma is the width? pars['amplitude'].set(min=0.05) pars.add("constBG", 0) else: pars = initParams fit_results = model.fit(intensity, pars, x=ttheta) fit_ttheta = np.linspace(ttheta[0], ttheta[-1], 100) fit_line = [fit_ttheta, model.eval(fit_results.params, x=fit_ttheta)] return fit_results, fit_line
def fit_voigt(xp: XPS_experiment, region: str, prefix: str = 'v_', pars: list = None, bounds: list = None, ax=None, flag_plot: bool = True): """General method for fitting voigt model Input ---------- xp : class XPS_experiment XPS data region : str core level name pars, bounds : list initial guess of the fit parameters and bounds. If unspecified, guessed automatically Returns ----------- fitv : lmfit.model fit result to Voigt model """ from lmfit.models import PseudoVoigtModel, GaussianModel x = xp.dfx[region].dropna().energy y = xp.dfx[region].dropna().counts mod = PseudoVoigtModel(prefix=prefix) if pars == None: pars = mod.guess(y, x=x) pars[prefix + 'sigma'].set(value=1) # Usually guessed wrong anyway pars[prefix + 'fraction'].set(value=0.2, min=0.15, max=0.20) fitv = mod.fit(y, pars, x=x) xp.fit.update({region: fitv}) if flag_plot: hatchplot_fit(xp, region, fitv, ax=ax, plot_comps=True) return fitv
def fittingPseudoVoigt(x, y): #fits a pseudovoigt curve mod = PseudoVoigtModel() pars = mod.guess(y, x=x) out = mod.fit(y, pars, x=x) print(out.fit_report(min_correl=0.25)) return out.best_fit
'grey': '#7F7F7F', 'lightgrey': '#BFBFBF' } # get point-spread function data psf = pu.load_muv_point_spread_function() # set model x and y variables detector_pixels = np.arange(len(psf)) detector_pixel_edges = np.linspace(0, len(psf) - 1, len(psf) + 1) # initialize model model = PseudoVoigtModel() # use model's built-in initial parameters guessing option initial_parameters = model.guess(psf, x=detector_pixels) # fit the model to the point-spread function data result = model.fit(psf, initial_parameters, x=detector_pixels) params = result.params parnames = sorted(params) # make a figure and axes fig, axes = plt.subplots(2, 1, figsize=(5, 4), sharex=True, gridspec_kw={'height_ratios': [4, 1]}, constrained_layout=True) # plot the IUVS data
def fit_double_shouldered_voigt(xp: XPS_experiment, region: str, par_g1: list, bound_g1: list, par_g2: list, bound_g2: list, lb: str = None, ax=None, flag_plot: bool = True) -> tuple: x = xp.dfx[region].dropna().energy y = xp.dfx[region].dropna().counts ### Separate two peaks ### sepPt = find_separation_point(x, y) x1 = x[x < sepPt].values x2 = x[x > sepPt].values y1 = y[x < sepPt].values y2 = y[x > sepPt].values ### Set and guess main (voigt) components #### vo1 = PseudoVoigtModel(prefix='v1_') pars1 = vo1.guess(y1, x=x1) vo2 = PseudoVoigtModel(prefix='v2_') pars2 = vo2.guess(y2, x=x2) pars1['v1_sigma'].set(value=1) # Usually guessed wrong anyway pars1['v1_fraction'].set(value=0.15, min=0.15, max=0.2) pars2['v2_sigma'].set(value=1) # Usually guessed wrong anyway pars2['v2_fraction'].set(value=0.15, min=0.15, max=0.2) ### Set gaussian shoulders ### gauss1 = GaussianModel(prefix='g1_') pars1.update(gauss1.make_params()) gauss2 = GaussianModel(prefix='g2_') pars2.update(gauss2.make_params()) mod1 = vo1 + gauss1 mod2 = vo2 + gauss2 for k, p, b in zip(gauss1.param_names, par_g1, bounds_g1): pars1[k].set(value=p, min=b[0], max=b[1]) for k, p, b in zip(gauss2.param_names, par_g2, bounds_g2): pars2[k].set(value=p, min=b[0], max=b[1]) fitvg1 = mod1.fit(y1, pars1, x=x1) fitvg2 = mod2.fit(y2, pars2, x=x2) if ax == None: ax = plt.gca() col = plot_region(xp, region, lb, ax).get_color() comps1 = fitvg1.eval_components(x=x1) ax.plot(x1, fitvg1.best_fit, '-r', label='best fit, $\chi^2_N$ = %i' % fitvg1.redchi) for compo in comps1: colc = ax.plot( x1, comps1[compo], ls='dashdot', label='%scenter: %.2f' % (compo, fitvg1.best_values[compo + 'center']))[0].get_color() ax.fill_between(x1, y1=0, y2=comps1[compo], alpha=0.3, color=colc) comps2 = fitvg2.eval_components(x=x2) ax.plot(x2, fitvg2.best_fit, '-', label='best fit, $\chi^2_N$ = %i' % fitvg2.redchi) for compo in comps2: colc = ax.plot( x2, comps2[compo], ls='dashdot', label='%scenter: %.2f' % (compo, fitvg2.best_values[compo + 'center']))[0].get_color() ax.fill_between(x2, y1=0, y2=comps2[compo], alpha=0.3, color=colc) ax.legend() return fitvg1, fitvg2
def fit_double_voigt(xp: XPS_experiment, region: str, pars: list = None, bounds: list = None, sepPt: float = None, frac: float = None, lb: str = None, ax=None, flag_plot: bool = True, plot_comps: bool = False, DEBUG: bool = False): """Fitting double voigt model Input ---------- xp : class XPS_experiment XPS data region : str core level name pars, bounds : list initial guess of the fit parameters and bounds. If unspecified, guessed automatically sepPt : float separation point in energy between the two peaks. If unspecified guessed automatically flag_plot, DEBUG : bool flags to plot intermediate and final fit results Returns ----------- fitv : lmfit.model fit result to Voigt model """ from lmfit.models import PseudoVoigtModel x = xp.dfx[region].dropna().energy y = xp.dfx[region].dropna().counts if sepPt == None: sepPt = find_separation_point(x, y) x1 = x[x < sepPt].values x2 = x[x > sepPt].values y1 = y[x < sepPt].values y2 = y[x > sepPt].values mod1 = PseudoVoigtModel(prefix='v1_') mod2 = PseudoVoigtModel(prefix='v2_') if pars == None: pars1 = mod1.guess(y1, x=x1) pars1['v1_sigma'].set(value=1) # Usually guessed wrong anyway pars2 = mod2.guess(y2, x=x2) pars2['v2_sigma'].set(value=1) # Usually guessed wrong anyway if frac != None: pars1['v1_fraction'].set(value=frac, vary=False) pars2['v2_fraction'].set(value=frac, vary=False) mod = mod1 + mod2 pars = mod.make_params() pars.update(pars1) pars.update(pars2) if DEBUG: # Fit & plot individual components separately fit1 = mod1.fit(y1, x=x1, params=pars1) fit2 = mod2.fit(y2, x=x2, params=pars2) plot_fit_result(xp, region, fit1) plot_fit_result(xp, region, fit2) fitv = mod.fit(y, pars, x=x) xp.fit.update({region: fitv}) if flag_plot: hatchplot_fit(xp, region, fitv, ax=ax, plot_comps=True) return fitv