def _resid(params, datasets=None, paramgroup=None, _larch=None, **kwargs): """ this is the residual function""" params2group(params, paramgroup) return concatenate([d._residual(paramgroup) for d in datasets])
def feffit(paramgroup, datasets, rmax_out=10, path_outputs=True, _larch=None, **kws): """execute a Feffit fit: a fit of feff paths to a list of datasets Parameters: ------------ paramgroup: group containing parameters for fit datasets: Feffit Dataset group or list of Feffit Dataset group. rmax_out: maximum R value to calculate output arrays. path_output: Flag to set whether all Path outputs should be written. Returns: --------- a fit results group. This will contain subgroups of: datasets: an array of FeffitDataSet groups used in the fit. params: This will be identical to the input parameter group. fit: an object which points to the low-level fit. Statistical parameters will be put into the params group. Each dataset will have a 'data' and 'model' subgroup, each with arrays: k wavenumber array of k chi chi(k). kwin window Omega(k) (length of input chi(k)). r uniform array of R, out to rmax_out. chir complex array of chi(R). chir_mag magnitude of chi(R). chir_pha phase of chi(R). chir_re real part of chi(R). chir_im imaginary part of chi(R). """ def _resid(params, datasets=None, paramgroup=None, _larch=None, **kwargs): """ this is the residual function""" params2group(params, paramgroup) return concatenate([d._residual(paramgroup) for d in datasets]) if isNamedClass(datasets, FeffitDataSet): datasets = [datasets] params = group2params(paramgroup, _larch=_larch) for ds in datasets: if not isNamedClass(ds, FeffitDataSet): print("feffit needs a list of FeffitDataSets") return ds.prepare_fit() fit = Minimizer(_resid, params, fcn_kws=dict(datasets=datasets, paramgroup=paramgroup), scale_covar=True, **kws) result = fit.leastsq() params2group(result.params, paramgroup) dat = concatenate( [d._residual(paramgroup, data_only=True) for d in datasets]) n_idp = 0 for ds in datasets: n_idp += ds.n_idp # here we rescale chi-square and reduced chi-square to n_idp npts = len(result.residual) chi_square = result.chisqr * n_idp * 1.0 / npts chi_reduced = chi_square / (n_idp * 1.0 - result.nvarys) rfactor = (result.residual**2).sum() / (dat**2).sum() # calculate 'aic', 'bic' rescaled to n_idp # note that neg2_loglikel is -2*log(likelihood) neg2_loglikel = n_idp * np.log(chi_square / n_idp) aic = neg2_loglikel + 2 * result.nvarys bic = neg2_loglikel + np.log(n_idp) * result.nvarys # With scale_covar = True, Minimizer() scales the uncertainties # by reduced chi-square assuming params.nfree is the correct value # for degrees-of-freedom. But n_idp-params.nvarys is a better measure, # so we rescale uncertainties here. covar = getattr(result, 'covar', None) # print("COVAR " , covar) if covar is not None: err_scale = (result.nfree / (n_idp - result.nvarys)) for name in result.var_names: p = result.params[name] if isParameter(p) and p.vary: p.stderr *= sqrt(err_scale) # next, propagate uncertainties to constraints and path parameters. result.covar *= err_scale vsave, vbest = {}, [] # 1. save current params for vname in result.var_names: par = result.params[vname] vsave[vname] = par vbest.append(par.value) # 2. get correlated uncertainties, set params accordingly uvars = correlated_values(vbest, result.covar) # 3. evaluate constrained params, save stderr for nam, obj in result.params.items(): eval_stderr(obj, uvars, result.var_names, result.params) # vsave) # , _larch) # 3. evaluate path params, save stderr for ds in datasets: for p in ds.pathlist: p.store_feffdat() for pname in ('degen', 's02', 'e0', 'ei', 'deltar', 'sigma2', 'third', 'fourth'): obj = p.params[PATHPAR_FMT % (pname, p.label)] eval_stderr(obj, uvars, result.var_names, result.params) # restore saved parameters again for vname in result.var_names: # setattr(params, vname, vsave[vname]) params[vname] = vsave[vname] # clear any errors evaluting uncertainties if len(_larch.error) > 0: _larch.error = [] # reset the parameters group with the newly updated uncertainties params2group(result.params, paramgroup) # here we create outputs arrays for chi(k), chi(r): for ds in datasets: ds.save_ffts(rmax_out=rmax_out, path_outputs=path_outputs) out = Group(name='feffit results', datasets=datasets, fitter=fit, fit_details=result, chi_square=chi_square, n_independent=n_idp, chi_reduced=chi_reduced, rfactor=rfactor, aic=aic, bic=bic, covar=covar) for attr in ('params', 'nvarys', 'nfree', 'ndata', 'var_names', 'nfev', 'success', 'errorbars', 'message', 'lmdif_message'): setattr(out, attr, getattr(result, attr, None)) return out