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 add_peak(self, peak): """Adds a new Peak to the Model list.""" 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, value=0.2) params = model.make_params() else: raise NotImplementedError("Only PseudoVoigt models supported") 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 fit_two_Psudo_Voigt(x_lst,y_lst,x_min_flt,x_max_flt,print_all_fits_bool,place_to_save_str): ''' x_lst = x axis y_lst = spectra to fit first = beginning of fitting regions last = end of fitting region print_all_fits = Bool, do you want to save all plots place_to_save = string that is the filename where we're saving the data This takes the spectra and fits two Lorentzian curves to it. Returns dictionary of fit values Parameters have prefixes "one" for first V, "two" for second V, "c" for constant ''' import numpy as np # for smoothing the curves import scipy.interpolate as interp #import splev from lmfit.models import PseudoVoigtModel, ConstantModel # Restrict the fit x_fit = [] y_fit = [] for x,y in zip(x_lst, y_lst): if x_min_flt < x < x_max_flt: x_fit.append(float(x)) y_fit.append(float(y)) x_fit = np.asarray(x_fit) y_fit = np.asarray(y_fit) # now we find the parameters using the - d^2/dx^2 ysmooth = interp.interp1d(x_fit, y_fit, kind='cubic') # differentiate x 2 yp = np.gradient(ysmooth(x_fit)) ypp = np.gradient(yp) # we want the peaks of -d2/dx2 ypp = np.asarray([-x for x in ypp]) ''' ******************************************************* Section of bad code that it'd take too long to do right ******************************************************* ''' # % of wavelength you want the peak centers to move wiggle_room = .05 w_guess = 3 # sigma pref1 = 'one' pref2 = 'two' prefo = 'off' # if the fancy shit doesn't work, this is how far in index # we shift the 2nd peak and max over doesnt_work_shift = 10 ''' ******************************************************* Section of bad code that it'd take too long to do right ******************************************************* ''' # this is the money # defines the model that'll be fit peak1 = PseudoVoigtModel(prefix = pref1, independent_vars=['x'],nan_policy='raise') peak2 = PseudoVoigtModel(prefix = pref2, independent_vars=['x'],nan_policy='raise') offset = ConstantModel(prefix=prefo, independent_vars=['x'],nan_policy='raise') mod = peak1 + peak2 + offset # guess parameters x_max = x_fit[np.argmax(ypp)] y_max = y_fit[np.argmax(ypp)] # peak #1 # here we set up the peak fitting guess. Then the peak fitter will make a parameter object out of them mod.set_param_hint(pref1+'amplitude', value = 5*y_max, min=y_max*.8,max = y_max*6,vary=True) mod.set_param_hint(pref1+'center', value = x_max, min = x_max*(1-wiggle_room), max = x_max*(1+wiggle_room),vary=True) mod.set_param_hint(pref1+'sigma', value = w_guess, min = 0, max = 5*w_guess,vary=True) # Set Fraction mod.set_param_hint(pref1+'fraction', value = .5, min = 0, max = 1,vary=True) # Change gama maybe # mod.set_param_hint(pref1+'gamma', value = 1, vary=True) # peak #2 x_trunk = [] y_trunk = [] ypp_trunk = [] try: for a,b,c in zip(x_fit.tolist(),y_fit.tolist(),ypp.tolist()): ''' BAD CODE MAKE THIS BETTER ''' if x_max + 8 < a < x_max + 12: x_trunk.append(a) y_trunk.append(b) ypp_trunk.append(c) x_trunk = np.asarray(x_trunk) y_trunk = np.asarray(y_trunk) ypp_trunk = np.asarray(ypp_trunk) x_max_2 = x_trunk[np.argmax(ypp_trunk)] y_max_2 = y_trunk[np.argmax(ypp_trunk)] except ValueError: x_max_2 = x_trunk[np.argmax(ypp) + doesnt_work_shift] y_max_2 = y_trunk[np.argmax(ypp) + doesnt_work_shift] # add peak 2 paramaters mod.set_param_hint(pref2+'amplitude', value = 4*y_max_2, min=y_max_2*.8,max = y_max_2*6,vary=True) # changed the bounds to be near other peak mod.set_param_hint(pref2+'center', value = x_max_2, min = x_max+8, max = x_max+14,vary=True) mod.set_param_hint(pref2+'sigma', value = w_guess/2, min = 0, max = w_guess ,vary=True) #mod.set_param_hint(pref2+'sigma', pref1 + 'sigma' < expr < pref1 + 'sigma') # Set Fraction mod.set_param_hint(pref2+'fraction', value = .5, min = 0, max = 1,vary=True) # Change gama maybe # mod.set_param_hint(pref2+'gamma', value = 1, vary=False) # constant offest mod.set_param_hint(prefo+'c', value = y_fit[-1], min = 0, max = 5*y_fit[-1],vary=False) # this does the fitting # the params = mod.ma... is what initializes the parameters result = mod.fit(y_fit, x=x_fit, params = mod.make_params()) # If print all fits ... if print_all_fits_bool: x_dense = np.arange(x_min_flt,x_max_flt,(x_max_flt-x_min_flt)/300.0).tolist() result.plot_fit(xlabel='Inv Cm', ylabel='counts',datafmt = 'xb', numpoints=len(x_fit)*10) ''' Here we make paramaters for peak 1 and 2 ''' for x in result.best_values: if pref1 in x: peak1.set_param_hint(x, value = result.best_values[str(x)]) elif pref2 in x: peak2.set_param_hint(x, value = result.best_values[str(x)]) else: peak1.set_param_hint(x, value = result.best_values[str(x)]) peak2.set_param_hint(x, value = result.best_values[str(x)]) comp = [peak1.eval(x=yy, params=peak1.make_params()) for yy in x_dense] plt.plot(x_dense,comp, 'green', label = None) comp = [peak2.eval(x=yy, params=peak2.make_params()) for yy in x_dense] plt.plot(x_dense, comp, 'green', label= None) plt.title("Fit vs Data") plt.ylim(0, 1.1*np.max(y_fit)) plt.legend() plt.savefig(place_to_save_str) plt.clf() return result.best_values