def fit(self): r"""actually run the fit""" # we can ignore set_what, since I think there's a mechanism in # lmfit to take care of that (it's for fixing parameters) # but the rest of what it's doing is to pull apart the # error, axis, etc, to be fed to minimize. # # It also automatically converts complex data to real data, and # does other things for error handling -- let's not just throw this out # # I think that a lot of this could be copied with little modification # # But you should read through and see what the previous fit method is doing # and then copy over what you can x = self.getaxis(self.fit_axis) if np.iscomplex(self.data.flatten()[0]): logging.debug(strm("Warning, taking only real part of fitting data!")) y = np.real(self.data) sigma = self.get_error() out = minimize( self.residual, self.pars, args=(x, y, sigma), ) # can you capture the following as a string? maybe return it? report_fit(out, show_correl=True) # {{{ capture the result for ouput, etc self.fit_coeff = [out.params[j].value for j in self.symbol_list] assert out.success self.covariance = out.covar # }}} return
def normal_skewed(x, y, parameters=None, dfunc='pdf', check=False, *args, **kwargs): # verbous.INFO('FITTING SKEWED-GAUSSIAN') if parameters == None: parameters = Parameters() parameters = Parameters() parameters.add('amp', value=max(y)) max_idx = np.argmin(abs(y - max(y))) parameters.add('mu', value=x[max_idx]) parameters.add('sig', value=15.) parameters.add('skew', value=-5.) if y[0] > y[-1]: reverse = True else: reverse = False errfunc = lambda p, x, y: distributions.normal_skew(x, parameters, reverse=reverse, dfunc=dfunc) - y fitout = minimize(errfunc, parameters, args=(x, y)) # verbous.INFO('FITTED PARAMETERS:') if check: printfuncs.report_fit(fitout.params) x_fit = np.linspace(0, 600, 1000) y_fit = distributions.normal_skew(x_fit, parameters, reverse=reverse, dfunc=dfunc) plt.plot(x, y) plt.plot(x_fit, y_fit) plt.show() return parameters
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 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 fit_spready(self, ): params = Parameters() c1 = self.refx[np.argmax(self.refy)] - self.x[np.argmax(self.y)] params.add('c1', value=c1, min=c1 - 50, max=c1 + 50) params.add('c2', value=0.5e-2, min=1e-3, max=1e-2) mini = Minimizer(self.lmfit_residuals, params, nan_policy='propagate') self.lmfit_minimize_result = mini.minimize( method='differential_evolution') printfuncs.report_fit(self.lmfit_minimize_result, min_correl=0.5)
def align_with_O2(spectra, O2_spectra, R=5000): # Convert to ispec structures spectra = ispec.create_spectrum_structure(spectra.T[0], spectra.T[1], spectra.T[2]) O2_spectra = ispec.create_spectrum_structure(O2_spectra.T[0], O2_spectra.T[1], O2_spectra.T[2]) # Now normalise normed_spectra, spectra_continuum_model = normalize_whole_spectrum(spectra) #wfilter = ispec.create_wavelength_filter(normed_spectra, wave_base=np.min(O2_spectra['waveobs']) - 3, wave_top=np.max(O2_spectra['waveobs']) + 3) wfilter = ispec.create_wavelength_filter(normed_spectra, wave_base=684, wave_top=690) normed_spectra = normed_spectra[wfilter] params = Parameters() params.add('rv', value=0, min=-100, max=100) params.add('strength', value=1, min=0.7, max=1.3) params.add('zp', value=1., min=0.9, max=1.1, vary=False) mini = Minimizer(lmfit_func, params, fcn_args=(np.copy(normed_spectra), np.copy(O2_spectra), False)) lmfit_minimize_result = mini.minimize() printfuncs.report_fit(lmfit_minimize_result, min_correl=0.5) corrected_spectra, o2_model = lmfit_func(lmfit_minimize_result.params, normed_spectra, O2_spectra, return_model=True) f = plt.figure() plt.plot(normed_spectra['waveobs'], normed_spectra['flux'], 'k', alpha=0.3) plt.plot(corrected_spectra['waveobs'], corrected_spectra['flux'], 'k', label='Corrected solution') plt.plot(O2_spectra['waveobs'], O2_spectra['flux'], 'r', alpha=0.3) plt.plot(O2_spectra['waveobs'], o2_model, 'r', label='O2 model') plt.gca().set(title='RV = {:.3f} +- {:.3f}'.format( lmfit_minimize_result.params['rv'].value, lmfit_minimize_result.params['rv'].stderr), xlabel='Wavelength [nm]', ylabel='Normalized flux') plt.legend() plt.xlim(685, 690) corrected = ispec.correct_velocity( np.copy(spectra), lmfit_minimize_result.params['rv'].value) return f, np.array( [corrected['waveobs'], corrected['flux'], corrected['err']]).T, lmfit_minimize_result.params[ 'rv'].value, lmfit_minimize_result.params['rv'].stderr
def do_fit(self, verbosity=False): PeakFitter.ith_fit += 1 myfit = Minimizer(self.residual, self.params, fcn_args=(self.data_x, ), fcn_kws={'data_y': self.data_y}, scale_covar=True) self.result = myfit.leastsq() self.init = self.residual(self.params, self.data_x) self.fit = self.residual(self.result.params, self.data_x) if verbosity: # print fit details out report_fit(self.result)
def main(): tmpname = 'data/templates/F0_+0.5_Dwarf.fits' model = Model(tmpname) # ftargetname = 'data/spec-4961-55719-0378.fits' ftargetname = '/home/zzx/workspace/data/xiamen/P200-Hale_spec/blue/reduce_second/specdir/fawftbblue0073.fits' # new_wo, new_fo, new_eo = specio.read_sdss(ftargetname, lw=3660, rw=10170) new_wo, new_fo, new_eo = specio.read_iraf(ftargetname) unit = func.get_unit(new_fo) new_fo = new_fo / unit new_eo = new_eo / unit # new_wo, new_fo, new_eo = specio.read_iraf(targetname) result = fit(model, new_wo, new_fo, new_eo, show=True, isprint=True) residual = model.residual out_parms = result.params # spec_fit = model.get_spectrum(out_parms, new_wo) scalepar = model.get_scale_par(out_parms) parshift = model.get_shift_par(out_parms) print(parshift[1]) velocity = str(parshift[1] * c.to('km/s')) print('shift = ' + velocity) myscale = model.get_scale(new_wo, scalepar) plt.figure() plt.plot(new_wo, myscale) plt.show() emcee_params = result.params.copy() # emcee_params.add('__lnsigma', value=np.log(0.1), min=np.log(1.0e-20), # max=np.log(1.0e20)) result_emcee = minimize(residual, params=emcee_params, args=(new_wo, new_fo, new_eo), method='emcee', nan_policy='omit', steps=1000) report_fit(result_emcee) plt.plot(new_wo, new_fo) # plt.plot(new_wo, spec_fit) spec_emcee = model.get_spectrum(result_emcee.params, new_wo) plt.plot(new_wo, spec_emcee) corner.corner(result_emcee.flatchain, labels=result_emcee.var_names, truths=list(result_emcee.params.valuesdict().values())) plt.show()
def perform_fit(exp_volumes, exp_pressures, starting_params, interval, fix_vo=False, bm2=False): volumes = exp_volumes[:, 0] sigV = exp_volumes[:, 1] p = exp_pressures[:, 0] sigP = exp_pressures[:, 1] uncert = np.column_stack((sigV, sigP)) #initial starting parameters fit_params = Parameters() fit_params.add('vo', value=starting_params['vo'], min=0.0) fit_params.add('ko', value=starting_params['ko'], min=0.0) fit_params.add('kp', value=starting_params['kp']) if fix_vo: fit_params['vo'].vary = False if bm2: fit_params['kp'].vary = False mini = Minimizer(bm3, fit_params, fcn_args=(volumes,), fcn_kws={'data': p,\ 'uncert': uncert}) out1 = mini.minimize(method='Nedler') out2 = mini.minimize(method='leastsq', params=out1.params) results = out2.params.valuesdict() plot_volumes = np.linspace((np.min(volumes) - 10), results['vo'], 1000) fit = bm3(out2.params, plot_volumes) report_fit(out2, show_correl=True, min_correl=0.001) PVs = np.column_stack((fit, plot_volumes)) ci = conf_interval(mini, out2) report_ci(ci) return ci, mini, out2, PVs
def align_distorted_spectra(ref_spectra, traced_flux, verbose=False): # First, sort out the two data sets refx = np.arange(ref_spectra.shape[0]) refy = ref_spectra datax = np.arange(traced_flux.shape[0]) datay = traced_flux #plt.close() #plt.plot(datax,datay, 'r') #plt.plot(refx,refy, 'b') #plt.show() spreader = wavespreader(datax, datay, refx, refy) dw = np.argmax(datay) - np.argmax(refy) theta0 = np.array([dw, 3000, 0., 0.]) params = Parameters() params.add('c0', value=theta0[0], min=theta0[0] - 50, max=theta0[0] + 50) params.add('c1', value=theta0[1], min=theta0[1] - 10, max=theta0[1] + 10) params.add('c2', value=theta0[2], min=theta0[2] - 1e-1, max=theta0[2] + 1e-1) params.add('c3', value=theta0[3], min=theta0[3] - 1e-5, max=theta0[3] + 1e-5) mini = Minimizer(spreader.residuals_lmfit, params, nan_policy='propagate') lmfit_minimize_result = mini.minimize(method='differential_evolution') if verbose: print('Align distorted spectr fit report') printfuncs.report_fit(lmfit_minimize_result, min_correl=0.5) return spreader, lmfit_minimize_result
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)
return model - data n = 1500 xmin = 0. xmax = 250.0 random.seed(0) noise = random.normal(scale=2.80, size=n) x = linspace(xmin, xmax, n) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=13.0, max=20, min=0.0) fit_params.add('period', value=2, max=10) fit_params.add('shift', value=0.0, max=pi / 2., min=-pi / 2.) fit_params.add('decay', value=0.02, max=0.10, min=0.00) out = minimize(residual, fit_params, args=(x, ), kws={'data': data}) fit = residual(out.params, x) report_fit(out, show_correl=True, modelpars=p_true) print('\n\nRaw (unordered, unscaled) Covariance Matrix:') print(out.covar) if HASPYLAB: plt.plot(x, data, 'ro') plt.plot(x, fit, 'b') plt.show()
def test_constraints(with_plot=True): with_plot = with_plot and WITHPLOT 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 = 201 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) if with_plot: pylab.plot(x, data, 'r+') 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, min_correl=0.3) fit = residual(result.params, x) if with_plot: pylab.plot(x, fit, 'b-') assert(result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert(result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert(result.params['wid_l'].value == 2 * result.params['wid_g'].value) # now, change fit slightly and re-run myfit.params['wid_l'].expr = '1.25*wid_g' result = myfit.leastsq() report_fit(result.params, min_correl=0.4) fit2 = residual(result.params, x) if with_plot: pylab.plot(x, fit2, 'k') pylab.show() assert(result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert(result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert(result.params['wid_l'].value == 1.25 * result.params['wid_g'].value)
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) if HASPYLAB: pylab.plot(x, init, 'b--') result = myfit.leastsq() report_fit(result) fit = residual(result.params, x) if HASPYLAB: pylab.plot(x, fit, 'k-') pylab.show()
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) if HASPYLAB: pylab.plot(x, init, 'b--') result = myfit.leastsq() report_fit(result) fit = residual(result.params, x) if HASPYLAB: pylab.plot(x, fit, 'k-') pylab.show()
xmin = 0. xmax = 250.0 random.seed(0) noise = random.normal(scale=2.80, size=n) x = linspace(xmin, xmax, n) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=13.0, max=20, min=0.0) fit_params.add('period', value=2, max=10) fit_params.add('shift', value=0.0, max=pi/2., min=-pi/2.) fit_params.add('decay', value=0.02, max=0.10, min=0.00) out = minimize(residual, fit_params, args=(x,), kws={'data':data}) fit = residual(fit_params, x) print '# N_func_evals, N_free = ', out.nfev, out.nfree print '# chi-square, reduced chi-square = % .7g, % .7g' % (out.chisqr, out.redchi) report_fit(fit_params, show_correl=True, modelpars=p_true) print 'Raw (unordered, unscaled) Covariance Matrix:' print out.covar if HASPYLAB: pylab.plot(x, data, 'ro') pylab.plot(x, fit, 'b') pylab.show()
def slit_fit(nu, spec, init_params=None, lineshape='sGaussian', power_factor=1., eval_only=False, save_fit=False, dir_save=None, file_name=None, **kwargs): r"""fitting the experimental slit function with a chosen lineshape .. attention:: It is recommended to always look for initial parameters by using the `eval_only` option to roughly match the shape of the experimental slit function. The built-in initial parameters may not work for all the cases. Parameters ---------- nu : 1d array of floats Spectral positions in [:math:`\mathrm{cm}^{-1}`]. spec : 1d array of floats Experimentally obtained slit function, usually an isolated atomic line from a calibration lamp. init_params : dict, optional Initial fitting parameters for the lineshape. Refer to :mod:`carspy.convol_fcn.asym_Voigt` and :mod:`carspy.convol_fcn.asym_Gaussian` for the required arguments. lineshape : str, optional Type of the lineshape, by default 'sGaussian'. Choose between 'sGaussian' and 'sVoigt'. eval_only : bool, optional If true, returns the evaluation with given initial parameters. save_fit : bool, optional If true, fit results will be saved in a pickle file. dir_save : str, optional If `save_fit` is true, a string to the desired directory for saving. file_name : str, optional If `save_fit` is true, specify the file name without file extension. Other Parameters ---------------- **kwargs: Keyword arguments of the `Model.fit()` method from the module `lmfit`. Returns ------- 1d array If `eval_only` is true, the evaluation result is returned. """ if lineshape == 'sGaussian': slit_func = partial(asym_Gaussian, power_factor=power_factor) elif lineshape == 'sVoigt': slit_func = partial(asym_Voigt, power_factor=power_factor) else: raise ValueError("Please choose between 'sGaussian' and 'sVoigt'") slit_func.__name__ = 'slit_func' fit_model = Model( slit_func, independent_vars='w', ) if init_params is None: init_params = (('w0', 0, True), ('sigma', 2, True, 0.01, 10), ('k', 2, True, 0, 10), ('a_sigma', -0.8, True, -5, 5), ('a_k', 1, True, -5, 5), ('sigma_L_l', 0.1, True, 0.01, 5), ('sigma_L_h', 0.1, True, 0.01, 5), ('offset', 0, True, 0, 1)) params = fit_model.make_params() params.add_many(*init_params) if eval_only: return fit_model.eval(params, w=nu) else: fit_result = fit_model.fit((spec / spec.max())**power_factor, params, w=nu, **kwargs) report_fit(fit_result, show_correl=True, modelpars=params) fit_result.plot() if save_fit and dir_save and file_name: path_write = Path(dir_save) / (file_name + '.pkl') pkl_dump(path_write, fit_result)
params_kinetic_seasonal.add("mu_partition", value=0.5, min=math.pow(10.0, -6.0), max=1.0, vary=True) params_kinetic_seasonal.add("tau_mu", value=100.0, min=1.0, max=365.0, vary=True) kinetic_seasonal_model = Model(SIRD_kinetic_seasonal, independent_vars=['t', 'x0']) optimization_method = "differential_evolution" # change to another method if desired out_kinetic_seasonal = minimize(loss_function, params_kinetic_seasonal, args=( T, X0, ), kws={ "model": kinetic_seasonal_model, "data": data_array }, method=optimization_method) report_fit(out_kinetic_seasonal, show_correl=False) params_json = out_kinetic_seasonal.params.dumps() with open(optimization_method + "_params.json", mode='w') as fname: json.dump(params_json, fname)
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) if HASPYLAB: pylab.plot(x, init, 'b--') myfit.leastsq() print(' Nfev = ', myfit.nfev) print(myfit.chisqr, myfit.redchi, myfit.nfree) report_fit(myfit.params) fit = residual(myfit.params, x) if HASPYLAB: pylab.plot(x, fit, 'k-') pylab.show()
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 = loren(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) + loren(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x * 0.5) pfit = [ Parameter(name='amp_g', value=10), Parameter(name='cen_g', value=9), Parameter(name='wid_g', value=1), Parameter(name='amp_tot', value=20), Parameter(name='amp_l', expr='amp_tot - amp_g'), Parameter(name='cen_l', expr='1.5+cen_g'), Parameter(name='line_slope', value=0.0), Parameter(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.asteval.symtable['wfun'] = width_func myfit.params.add(name='wid_l', expr='wfun(wid_g)') myfit.leastsq() print(' Nfev = ', myfit.nfev) print(myfit.chisqr, myfit.redchi, myfit.nfree) report_fit(myfit.params) pfit = myfit.params fit = residual(myfit.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)
xmin = 0. xmax = 250.0 random.seed(0) noise = random.normal(scale=2.80, size=n) x = linspace(xmin, xmax, n) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=13.0, max=20, min=0.0) fit_params.add('period', value=2, max=10) fit_params.add('shift', value=0.0, max=pi/2., min=-pi/2.) fit_params.add('decay', value=0.02, max=0.10, min=0.00) out = minimize(residual, fit_params, args=(x,), kws={'data':data}) fit = residual(out.params, x) print '# N_func_evals, N_free = ', out.nfev, out.nfree print '# chi-square, reduced chi-square = % .7g, % .7g' % (out.chisqr, out.redchi) report_fit(out.params, show_correl=True, modelpars=p_true) print 'Raw (unordered, unscaled) Covariance Matrix:' print out.covar if HASPYLAB: pylab.plot(x, data, 'ro') pylab.plot(x, fit, 'b') pylab.show()
def fit(template, wave, flux, err, params=None, show=False, isprint=False, mask=None): print('run fit') if params is None: params = Parameters() # set_pars(params, 'shift', [0, 1], valuelst=[1.16, -0.00076]) shiftparname = set_pars(params, 'shift', [1], valuelst=[0.0]) # sigmaparname = set_pars(params, 'sigma', [1], valuelst=[0.00001], # minlst=[1.0e-8], maxlst=[5.0e-4]) scalevalst = [1.0, -1.0, -1.0, 0.22, -0.1, -0.13] scaleparname = set_pars(params, 'scale', 5, valuelst=scalevalst) # template.set_lmpar_name(scaleparname, sigmaparname, shiftparname) template.set_lmpar_name(scaleparname, None, shiftparname) # start = time.process_time() # print(start) if mask is not None: argsel = func.mask(wave, mask) # print('len wave, flux, err') # print(len(wave)) # print(len(flux)) # print(len(err)) def residual(pars, x, data, eps): # print('flag') # print(pars) # print(x) # print('length of template is ') # print(len(template.wave)) flux_fit1 = template.get_spectrum(pars, x) # print(len(flux_fit1)) # arrpar = read_lmpar(pars, sigmaparname) # flux_fit2 = np.array(convol.gauss_filter(x, data, arrpar)) if mask is not None: return ((flux_fit1 - data) / eps)[argsel] return (flux_fit1 - flux_fit2) / eps # out = minimize(template.residual, params, args=(wave, flux, err), # method='leastsq') # end = time.process_time() # print("Time used:", end-start) out = minimize(residual, params, args=(wave, flux, err), method='leastsq') if isprint: report_fit(out) # shift = out.params['shift1'].value * c # shifterr = out.params['shift1'].stderr * c # print('-'*20+' velocity '+'-'*20) # print(shift.to('km/s')) # print(shifterr.to('km/s')) if show: plt.figure() # arrpar = read_lmpar(out.params, sigmaparname) # print('gaussian filter par = ') # print(arrpar) plt.plot(wave, flux) spec_fit = template.get_spectrum(out.params, wave) # lower = spec_fit - err # upper = spec_fit + err # # plt.fill_between(wave, lower, upper, alpha=0.3, color='grey') plt.plot(wave, spec_fit) plt.show() return out
if data is None: return model return model - data ############################################################################### # Generate synthetic data and initialize fitting Parameters: random.seed(0) x = linspace(0, 250, 1500) noise = random.normal(scale=2.8, size=x.size) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=13, max=20, min=0) fit_params.add('period', value=2, max=10) fit_params.add('shift', value=0, max=pi/2., min=-pi/2.) fit_params.add('decay', value=0.02, max=0.1, min=0) ############################################################################### # Perform the fit and show the results: out = minimize(residual, fit_params, args=(x,), kws={'data': data}) fit = residual(out.params, x) ############################################################################### report_fit(out, modelpars=p_true) ############################################################################### plt.plot(x, data, 'o', label='data') plt.plot(x, fit, label='best fit') plt.legend()
Parameter(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) if HASPYLAB: pylab.plot(x, init, 'b--') myfit.leastsq() print(' Nfev = ', myfit.nfev) print( myfit.chisqr, myfit.redchi, myfit.nfree) report_fit(myfit.params) fit = residual(myfit.params, x) if HASPYLAB: pylab.plot(x, fit, 'k-') pylab.show()
def test_constraints(with_plot=True): with_plot = with_plot and WITHPLOT 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 = 201 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) if with_plot: pylab.plot(x, data, 'r+') 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) myfit.leastsq() print(' Nfev = ', myfit.nfev) print(myfit.chisqr, myfit.redchi, myfit.nfree) report_fit(myfit.params, min_correl=0.3) fit = residual(myfit.params, x) if with_plot: pylab.plot(x, fit, 'b-') assert (myfit.params['cen_l'].value == 1.5 + myfit.params['cen_g'].value) assert (myfit.params['amp_l'].value == myfit.params['amp_tot'].value - myfit.params['amp_g'].value) assert (myfit.params['wid_l'].value == 2 * myfit.params['wid_g'].value) # now, change fit slightly and re-run myfit.params['wid_l'].expr = '1.25*wid_g' myfit.leastsq() report_fit(myfit.params, min_correl=0.4) fit2 = residual(myfit.params, x) if with_plot: pylab.plot(x, fit2, 'k') pylab.show() assert (myfit.params['cen_l'].value == 1.5 + myfit.params['cen_g'].value) assert (myfit.params['amp_l'].value == myfit.params['amp_tot'].value - myfit.params['amp_g'].value) assert (myfit.params['wid_l'].value == 1.25 * myfit.params['wid_g'].value)
def ls_fit(self, add_params=None, path_fit=None, show_fit=False, eval_only=False, **kwargs): """ Fitting the experimental CARS spectrum. .. attention:: The least-quare fit module ``lmfit`` is necessary for this method. Please be aware that certain Python versions may not be supported by ``lmfit``. For displaying the fit results ``matplotlib`` will be needed as well. Parameters ---------- add_params : nested tuple, optional List of parameters controlling the fitting process. This option can be used to modify these initial parameters: .. code-block:: python (('temperature', 2000, True, 250, 3000), ('del_Tv', 0, False), ('x_mol', 0.6, x_mol_var, 0.2, 1.5), ('nu_shift', fit_params['nu_shift'], False), ('nu_stretch', fit_params['nu_stretch'], False), ('pump_lw', fit_params['pump_lw'], False), ('param1', fit_params['param1'], False), ('param2', fit_params['param2'], False), ('param3', fit_params['param3'], False), ('param4', fit_params['param4'], False), ('param5', fit_params['param5'], False), ('param6', fit_params['param6'], False)) Each element of the nested tuple has the following element in order: variable_name : str All the arguments of :mod:`carspy.cars_fit.CarsFit.cars_expt_synth` are admissible variables except for the independent variable `nu_expt`. initial_guess : float Initial guess or fixed value set for this variable. variable : bool Determine if the variable is fixed (False) or not (True) during the fit. lower_bound : float Lower boundary for the fitting variable. If not provided, negative infinity will be assumed. upper_bound : float Upper boundary for the fitting variable. If not provide, positive infinity will be assumed. For more details refer to the documentation of ``lmfit.Model``. path_fit : str Path to the `.pkl` file of fitting result created by :mod:`carspy.cars_fit.CarsFit.save_fit`. This allows importing the fitting result of an existing spectrum, such that the inferred values of certain parameters (such as those related to the spectrometer) could be re-used in the next fit. A standard use case for this would be the fitting result of a room-temperature spectrum. This is needed if the `fit` in `fit_mode` of :mod:`carspy.cars_fit.CarsFit` is set to `T_x`. show_fit : bool, optional If True, the fitting results will be reported and plotted. This is done via built-in functions in ``lmfit``. """ # general setup fit_model = Model(self.cars_expt_synth, independent_vars=['nu_expt']) initi_params = [] # different fitting modes if self.fit_mode['fit'] == 'T_x': if path_fit is None: raise ValueError("Please provide path to a .pkl file " "containing the fitting result of a spectrum") if self.fit_mode['chem_eq']: x_mol_var = False else: x_mol_var = True fit_params = pkl_load(path_fit).params initi_params = (('temperature', 2000, True, 250, 3000), ('del_Tv', 0, False), ('x_mol', 0.6, x_mol_var, 0.2, 1.5), ('nu_shift', fit_params['nu_shift'], False), ('nu_stretch', fit_params['nu_stretch'], False), ('pump_lw', fit_params['pump_lw'], False), ('param1', fit_params['param1'], False), ('param2', fit_params['param2'], False), ('param3', fit_params['param3'], False), ('param4', fit_params['param4'], False), ('param5', fit_params['param5'], False), ('param6', fit_params['param6'], False)) if self.fit_mode['fit'] == 'custom': if add_params is None: raise ValueError("Please specify fitting parameters first " "using add_params") params = fit_model.make_params() params.add_many(*initi_params) if add_params is not None: params.add_many(*add_params) if eval_only: return fit_model.eval(params, nu_expt=self.nu) else: self.fit_result = fit_model.fit(np.nan_to_num(self.spec_cars), params, nu_expt=self.nu, **kwargs) if show_fit: report_fit(self.fit_result, show_correl=True, modelpars=params) self.fit_result.plot()
def fit_lamost(): bluelst, redlst = [], [] namelst = glob.glob('/home/zzx/workspace/data/stellar_X/*.fits') namelst = [ '/home/zzx/workspace/data/stellar_X/med-58409-TD045606N223435B01_sp16-102.fits' ] for name in namelst: # fig1 = plt.figure() # fig2 = plt.figure() # ax1 = fig1.add_subplot(111) # ax2 = fig2.add_subplot(111) print(name) size = len(fits.open(name)) for ind in range(3, size): spec = specio.Spectrum(name, ind) spec.clean_cosmic_ray() if 'B' in spec.header['EXTNAME']: bluelst.append(spec) else: redlst.append(spec) name = namelst[0] model_blue = Model(name, 3) model_blue.clean_cosmic_ray() model_red = Model(name, 11) model_red.clean_cosmic_ray() params = Parameters() shiftparname = set_pars(params, 'shift', [1], valuelst=[0.0]) scalevalst = [ 0.99608100, -0.00931768, 0.00319284, 5.5658e-04, -4.4060e-04, 0.0 ] bscaleparname = set_pars(params, 'b_scale', 5, valuelst=scalevalst) rscaleparname = set_pars(params, 'r_scale', 5, valuelst=scalevalst) bsimgapar = set_pars(params, 'b_sigma', [1], valuelst=[0.0004]) rsigmapar = set_pars(params, 'r_sigma', [1], valuelst=[0.0004]) model_blue.set_lmpar_name(bscaleparname, bsimgapar, shiftparname) model_red.set_lmpar_name(rscaleparname, rsigmapar, shiftparname) shiftlst, shifterrlst = [], [] def residual(pars, x1, data1, eps1, x2, data2, eps2): res1 = model_blue.residual(pars, x1, data1, eps1) res2 = model_red.residual(pars, x2, data2, eps2) return np.append(res2, res1) return res2 for ind in range(len(redlst)): bspec = bluelst[ind] # bspec = redlst[ind] rspec = redlst[ind] arg1 = func.select(bspec.wave, [[4920, 5300]]) bnw = bspec.wave[arg1] bnf = bspec.flux[arg1] bne = bspec.err[arg1] arg2 = func.select(rspec.wave, [[6320, 6860]]) rnw = rspec.wave[arg2] rnf = rspec.flux[arg2] rne = rspec.err[arg2] bfakeerr = np.ones(len(bnw), dtype=np.float64) * 0.01 rfakeerr = np.ones(len(rnw), dtype=np.float64) * 0.01 bne = bfakeerr rne = rfakeerr # out = minimize(model_blue.residual, params, args=(nw, nf)) # out = minimize(model_red.residual, params, args=(nw, nf)) out = minimize(residual, params, args=(bnw, bnf, bne, rnw, rnf, rne)) report_fit(out) shiftlst.append(out.params['shift1'].value * c) shifterrlst.append(out.params['shift1'].stderr * c) plt.figure() spec_fit_blue = model_blue.get_spectrum(out.params, model_blue.wave) spec_fit_red = model_red.get_spectrum(out.params, model_red.wave) plt.plot(bnw, bnf) plt.plot(model_blue.wave, spec_fit_blue) plt.figure() plt.plot(rnw, rnf) plt.plot(model_red.wave, spec_fit_red) plt.show() for ind, value in enumerate(shiftlst): # print(value.to('km/s')) print(value.to('km/s'), shifterrlst[ind].to('km/s'))