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 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 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 model_gen(V_series, dQdV_series, cd, i, cyc, battery): """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. 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) # creates a polynomial fitting object mod = models.PolynomialModel(4) # sets polynomial parameters based on a # guess of a polynomial fit to the data with no peaks par = mod.guess(sigy_bot, x=sigx_bot) # prints a notice if no peaks are found if all(i) is False: notice = 'Cycle ' + str(cyc) + cd + \ ' in battery ' + battery + ' has no peaks.' print(notice) # iterates over all peak indices else: for index in i: # 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) par.update(gaus_loop.make_params()) # 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[index], vary=False) par[sigma].set(0.01) par[amplitude].set(.05, min=0) par[fraction].set(.5, min=0, max=1) mod = mod + gaus_loop return par, mod
def pseudovoigt(self, oversample_multiplier=1, delta_rp=0, mz_overlay=1, fraction=0.5): ''' Legacy pseudovoigt lineshape function ''' 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 # 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) ) model = models.PseudoVoigtModel() # TODO derive amplitude gamma = sigma amplitude = (sqrt(2 * pi) * sigma) * self.abundance amplitude = (sqrt(pi / log(2)) * (pi * sigma * self.abundance)) / ( (pi * (1 - gamma)) + (sqrt(pi * log(2)) * gamma)) params = model.make_params(center=self.mz_exp, 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 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 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 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