Exemple #1
0
 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])
Exemple #2
0
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