def test_model_nan_policy(self): x = np.linspace(0, 10, 201) np.random.seed(0) y = gaussian(x, 10.0, 6.15, 0.8) y += gaussian(x, 8.0, 6.35, 1.1) y += gaussian(x, 0.25, 6.00, 7.5) y += np.random.normal(size=len(x), scale=0.5) y[55] = y[91] = np.nan mod = PseudoVoigtModel() params = mod.make_params(amplitude=20, center=5.5, sigma=1, fraction=0.25) params['fraction'].vary = False # with raise, should get a ValueError result = lambda: mod.fit(y, params, x=x, nan_policy='raise') self.assertRaises(ValueError, result) # with propagate, should get no error, but bad results result = mod.fit(y, params, x=x, nan_policy='propagate') self.assertTrue(result.success) self.assertTrue(np.isnan(result.chisqr)) self.assertTrue(np.isnan(result.aic)) self.assertFalse(result.errorbars) self.assertTrue(result.params['amplitude'].stderr is None) self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 0.001) # with omit, should get good results result = mod.fit(y, params, x=x, nan_policy='omit') self.assertTrue(result.success) self.assertTrue(result.chisqr > 2.0) self.assertTrue(result.aic < -100) self.assertTrue(result.errorbars) self.assertTrue(result.params['amplitude'].stderr > 0.1) self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 5.0) self.assertTrue(abs(result.params['center'].value - 6.0) < 0.5)
def residual(pars, x, data=None): g1 = gaussian(x, pars['a1'], pars['c1'], pars['w1']) g2 = gaussian(x, pars['a2'], pars['c2'], pars['w2']) model = g1 + g2 if data is None: return model return (model - data)
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_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_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_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(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) 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)
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 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 test_model_nan_policy(self): """Tests for nan_policy with NaN values in the input data.""" x = np.linspace(0, 10, 201) np.random.seed(0) y = gaussian(x, 10.0, 6.15, 0.8) y += gaussian(x, 8.0, 6.35, 1.1) y += gaussian(x, 0.25, 6.00, 7.5) y += np.random.normal(size=len(x), scale=0.5) # with NaN values in the input data y[55] = y[91] = np.nan mod = PseudoVoigtModel() params = mod.make_params(amplitude=20, center=5.5, sigma=1, fraction=0.25) params['fraction'].vary = False # with raise, should get a ValueError result = lambda: mod.fit(y, params, x=x, nan_policy='raise') msg = ( 'NaN values detected in your input data or the output of your ' 'objective/model function - fitting algorithms cannot handle this!' ) self.assertRaisesRegex(ValueError, msg, result) # with propagate, should get no error, but bad results result = mod.fit(y, params, x=x, nan_policy='propagate') self.assertTrue(result.success) self.assertTrue(np.isnan(result.chisqr)) self.assertTrue(np.isnan(result.aic)) self.assertFalse(result.errorbars) self.assertTrue(result.params['amplitude'].stderr is None) self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 0.001) # with omit, should get good results result = mod.fit(y, params, x=x, nan_policy='omit') self.assertTrue(result.success) self.assertTrue(result.chisqr > 2.0) self.assertTrue(result.aic < -100) self.assertTrue(result.errorbars) self.assertTrue(result.params['amplitude'].stderr > 0.1) self.assertTrue(abs(result.params['amplitude'].value - 20.0) < 5.0) self.assertTrue(abs(result.params['center'].value - 6.0) < 0.5) # with 'wrong_argument', should get a ValueError err_msg = r"nan_policy must be 'propagate', 'omit', or 'raise'." with pytest.raises(ValueError, match=err_msg): mod.fit(y, params, x=x, nan_policy='wrong_argument')
def gauss_dataset(params, i, x): """calc gaussian from params for data set i using simple, hardwired naming convention""" amp = params["amp_%i" % (i + 1)].value cen = params["cen_%i" % (i + 1)].value sig = params["sig_%i" % (i + 1)].value return gaussian(x, amp, cen, sig)
def test_unprefixed_name_collisions(self): # tests Github Issue 710 np.random.seed(0) x = np.linspace(0, 20, 201) y = 6 + x * 0.55 + gaussian(x, 4.5, 8.5, 2.1) + np.random.normal(size=len(x), scale=0.03) def myline(x, a, b): return a + b * x def mygauss(x, a, b, c): return gaussian(x, a, b, c) mod = Model(myline, prefix='line_') + Model(mygauss, prefix='peak_') pars = mod.make_params(line_a=5, line_b=1, peak_a=10, peak_b=10, peak_c=5) pars.add('a', expr='line_a + peak_a') result = mod.fit(y, pars, x=x) self.assertTrue(result.params['peak_a'].value > 4) self.assertTrue(result.params['peak_a'].value < 5) self.assertTrue(result.params['peak_b'].value > 8) self.assertTrue(result.params['peak_b'].value < 9) self.assertTrue(result.params['peak_c'].value > 1.5) self.assertTrue(result.params['peak_c'].value < 2.5) self.assertTrue(result.params['line_a'].value > 5.5) self.assertTrue(result.params['line_a'].value < 6.5) self.assertTrue(result.params['line_b'].value > 0.25) self.assertTrue(result.params['line_b'].value < 0.75) self.assertTrue(result.params['a'].value > 10) self.assertTrue(result.params['a'].value < 11)
def test_custom_independentvar(): """Tests using a non-trivial object as an independent variable.""" npts = 501 xmin = 1 xmax = 21 cen = 8 obj = Stepper(xmin, xmax, npts) y = gaussian(obj.get_x(), amplitude=3.0, center=cen, sigma=2.5) y += np.random.normal(scale=0.2, size=npts) gmod = Model(gaussian_mod) params = gmod.make_params(amplitude=2, center=5, sigma=8) out = gmod.fit(y, params, obj=obj) assert (out.nvarys == 3) assert (out.nfev > 10) assert (out.chisqr > 1) assert (out.chisqr < 100) assert (out.params['sigma'].value < 3) assert (out.params['sigma'].value > 2) assert (out.params['center'].value > xmin) assert (out.params['center'].value < xmax) assert (out.params['amplitude'].value > 1) assert (out.params['amplitude'].value < 5)
def gauss_dataset(params, i, x): """calc gaussian from params for data set i using simple, hardwired naming convention""" amp = params['amp_%i' % (i+1)] cen = params['cen_%i' % (i+1)] sig = params['sig_%i' % (i+1)] return gaussian(x, amp, cen, sig)
def gauss_dataset(params, i, x): """calc gaussian from params for data set i using simple, hardwired naming convention""" amp = params[f'amp_{i+1}'] cen = params[f'cen_{i+1}'] sig = params[f'sig_{i+1}'] return gaussian(x, amp, cen, sig)
def fitb(self, frame, s, **kws): """ fit band """ doblin = kws.get("doblin", True) x, y = banddata(self, frame, s, doblin=doblin) ymax = y.max() # Detect if there is no line peak and the intensity is close # to the noise level, for W/(m2 nm) detect = kws.get("detect", False) if detect: if y.max() < y.std() + y.mean() + 0.11 and y.max() < 0.3: return {"fit": None, "exp": [x, y], "out": None} out = self.model.fit(y / ymax, self.pars, x=x) v = out.best_values xx = np.linspace(x[0], x[-1], len(x) * 10) ys = np.array([ gaussian( xx, v["g{}_amplitude".format(i)] * ymax, v["g{}_center".format(i)], v["g{}_sigma".format(i)], ) for i in range(len(self.cw)) ]) return {"fit": [xx, ys], "exp": [x, y], "out": out}
def test_param_set(): np.random.seed(2015) x = np.arange(0, 20, 0.05) y = gaussian(x, amplitude=15.43, center=4.5, sigma=2.13) y = y + 0.05 - 0.01*x + np.random.normal(scale=0.03, size=len(x)) model = VoigtModel() params = model.guess(y, x=x) # test #1: gamma is constrained to equal sigma sigval = params['gamma'].value assert(params['gamma'].expr == 'sigma') assert_allclose(params['gamma'].value, sigval, 1e-4, 1e-4, '', True) # test #2: explicitly setting a param value should work, even when # it had been an expression. The value will be left as fixed gamval = 0.87543 params['gamma'].set(value=gamval) assert(params['gamma'].expr is None) assert(not params['gamma'].vary) assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True) # test #3: explicitly setting an expression should work params['gamma'].set(expr='sigma/2.0') assert(params['gamma'].expr is not None) assert(not params['gamma'].vary) assert_allclose(params['gamma'].value, sigval/2.0, 1e-4, 1e-4, '', True) # test #4: explicitly setting a param value WITH vary=True # will set it to be variable gamval = 0.7777 params['gamma'].set(value=gamval, vary=True) assert(params['gamma'].expr is None) assert(params['gamma'].vary) assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)
def test_default_inputs_gauss(): area = 1 cen = 0 std = 0.2 x = np.arange(-3, 3, 0.01) y = gaussian(x, area, cen, std) g = GaussianModel() fit_option1 = {'maxfev': 5000, 'xtol': 1e-2} result1 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option1) fit_option2 = {'maxfev': 5000, 'xtol': 1e-6} result2 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option2) assert result1.values != result2.values
def test_saveload_usersyms(): """Test save/load of modelresult with non-trivial user symbols, this example uses a VoigtModel, wheree `wofz()` is used in a constraint expression""" x = np.linspace(0, 20, 501) y = gaussian(x, 1.1, 8.5, 2) + lorentzian(x, 1.7, 8.5, 1.5) np.random.seed(20) y = y + np.random.normal(size=len(x), scale=0.025) model = VoigtModel() pars = model.guess(y, x=x) result = model.fit(y, pars, x=x) savefile = 'tmpvoigt_modelresult.sav' save_modelresult(result, savefile) assert_param_between(result.params['sigma'], 0.7, 2.1) assert_param_between(result.params['center'], 8.4, 8.6) assert_param_between(result.params['height'], 0.2, 1.0) time.sleep(0.25) result2 = load_modelresult(savefile) assert_param_between(result2.params['sigma'], 0.7, 2.1) assert_param_between(result2.params['center'], 8.4, 8.6) assert_param_between(result2.params['height'], 0.2, 1.0)
def pvoigt(x, area, center, sigma, fraction): """1 dimensional pseudo-voigt: pvoigt(x, area, center, sigma, fraction) = amplitude*(1-fraction)*gaussion(x, center,sigma) + amplitude*fraction*lorentzian(x, center, sigma) 1 dimensional pseudo-voigt, linear combination of gaussian and lorentzian curve. Parameters ---------- x : array independent variable area : float area of pvoigt peak center : float center position sigma : float standard deviation fraction : float weight for lorentzian peak in the linear combination, and (1-fraction) is the weight for gaussian peak. """ return ((1-fraction) * gaussian(x, area, center, sigma) + fraction * lorentzian(x, area, center, sigma))
def pvoigt(x, area, center, sigma, fraction): """1 dimensional pseudo-voigt: pvoigt(x, area, center, sigma, fraction) = amplitude*(1-fraction)*gaussion(x, center,sigma) + amplitude*fraction*lorentzian(x, center, sigma) 1 dimensional pseudo-voigt, linear combination of gaussian and lorentzian curve. Parameters ---------- x : array independent variable area : float area of pvoigt peak center : float center position sigma : float standard deviation fraction : float weight for lorentzian peak in the linear combination, and (1-fraction) is the weight for gaussian peak. """ return ((1 - fraction) * gaussian(x, area, center, sigma) + fraction * lorentzian(x, area, center, sigma))
def gauss_dataset(params, i, x): """calc gaussian from params for data set i using simple, hardwired naming convention""" amp = params['amp_%i' % (i + 1)].value cen = params['cen_%i' % (i + 1)].value sig = params['sig_%i' % (i + 1)].value return gaussian(x, amp, cen, sig)
def test_custom_independentvar(): """Tests using a non-trivial object as an independent variable.""" npts = 501 xmin = 1 xmax = 21 cen = 8 obj = Stepper(xmin, xmax, npts) y = gaussian(obj.get_x(), amplitude=3.0, center=cen, sigma=2.5) y += np.random.normal(scale=0.2, size=npts) gmod = Model(gaussian_mod) params = gmod.make_params(amplitude=2, center=5, sigma=8) out = gmod.fit(y, params, obj=obj) assert(out.nvarys == 3) assert(out.nfev > 10) assert(out.chisqr > 1) assert(out.chisqr < 100) assert(out.params['sigma'].value < 3) assert(out.params['sigma'].value > 2) assert(out.params['center'].value > xmin) assert(out.params['center'].value < xmax) assert(out.params['amplitude'].value > 1) assert(out.params['amplitude'].value < 5)
def test_constraints1(): def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x * 0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x, ), fcn_kws={ 'sigma': sigma, 'data': data }, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) result = myfit.leastsq() print(' Nfev = ', result.nfev) print(result.chisqr, result.redchi, result.nfree) report_fit(result.params) pfit = result.params fit = residual(result.params, x) assert (pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert (pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert (pfit['wid_l'].value == 2 * pfit['wid_g'].value)
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) model = yg + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return model - data return (model - data) / sigma
def test_constraints2(): """add a user-defined function to symbol table""" def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma': sigma, 'data': data}, scale_covar=True) def width_func(wpar): """ """ return 2*wpar myfit.params._asteval.symtable['wfun'] = width_func try: myfit.params.add(name='wid_l', expr='wfun(wid_g)') except: assert(False) result = myfit.leastsq() pfit = result.params assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value)
def test_constraints1(): def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params) pfit= result.params fit = residual(result.params, x) assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value)
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) model = yg + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return model - data return (model-data) / sigma
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 pseudoVoigt_resolution(x, mu, wG, wL): """pseudo-voigt used as resolution function - area normalized to 1""" sigG = wG / np.sqrt(8. * np.log(2.)) sigL = wL / 2. r = mu * lorentzian(x, 1., 0., sigL) + (1 - mu) * gaussian( x, 1.0, 0.0, sigG) fac = r.sum() * (x[-1] - x[0]) / (x.size - 1) r = r / fac return r
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 residual(pars, x, data): model = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) model += lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) return (model - data)
def residual(pars, x, sigma=None, data=None): """Define objective function.""" yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return model - data return (model-data) / sigma
def add_gauss(xxx, yyy, line, sigma): index_left = bisect.bisect_left(xxx, line.freq - 5 * sigma) index_right = bisect.bisect_left(xxx, line.freq + 5 * sigma) peak = lineshapes.gaussian( x=xxx[index_left:index_right], center=line.freq, sigma=sigma, amplitude=np.exp( line.log_I)) #amplitude=np.sqrt(2 * np.pi) * max(1.e-15, sigma)) yyy[index_left:index_right] = yyy[index_left:index_right] + peak
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) slope = pars['line_slope'] offset = pars['line_off'] model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma
def get_gaussianmodel(amplitude=1.0, center=5.0, sigma=1.0, noise=0.1): # create data to be fitted np.random.seed(7392) x = np.linspace(-20, 20, 201) y = gaussian(x, amplitude, center=center, sigma=sigma) y = y + np.random.normal(size=len(x), scale=noise) model = GaussianModel() params = model.make_params(amplitude=amplitude / 5.0, center=center - 1.0, sigma=sigma * 2.0) return x, y, model, params
def get_gaussianmodel(amplitude=1.0, center=5.0, sigma=1.0, noise=0.1): # create data to be fitted np.random.seed(7392) x = np.linspace(-20, 20, 201) y = gaussian(x, amplitude, center=center, sigma=sigma) y = y + np.random.normal(size=len(x), scale=noise) model = GaussianModel() params = model.make_params(amplitude=amplitude/5.0, center=center-1.0, sigma=sigma*2.0) return x, y, model, params
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) slope = pars['line_slope'] offset = pars['line_off'] model = yg + yl + offset + x*slope if data is None: return model if sigma is None: return model - data return (model - data) / sigma
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma
def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) yl = lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) frac = pars['frac'].value slope = pars['line_slope'].value offset = pars['line_off'].value model = (1-frac) * yg + frac * yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma
def elastic(x, coherent_sct_amplitude, coherent_sct_energy, fwhm_offset, fwhm_fanoprime, e_offset, e_linear, e_quadratic, epsilon=2.96): """ Use gaussian function to model elastic peak Parameters ---------- x : array energy value coherent_sct_amplitude : float area of elastic peak coherent_sct_energy : float incident energy fwhm_offset : float global fitting parameter for peak width fwhm_fanoprime : float global fitting parameter for peak width e_offset : float offset of energy calibration e_linear : float linear coefficient in energy calibration e_quadratic : float quadratic coefficient in energy calibration epsilon : float energy to create a hole-electron pair for Ge 2.96, for Si 3.61 at 300K needs to double check this value Returns ------- value : array elastic peak """ x = e_offset + x * e_linear + x**2 * e_quadratic temp_val = 2 * np.sqrt(2 * np.log(2)) sigma = np.sqrt((fwhm_offset / temp_val)**2 + coherent_sct_energy * epsilon * fwhm_fanoprime) return gaussian(x, coherent_sct_amplitude, coherent_sct_energy, sigma)
def fitresult(): """Return a ModelResult after fitting a randomized Gaussian data set.""" x = np.linspace(0, 12, 601) data = gaussian(x, amplitude=36.4, center=6.70, sigma=0.88) data = data + np.random.normal(x.size, scale=3.2) model = GaussianModel() params = model.make_params(amplitude=50, center=5, sigma=2) params['amplitude'].min = 1 params['amplitude'].max = 100.0 params['sigma'].min = 0 params['sigma'].brute_step = 0.001 result = model.fit(data, params, x=x) return result
def test_itercb(): x = np.linspace(0, 20, 401) y = gaussian(x, amplitude=24.56, center=7.6543, sigma=1.23) y = y - .20 * x + 3.333 + np.random.normal(scale=0.23, size=len(x)) mod = GaussianModel(prefix='peak_') + LinearModel(prefix='bkg_') pars = mod.make_params(peak_amplitude=21.0, peak_center=7.0, peak_sigma=2.0, bkg_intercept=2, bkg_slope=0.0) out = mod.fit(y, pars, x=x, iter_cb=per_iteration) assert (out.nfev == 23) assert (not out.errorbars) assert (not out.success)
def conv_gaussian_rotations(left, right, params, **kwargs): """Convolution of a Gaussian and a liquid rotations model.""" # set left to Gaussian component if not so if left.func.__name__ == "rotations": left, right = (right, left) lp, rp, x, q, out, lglob, rglob = _getVariables( left, right, params, **kwargs ) for qId, qVal in enumerate(q): amplitude = ( lp["amplitude"] if "amplitude" in lglob else lp["amplitude_%i" % qId] ) amplitude *= ( rp["amplitude"] if "amplitude" in rglob else rp["amplitude_%i" % qId] ) center = lp["center_%i" % qId] + rp["center_%i" % qId] lsigma = ( lp["sigma"] * qVal ** 2 if "sigma" in lglob else lp["sigma_%i" % qId] ) bondDist = rp["bondDist"] rsigma = rp["sigma"] if "sigma" in rglob else lp["sigma_%i" % qId] eisf = spherical_jn(0, bondDist * qVal) ** 2 eisf *= gaussian(x, amplitude, center, rsigma) qisf = np.sum( [ spherical_jn(i, bondDist * qVal) ** 2 * (2 * i + 1) * voigt(x, amplitude, center, lsigma, i * (i + 1) * rsigma) for i in range(1, 5) ], axis=0, ) out.append(eisf + qisf) return np.array(out)
def test_itercb(): x = np.linspace(0, 20, 401) y = gaussian(x, amplitude=24.56, center=7.6543, sigma=1.23) y = y - .20*x + 3.333 + np.random.normal(scale=0.23, size=len(x)) mod = GaussianModel(prefix='peak_') + LinearModel(prefix='bkg_') pars = mod.make_params(peak_amplitude=21.0, peak_center=7.0, peak_sigma=2.0, bkg_intercept=2, bkg_slope=0.0) out = mod.fit(y, pars, x=x, iter_cb=per_iteration) assert(out.nfev == 23) assert(out.aborted) assert(not out.errorbars) assert(not out.success)
def test_default_inputs_gauss(): area = 1 cen = 0 std = 0.2 x = np.arange(-3, 3, 0.01) y = gaussian(x, area, cen, std) g = GaussianModel() fit_option1 = {'maxfev': 5000, 'xtol': 1e-2} result1 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option1) fit_option2 = {'maxfev': 5000, 'xtol': 1e-6} result2 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option2) assert_true(result1.values!=result2.values) return
def minimizer(): """Return the Minimizer object.""" def residual(pars, x, sigma=None, data=None): """Define objective function.""" yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return model - data return (model-data) / sigma # generate synthetic data n = 601 xmin = 0. xmax = 20.0 x = np.linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + np.random.normal(scale=0.23, size=n) + x*0.5) # create initial Parameters pars = Parameters() pars.add(name='amp_g', value=10) pars.add(name='cen_g', value=9) pars.add(name='wid_g', value=1) pars.add(name='amp_tot', value=20) pars.add(name='amp_l', expr='amp_tot - amp_g') pars.add(name='cen_l', expr='1.5+cen_g') pars.add(name='wid_l', expr='2*wid_g') pars.add(name='line_slope', value=0.0) pars.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) mini = Minimizer(residual, pars, fcn_args=(x,), fcn_kws={'sigma': sigma, 'data': data}) return mini
def test_param_set(): np.random.seed(2015) x = np.arange(0, 20, 0.05) y = gaussian(x, amplitude=15.43, center=4.5, sigma=2.13) y = y + 0.05 - 0.01*x + np.random.normal(scale=0.03, size=len(x)) model = VoigtModel() params = model.guess(y, x=x) # test #1: gamma is constrained to equal sigma assert(params['gamma'].expr == 'sigma') params.update_constraints() sigval = params['gamma'].value assert_allclose(params['gamma'].value, sigval, 1e-4, 1e-4, '', True) # test #2: explicitly setting a param value should work, even when # it had been an expression. The value will be left as fixed gamval = 0.87543 params['gamma'].set(value=gamval) assert(params['gamma'].expr is None) assert(not params['gamma'].vary) assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True) # test #3: explicitly setting an expression should work # Note, the only way to ensure that **ALL** constraints are up to date # is to call params.update_constraints(). This is because the constraint # may have multiple dependencies. params['gamma'].set(expr='sigma/2.0') assert(params['gamma'].expr is not None) assert(not params['gamma'].vary) params.update_constraints() assert_allclose(params['gamma'].value, sigval/2.0, 1e-4, 1e-4, '', True) # test #4: explicitly setting a param value WITH vary=True # will set it to be variable gamval = 0.7777 params['gamma'].set(value=gamval, vary=True) assert(params['gamma'].expr is None) assert(params['gamma'].vary) assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True)
def test_multidatasets(): # create 5 datasets x = np.linspace( -1, 2, 151) data = [] for i in np.arange(5): amp = 2.60 + 1.50*np.random.rand() cen = -0.20 + 1.50*np.random.rand() sig = 0.25 + 0.03*np.random.rand() dat = gaussian(x, amp, cen, sig) + \ np.random.normal(size=len(x), scale=0.1) data.append(dat) # data has shape (5, 151) data = np.array(data) assert(data.shape) == (5, 151) # create 5 sets of parameters, one per data set pars = Parameters() for iy, y in enumerate(data): pars.add( 'amp_%i' % (iy+1), value=0.5, min=0.0, max=200) pars.add( 'cen_%i' % (iy+1), value=0.4, min=-2.0, max=2.0) pars.add( 'sig_%i' % (iy+1), value=0.3, min=0.01, max=3.0) # but now constrain all values of sigma to have the same value # by assigning sig_2, sig_3, .. sig_5 to be equal to sig_1 for iy in (2, 3, 4, 5): pars['sig_%i' % iy].expr='sig_1' # run the global fit to all the data sets out = minimize(objective, pars, args=(x, data)) assert(len(pars) == 15) assert(out.nvarys == 11) assert(out.nfev > 15) assert(out.chisqr > 1.0) assert(pars['amp_1'].value > 0.1) assert(pars['sig_1'].value > 0.1) assert(pars['sig_2'].value == pars['sig_1'].value)
def test_reports_created(): """do a simple Model fit but with all the bells-and-whistles and verify that the reports are created """ x = np.linspace(0, 12, 601) data = gaussian(x, amplitude=36.4, center=6.70, sigma=0.88) data = data + np.random.normal(size=len(x), scale=3.2) model = GaussianModel() params = model.make_params(amplitude=50, center=5, sigma=2) params['amplitude'].min = 0 params['sigma'].min = 0 params['sigma'].brute_step = 0.001 result = model.fit(data, params, x=x) report = result.fit_report() assert(len(report) > 500) html_params = result.params._repr_html_() assert(len(html_params) > 500) html_report = result._repr_html_() assert(len(html_report) > 1000)
return (model - data)/sigma n = 201 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) p_true = Parameters() p_true.add('amp_g', value=21.0) p_true.add('cen_g', value=8.1) p_true.add('wid_g', value=1.6) p_true.add('line_off', value=-1.023) p_true.add('line_slope', value=0.62) data = (gaussian(x, p_true['amp_g'].value, p_true['cen_g'].value, p_true['wid_g'].value) + random.normal(scale=0.23, size=n) + x*p_true['line_slope'].value + p_true['line_off'].value ) if HASPYLAB: pylab.plot(x, data, 'r+') p_fit = Parameters() p_fit.add('amp_g', value=10.0) p_fit.add('cen_g', value=9) p_fit.add('wid_g', value=1) p_fit.add('line_slope', value=0.0) p_fit.add('line_off', value=0.0) myfit = Minimizer(residual, p_fit, fcn_args=(x,),
model = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) model += lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) return (model - data) n = 601 random.seed(0) x = linspace(0, 20.0, n) data = (gaussian(x, 21, 6.1, 1.2) + lorentzian(x, 10, 9.6, 1.3) + random.normal(scale=0.1, size=n)) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='amp_l', value=10) pfit.add(name='cen_g', value=5) pfit.add(name='peak_split', value=2.5, min=0, max=5, vary=True) pfit.add(name='cen_l', expr='peak_split+cen_g') pfit.add(name='wid_g', value=1) pfit.add(name='wid_l', expr='wid_g') mini = Minimizer(residual, pfit, fcn_args=(x, data)) out = mini.leastsq()
def test_constraints2(): """add a user-defined function to symbol table""" def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'].value, pars['cen_g'].value, pars['wid_g'].value) yl = lorentzian(x, pars['amp_l'].value, pars['cen_l'].value, pars['wid_l'].value) slope = pars['line_slope'].value offset = pars['line_off'].value model = yg + yl + offset + x * slope if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) def width_func(wpar): """ """ return 2*wpar myfit.params._asteval.symtable['wfun'] = width_func try: myfit.params.add(name='wid_l', expr='wfun(wid_g)') except: assert(False) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params) pfit= result.params fit = residual(result.params, x) assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value)
def flexible_func(x, amplitude, center, sigma, **kwargs): return gaussian(x, amplitude, center, sigma)