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 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_user_defined_gaussian_plus_constant(self): data = self.data + 5.0 model = self.model + models.ConstantModel() guess = self.guess() pars = model.make_params(c=10.1, **guess) true_values = self.true_values() true_values['c'] = 5.0 result = model.fit(data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01)
def test_composite_with_expression(self): expression_model = models.ExpressionModel("exp(-x/x0)", name='exp') amp_model = models.ConstantModel(prefix='amp_') off_model = models.ConstantModel(prefix='off_', name="off") comp_model = off_model + amp_model * expression_model x = self.x true_values = self.true_values() data = comp_model.eval(x=x, **true_values) + self.noise # data = 0.25 + 1 * np.exp(-x / 2.) params = comp_model.make_params(**self.guess()) result = comp_model.fit(data, x=x, params=params) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01) data_components = comp_model.eval_components(x=x) self.assertIn('exp', data_components)
def diagnostic(self): ###--------------------------------------------------------------------- self.read_param() self.reduction() print 'Fit the input data' model = lfm.ConstantModel() param = model.make_params() for name in model.param_names: param.add(name, vary=True, value=self.parval, min=self.parmin, max=self.parmax) result = model.fit(x=self.xd, data=self.yd, weights=self.ye**(-1), params=param, method='leastsq') chisqr = result.chisqr dgfrdm = result.nfree #d.o.f. redchi = result.redchi prbrty = TMath.Prob(chisqr, dgfrdm) #p-value log = open(self.flogfl, 'w') log.write( "--------------------------------------------------------------------\n" ) log.write(result.fit_report()) #log.write("[[Confidence Intervals]]\n") #log.write(result.ci_report()) log.write("\n") log.write( "--------------------------------------------------------------------\n" ) log.write(" Chi-squared value / d.o.f. = %.5f / %d\n" % (chisqr, dgfrdm)) log.write(" Reduced Chi-squared value = %.5f\n" % (redchi)) log.write(" p-value = %7.5e\n" % (prbrty)) log.write("\n") log.close() print 'Fitting results were recorded to %s.' % (self.flogfl)
def fit_spectrum(x, y, num_resonances): """ Iteratively identifies canditate resonances, performs a least-squares regression, and removes the identified resonance from the data. This function is `dumb' in the sense that it abdicates responsibility for hypothesis testing. Having both find_resonance and find_resonances might be a bad naming convention. Args: x (numpy.ndarray): A one-dimensional real-valued numpy array, the frequency domain variable. y (numpy.ndarray): A one-dimensional real-valued numpy array, the signal variable. num_resonances (type): Description of parameter `num_resonances`. Returns: type: Description of returned object. """ # First pass, picking out resonances one-by-one. # Build model for whole spectrum along the way. resonance_fit_results = [] spectrum_model = models.ConstantModel() y_copy = y for i in range(num_resonances): resonance_fit_results.append(find_resonance(x, y_copy)) y_copy = remove_resonance_from_data(y_copy, resonance_fit_results[-1]) # Make a Lorentzian model for each resonance, with prefixes for proper name-mangling. lorentzian_model = models.LorentzianModel() lorentzian_model.prefix = '_' + str(i) + '_' spectrum_model += lorentzian_model # Sum up all the offsets from each resonance model net_offset = sum(resonance_fit_results[i].params['c'].value for i in range(num_resonances)) # Build a dict of all the Lorentzian parameters lorentzian_params = {} for i in range(num_resonances): lorentzian_params['_' + str(i) + '_amplitude'] = resonance_fit_results[i].params['amplitude'].value lorentzian_params['_' + str(i) + '_center'] = resonance_fit_results[i].params['center'].value lorentzian_params['_' + str(i) + '_sigma'] = resonance_fit_results[i].params['sigma'].value # And re-adjust the best fit. spectrum_fit_result = spectrum_model.fit(y, x=x, c=net_offset, **lorentzian_params) return spectrum_fit_result
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 __init__(self, independent_vars=['x'], prefix='', nan_policy='raise', name=None, num_resonances=1, **kwargs): kwargs.update({'prefix': prefix, 'nan_policy': nan_policy, 'independent_vars': independent_vars}) # This method might be a little bit kludgy. I'm guessing there's a more # pythonic way to achieve the same end. constant_model = models.ConstantModel(**kwargs) # Creates a sequence of LorentzianModel objects with prefixes `_i_`, for # i = 0, 1, ..., num_resonances - 1, and sums them. # TODO: is there a more elegant way to achieve this behavior? CompositeModel # doesn't accept null operands; but maybe there's a better way. resonance_model = Model(lambda x: 0) for i in range(num_resonances): lorentzian_model = models.LorentzianModel(**kwargs) lorentzian_model.prefix = '_' + str(i) + '_' resonance_model += lorentzian_model super(SpectrumModel, self).__init__(constant_model, resonance_model, operator.add, **kwargs)
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)
e_g_err = geometrisch_err(0.015, 0.15, 0.001, 0.001) strontium_totaal = 960 * 1400 strontium_totaal_err = 960 df_1['efficientie'] = df_1['strontium'] / strontium_totaal df_1['efficientie_err'] = np.sqrt( (df_1['strontium_err'] / strontium_totaal)**2 + (-(df_1['strontium'] * strontium_totaal_err) / strontium_totaal**2)**2) df_1['intrinsiek'] = df_1['efficientie'] / e_g df_1['intrinsiek_err'] = np.sqrt((df_1['efficientie_err'] / e_g)**2 + (-(df_1['efficientie'] * e_g_err) / e_g**2)**2) mod_linear = models.ConstantModel() fit = mod_linear.fit(df_1['strontium'], x=df_1['GM'], weights=1 / df_1['strontium_err']) # print(lmfit.report_fit(fit)) # print(fit.redchi) ## referentie: https://stackoverflow.com/questions/43381833/lmfit-extract-fit-statistics-parameters-after-fitting # print(fit.params['c'].value) intrinsiek = df_1['intrinsiek'].tolist() intrinsiek_err = df_1['intrinsiek_err'].tolist() intrinsiek_err_sqrd = []
# in this test version are nearly as naive as possible. Since this is a module that is # worth getting Right with a capital 'R', and since a lot of people have reinvented # this wheel before, it would behoove me to review prior art. In particular, it's likely # that there are standard algorithms and hypothesis tests that are well-known in # the NMR, HEP, and astronomy communities. Check out any CERN docs on spectrum-fitting; # they're probably the gold standard. In short, this is abeing written to be deprecated. # TODO: Review and fix redundancy between SpectrumModel class and spectrum model # building in fit_spectrum. DRY it out! # TODO: SpectrumModel constructor is ugly. # TODO: spectrum_fit is really quite slow. # TODO: this actually can be rewritten more intelligently. # Make the guessing functions the guess method of the SpectrumModel class. # Global definitions RESONANCE_MODEL = models.ConstantModel() + models.LorentzianModel() # Classes class SpectrumModel(CompositeModel): """ An lmfit Model representing a spectrum of finitely-many Lorentzian resonances with parameters ``c'', ``_i_amplitude``, ``_i_center``, ``_i_sigma`` for i = 0, 1, ..., num_resonances - 1 Args: num_resonances (int): The number of Lorentzian resonances. """
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))