示例#1
0
 def _peakparams(self, paramgroup=None, **kws):
     """evaluate peak parameter values        """
     # sigma, amplitude, center
     out = []
     for parname in ('amplitude', 'sigma', 'center'):
         val = getattr(self, parname)
         if parname in kws:
             if kws[parname] is not None:
                 val = kws[parname]
         if isinstance(val, six.string_types):
             thispar = Parameter(expr=val, _larch=self._larch)
             setattr(self, parname, thispar)
             val = getattr(self, parname)
         out.append(param_value(val))
     return out
示例#2
0
def autobk(energy, mu=None, group=None, rbkg=1, nknots=None, e0=None,
           edge_step=None, kmin=0, kmax=None, kweight=1, dk=0,
           win='hanning', k_std=None, chi_std=None, nfft=2048, kstep=0.05,
           pre_edge_kws=None, nclamp=4, clamp_lo=1, clamp_hi=1,
           calc_uncertainties=False, _larch=None, **kws):
    """Use Autobk algorithm to remove XAFS background

    Parameters:
    -----------
      energy:    1-d array of x-ray energies, in eV, or group
      mu:        1-d array of mu(E)
      group:     output group (and input group for e0 and edge_step).
      rbkg:      distance (in Ang) for chi(R) above
                 which the signal is ignored. Default = 1.
      e0:        edge energy, in eV.  If None, it will be determined.
      edge_step: edge step.  If None, it will be determined.
      pre_edge_kws:  keyword arguments to pass to pre_edge()
      nknots:    number of knots in spline.  If None, it will be determined.
      kmin:      minimum k value   [0]
      kmax:      maximum k value   [full data range].
      kweight:   k weight for FFT.  [1]
      dk:        FFT window window parameter.  [0]
      win:       FFT window function name.     ['hanning']
      nfft:      array size to use for FFT [2048]
      kstep:     k step size to use for FFT [0.05]
      k_std:     optional k array for standard chi(k).
      chi_std:   optional chi array for standard chi(k).
      nclamp:    number of energy end-points for clamp [2]
      clamp_lo:  weight of low-energy clamp [1]
      clamp_hi:  weight of high-energy clamp [1]
      calc_uncertaintites:  Flag to calculate uncertainties in
                            mu_0(E) and chi(k) [False]

    Output arrays are written to the provided group.

    Follows the 'First Argument Group' convention.
    """
    msg = _larch.writer.write
    if 'kw' in kws:
        kweight = kws.pop('kw')
    if len(kws) > 0:
        msg('Unrecognized a:rguments for autobk():\n')
        msg('    %s\n' % (', '.join(kws.keys())))
        return

    energy, mu, group = parse_group_args(energy, members=('energy', 'mu'),
                                         defaults=(mu,), group=group,
                                         fcn_name='autobk')

    energy = remove_dups(energy)
    # if e0 or edge_step are not specified, get them, either from the
    # passed-in group or from running pre_edge()
    group = set_xafsGroup(group, _larch=_larch)

    if edge_step is None and isgroup(group, 'edge_step'):
        edge_step = group.edge_step
    if e0 is None and isgroup(group, 'e0'):
        e0 = group.e0
    if e0 is None or edge_step is None:
        # need to run pre_edge:
        pre_kws = dict(nnorm=3, nvict=0, pre1=None,
                       pre2=-50., norm1=100., norm2=None)
        if pre_edge_kws is not None:
            pre_kws.update(pre_edge_kws)
        pre_edge(energy, mu, group=group, _larch=_larch, **pre_kws)
        if e0 is None:
            e0 = group.e0
        if edge_step is None:
            edge_step = group.edge_step
    if e0 is None or edge_step is None:
        msg('autobk() could not determine e0 or edge_step!: trying running pre_edge first\n')
        return

    # get array indices for rkbg and e0: irbkg, ie0
    ie0 = index_of(energy, e0)
    rgrid = np.pi/(kstep*nfft)
    if rbkg < 2*rgrid: rbkg = 2*rgrid
    irbkg = int(1.01 + rbkg/rgrid)

    # save ungridded k (kraw) and grided k (kout)
    # and ftwin (*k-weighting) for FT in residual
    enpe = energy[ie0:] - e0
    kraw = np.sign(enpe)*np.sqrt(ETOK*abs(enpe))
    if kmax is None:
        kmax = max(kraw)
    else:
        kmax = max(0, min(max(kraw), kmax))
    kout  = kstep * np.arange(int(1.01+kmax/kstep), dtype='float64')
    iemax = min(len(energy), 2+index_of(energy, e0+kmax*kmax/ETOK)) - 1

    # interpolate provided chi(k) onto the kout grid
    if chi_std is not None and k_std is not None:
        chi_std = np.interp(kout, k_std, chi_std)
    # pre-load FT window
    ftwin = kout**kweight * ftwindow(kout, xmin=kmin, xmax=kmax,
                                     window=win, dx=dk)
    # calc k-value and initial guess for y-values of spline params
    nspl = max(4, min(128, 2*int(rbkg*(kmax-kmin)/np.pi) + 1))
    spl_y, spl_k, spl_e  = np.zeros(nspl), np.zeros(nspl), np.zeros(nspl)
    for i in range(nspl):
        q  = kmin + i*(kmax-kmin)/(nspl - 1)
        ik = index_nearest(kraw, q)
        i1 = min(len(kraw)-1, ik + 5)
        i2 = max(0, ik - 5)
        spl_k[i] = kraw[ik]
        spl_e[i] = energy[ik+ie0]
        spl_y[i] = (2*mu[ik+ie0] + mu[i1+ie0] + mu[i2+ie0] ) / 4.0

    # get spline represention: knots, coefs, order=3
    # coefs will be varied in fit.
    knots, coefs, order = splrep(spl_k, spl_y)

    # set fit parameters from initial coefficients
    params = Group()
    for i in range(len(coefs)):
        name = FMT_COEF % i
        p = Parameter(coefs[i], name=name, vary=i<len(spl_y))
        p._getval()
        setattr(params, name, p)

    initbkg, initchi = spline_eval(kraw[:iemax-ie0+1], mu[ie0:iemax+1],
                                   knots, coefs, order, kout)

    # do fit
    fit = Minimizer(__resid, params, _larch=_larch, toler=1.e-4,
                    fcn_kws = dict(ncoefs=len(coefs), chi_std=chi_std,
                                   knots=knots, order=order,
                                   kraw=kraw[:iemax-ie0+1],
                                   mu=mu[ie0:iemax+1], irbkg=irbkg, kout=kout,
                                   ftwin=ftwin, kweight=kweight,
                                   nfft=nfft, nclamp=nclamp,
                                   clamp_lo=clamp_lo, clamp_hi=clamp_hi))
    fit.leastsq()

    # write final results
    coefs = [getattr(params, FMT_COEF % i) for i in range(len(coefs))]
    bkg, chi = spline_eval(kraw[:iemax-ie0+1], mu[ie0:iemax+1],
                           knots, coefs, order, kout)
    obkg = np.copy(mu)
    obkg[ie0:ie0+len(bkg)] = bkg

    # outputs to group
    group = set_xafsGroup(group, _larch=_larch)
    group.bkg  = obkg
    group.chie = (mu-obkg)/edge_step
    group.k    = kout
    group.chi  = chi/edge_step

    # now fill in 'autobk_details' group
    params.init_bkg = np.copy(mu)
    params.init_bkg[ie0:ie0+len(bkg)] = initbkg
    params.init_chi = initchi/edge_step
    params.knots_e  = spl_e
    params.knots_y  = np.array([coefs[i] for i in range(nspl)])
    params.init_knots_y = spl_y
    params.nfev = params.fit_details.nfev
    params.kmin = kmin
    params.kmax = kmax  
    group.autobk_details = params

    # uncertainties in mu0 and chi:  fairly slow!!
    if HAS_UNCERTAIN and calc_uncertainties:
        vbest, vstd = [], []
        for n in fit.var_names:
            par = getattr(params, n)
            vbest.append(par.value)
            vstd.append(par.stderr)
        uvars = uncertainties.correlated_values(vbest, params.covar)
        # uncertainty in bkg (aka mu0)
        # note that much of this is working around
        # limitations in the uncertainty package that make it
        #  1. take an argument list (not array)
        #  2. work on returned scalars (but not arrays)
        #  3. not handle kw args and *args well (so use
        #     of global "index" is important here)
        nkx = iemax-ie0 + 1
        def my_dsplev(*args):
            coefs = np.array(args)
            return splev(kraw[:nkx], [knots, coefs, order])[index]
        fdbkg = uncertainties.wrap(my_dsplev)
        dmu0  = [fdbkg(*uvars).std_dev() for index in range(len(bkg))]
        group.delta_bkg = np.zeros(len(mu))
        group.delta_bkg[ie0:ie0+len(bkg)] = np.array(dmu0)

        # uncertainty in chi (see notes above)
        def my_dchi(*args):
            coefs = np.array(args)
            b,chi = spline_eval(kraw[:nkx], mu[ie0:iemax+1],
                                knots, coefs, order, kout)
            return chi[index]
        fdchi = uncertainties.wrap(my_dchi)
        dchi  = [fdchi(*uvars).std_dev() for index in range(len(kout))]
        group.delta_chi = np.array(dchi)/edge_step
示例#3
0
def do_fit(self, which):

    if which == 'testrun':
        folder = self.testrun
    else:
        folder = self.baseline

    data = read_xdi(join(self.path, 'UO2.chik'), _larch=self._larch)

    gds = Group(amp=Parameter(1, vary=True, _larch=self._larch),
                enot=Parameter(0.01, vary=True, _larch=self._larch),
                sso=Parameter(0.003, vary=True, _larch=self._larch),
                ssu=Parameter(0.003, vary=True, _larch=self._larch),
                sso2=Parameter(0.003, vary=True, _larch=self._larch),
                dro=Parameter(0.0001, vary=True, _larch=self._larch),
                dru=Parameter(0.0001, vary=True, _larch=self._larch),
                dro2=Parameter(0.0001, vary=True, _larch=self._larch),
                nu=Parameter(12, vary=True, _larch=self._larch),
                no2=Parameter(expr='2*nu', _larch=self._larch),
                _larch=self._larch)

    paths = list()
    paths.append(
        feffpath(
            realpath(join(folder, "feff0001.dat")),  # 1st shell O SS
            s02='amp',
            e0='enot',
            sigma2='sso',
            deltar='dro',
            _larch=self._larch))
    # paths.append(feffpath(realpath(join(folder, "feff0002.dat")), # triangle in first shell
    #                       s02    = 'amp',
    #                       e0     = 'enot',
    #                       sigma2 = 'sso*1.5',
    #                       deltar = 'dro*(1+sqrt(2))/2', _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0003.dat")),  # 2nd shell U SS
            degen=1,
            s02='amp*nu',
            e0='enot',
            sigma2='ssu',
            deltar='dru',
            _larch=self._larch))
    # paths.append(feffpath(realpath(join(folder, "feff0004.dat")), # 1st shell, longer triangle
    #                       s02    = 'amp',
    #                       e0     = 'enot',
    #                       sigma2 = '2*sso',
    #                       deltar = '2*dro', _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0006.dat")),  # 3rd shell O SS
            degen=1,
            s02='amp*no2',
            #s02    = 'amp*nu*2',
            e0='enot',
            sigma2='sso2',
            deltar='dro2',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0007.dat")
                     ),  # 1st shell, non-forward linear through absorber
            s02='amp',
            e0='enot',
            sigma2='sso2',
            deltar='dro2',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(
                folder, "feff0008.dat")),  # 1st shell forward through absorber
            s02='amp',
            e0='enot',
            sigma2='2*sso',
            deltar='2*dro',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0009.dat")),  # rattle in 1st shell
            s02='amp',
            e0='enot',
            sigma2='2*sso',
            deltar='2*dro',
            _larch=self._larch))

    trans = feffit_transform(kmin=3,
                             kmax=11,
                             kw=(2, 1, 3),
                             dk=1,
                             window='hanning',
                             rmin=1.25,
                             rmax=4.3,
                             _larch=self._larch)
    dset = feffit_dataset(data=data,
                          pathlist=paths,
                          transform=trans,
                          _larch=self._larch)
    fit = feffit(gds, dset, _larch=self._larch)

    if self.doplot:
        offset = max(dset.data.chir_mag)
        _newplot(dset.data.r,
                 dset.data.chir_mag + offset,
                 xmax=8,
                 win=2,
                 xlabel=r'$R \rm\,(\AA)$',
                 label='data',
                 ylabel=r'$|\chi(R)| \rm\,(\AA^{-3})$',
                 title='Fit to ' + self.folder,
                 show_legend=True,
                 _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_mag + offset,
              label='fit',
              win=2,
              _larch=self._larch)
        _plot(dset.data.r,
              dset.data.chir_re,
              label='data',
              win=2,
              _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_re,
              label='fit',
              win=2,
              _larch=self._larch)
    #end if

    if self.verbose:
        print feffit_report(fit, _larch=self._larch)
    #end if

    return fit
示例#4
0
def do_fit(self, which, firstshell=False, fittest='baseline'):

    firstshell = False  # no 1st shell fit for this material

    if which == 'testrun':
        folder = self.testrun
    elif which == 'baseline':
        folder = self.baseline
    else:
        folder = realpath(join(self.folder, fittest, which))
    #endif

    data = read_xdi(join(self.path, 'uranyl.chik'), _larch=self._larch)

    gds = Group(
        amp=Parameter(1, vary=True, _larch=self._larch),
        enot=Parameter(1e-7, vary=True, _larch=self._larch),
        #enot   = Parameter(1e-7,   vary=True,  _larch=self._larch, min=0, max=13),
        enoteq=Parameter(expr='enot', _larch=self._larch),
        deloax=Parameter(1e-7, vary=True, _larch=self._larch),
        deloeq=Parameter(1e-7, vary=True, _larch=self._larch),
        sigoax=Parameter(0.003, vary=True, _larch=self._larch),
        sigoeq=Parameter(0.003, vary=True, _larch=self._larch),
        nax=Parameter(2.0, vary=False, _larch=self._larch),
        neq=Parameter(6, vary=False, _larch=self._larch),  #, min=0, max=12),
        _larch=self._larch)

    paths = list()
    paths.append(
        feffpath(
            realpath(join(folder, "feff0001.dat")),  # axial oxygen
            degen=1,
            s02='amp*nax',
            e0='enot',
            sigma2='sigoax',
            deltar='deloax',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0003.dat")),  # equatorial oxygen
            degen=1,
            s02='amp*neq',
            e0='enoteq',
            sigma2='sigoeq',
            deltar='deloeq',
            _larch=self._larch))

    paths.append(
        feffpath(
            realpath(join(folder, "feff0008.dat")),  # axial oxygen, rattle
            degen=1,
            s02='amp*nax',
            e0='enot',
            sigma2='sigoax*4',
            deltar='deloax*2',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder,
                          "feff0009.dat")),  # axial oxygen, non-forward
            degen=1,
            s02='amp*nax',
            e0='enot',
            sigma2='sigoax',
            deltar='deloax*2',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0010.dat")),  # axial oxygen, forward
            degen=1,
            s02='amp*nax',
            e0='enot',
            sigma2='sigoax',
            deltar='deloax*2',
            _larch=self._larch))

    trans = feffit_transform(kmin=3,
                             kmax=11,
                             kw=(2, 1, 3),
                             dk=1,
                             window='hanning',
                             rmin=1.0,
                             rmax=3.2,
                             _larch=self._larch)
    dset = feffit_dataset(data=data,
                          pathlist=paths,
                          transform=trans,
                          _larch=self._larch)
    fit = feffit(gds, dset, _larch=self._larch)

    if self.doplot:
        offset = max(dset.data.chir_mag)
        _newplot(dset.data.r,
                 dset.data.chir_mag + offset,
                 xmax=8,
                 win=2,
                 xlabel=r'$R \rm\,(\AA)$',
                 label='data',
                 ylabel=r'$|\chi(R)| \rm\,(\AA^{-3})$',
                 title='Fit to ' + self.folder,
                 show_legend=True,
                 _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_mag + offset,
              label='fit',
              win=2,
              _larch=self._larch)
        _plot(dset.data.r,
              dset.data.chir_re,
              label='data',
              win=2,
              _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_re,
              label='fit',
              win=2,
              _larch=self._larch)
    #end if

    if self.verbose:
        print feffit_report(fit, _larch=self._larch)
    #end if

    shells = ''
    if firstshell: shells = '_1st'

    write_ascii(join(self.folder, fittest, "fit_" + which + ".k"),
                dset.data.k,
                dset.data.chi,
                dset.model.chi,
                labels="r data_mag fit_mag data_re fit_re",
                _larch=self._larch)
    write_ascii(join(self.folder, fittest, "fit_" + which + ".r"),
                dset.data.r,
                dset.data.chir_mag,
                dset.model.chir_mag,
                dset.data.chir_re,
                dset.model.chir_re,
                labels="r data_mag fit_mag data_re fit_re",
                _larch=self._larch)

    renderer = pystache.Renderer()
    with open(join(self.folder, fittest, 'fit_' + which + '.gp'), 'w') as inp:
        inp.write(
            renderer.render_path(
                'plot.mustache',  # gnuplot mustache file
                {
                    'material': 'uranyl',
                    'model': which,
                    'fittest': fittest,
                    'shells': shells,
                    'kmin': 3,
                    'kmax': 11,
                    'rmin': 1.0,
                    'rmax': 3.2,
                    'offset': 1,
                }))

    return fit
示例#5
0
def do_fit(self, which):

    if which == 'testrun':
        folder = self.testrun
    else:
        folder = self.baseline

    data = read_xdi(join(self.path, 'NiO.chik'), _larch=self._larch)
    if hasattr(data, 'wavenumber'):
        data.k = data.wavenumber

    gds = Group(
        amp=Parameter(1, vary=True, _larch=self._larch),
        enot=Parameter(0.01, vary=True, _larch=self._larch),
        alpha=Parameter(0.0001, vary=True, _larch=self._larch),
        sso=Parameter(0.003, vary=True, _larch=self._larch),
        ssni=Parameter(0.003, vary=True, _larch=self._larch),
        sso2=Parameter(0.003, vary=True, _larch=self._larch),
        #sso3   = Parameter(0.003,  vary=True, _larch=self._larch),
        ssni2=Parameter(0.003, vary=True, _larch=self._larch),
        #ssni3  = Parameter(0.003,  vary=True, _larch=self._larch),
        #ssni4  = Parameter(0.003,  vary=True, _larch=self._larch),
        _larch=self._larch)

    paths = list()
    paths.append(
        feffpath(
            realpath(join(folder, "feff0001.dat")),  # 1st shell O SS
            s02='amp',
            e0='enot',
            sigma2='sso',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0002.dat")),  # 2nd shell Ni SS
            s02='amp',
            e0='enot',
            sigma2='ssni',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0003.dat")),  # O-O triangle
            s02='amp',
            e0='enot',
            sigma2='1.5*sso',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0004.dat")),  # O-Ni triangle
            s02='amp',
            e0='enot',
            sigma2='sso+ssni',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0005.dat")),  # 3rd shell O SS
            s02='amp',
            e0='enot',
            sigma2='sso2',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0006.dat")),  # 4th shell Ni SS
            s02='amp',
            e0='enot',
            sigma2='ssni2',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0007.dat")),  # O-O non-forward linear
            s02='amp',
            e0='enot',
            sigma2='sso*2',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0008.dat")),  # O-Ni forward scattering
            s02='amp',
            e0='enot',
            sigma2='ssni2',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder,
                          "feff0009.dat")),  # O-O forward through absorber
            s02='amp',
            e0='enot',
            sigma2='sso*2',
            deltar='alpha*reff',
            _larch=self._larch))
    paths.append(
        feffpath(
            realpath(join(folder, "feff0010.dat")),  # O-Ni-O double forward
            s02='amp',
            e0='enot',
            sigma2='ssni2',
            deltar='alpha*reff',
            _larch=self._larch))

    trans = feffit_transform(kmin=3,
                             kmax=15.938,
                             kw=(2, 1, 3),
                             dk=1,
                             window='hanning',
                             rmin=1.5,
                             rmax=4.2,
                             _larch=self._larch)
    dset = feffit_dataset(data=data,
                          pathlist=paths,
                          transform=trans,
                          _larch=self._larch)
    fit = feffit(gds, dset, _larch=self._larch)

    if self.doplot:
        offset = 0.6 * max(dset.data.chir_mag)
        _newplot(dset.data.r,
                 dset.data.chir_mag + offset,
                 xmax=8,
                 win=2,
                 xlabel=r'$R \rm\,(\AA)$',
                 label='data',
                 ylabel=r'$|\chi(R)| \rm\,(\AA^{-3})$',
                 title='Fit to ' + self.folder,
                 show_legend=True,
                 _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_mag + offset,
              label='fit',
              win=2,
              _larch=self._larch)
        _plot(dset.data.r,
              dset.data.chir_re,
              label='data',
              win=2,
              _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_re,
              label='fit',
              win=2,
              _larch=self._larch)
    #end if

    if self.verbose:
        print feffit_report(fit, _larch=self._larch)
    #end if

    return fit
示例#6
0
def do_fit(self, which, firstshell=False, fittest='baseline'):

    if which == 'testrun':
        folder = self.testrun
    elif which == 'baseline':
        folder = self.baseline
    else:
        folder = realpath(join(self.folder, fittest, which))
    #endif

    data = read_xdi(join(self.path, 'FeS2.chik'), _larch=self._larch)

    gds = Group(amp=Parameter(1, vary=True, _larch=self._larch),
                enot=Parameter(1e-7, vary=True, _larch=self._larch),
                ss=Parameter(0.003, vary=True, _larch=self._larch),
                _larch=self._larch)

    if firstshell:
        gds.delr = Parameter(1e-7, vary=True, _larch=self._larch)
        dr1param = 'delr'
    else:
        gds.alpha = Parameter(1e-7, vary=True, _larch=self._larch)
        gds.ss2 = Parameter(0.003, vary=True, _larch=self._larch)
        gds.ss3 = Parameter(expr='ss2', _larch=self._larch)
        gds.ssfe = Parameter(0.003, vary=True, _larch=self._larch)
        dr1param = 'alpha*reff'

    paths = list()
    paths.append(
        feffpath(
            realpath(join(folder, "feff0001.dat")),  # 1st shell S SS
            s02='amp',
            e0='enot',
            sigma2='ss',
            deltar=dr1param,
            _larch=self._larch))
    if not firstshell:
        paths.append(
            feffpath(
                realpath(join(folder, "feff0002.dat")),  # 2nd shell S SS
                s02='amp',
                e0='enot',
                sigma2='ss2',
                deltar='alpha*reff',
                _larch=self._larch))
        paths.append(
            feffpath(
                realpath(join(folder, "feff0003.dat")),  # 3rd shell S SS
                s02='amp',
                e0='enot',
                sigma2='ss3',
                deltar='alpha*reff',
                _larch=self._larch))
        paths.append(
            feffpath(
                realpath(join(folder, "feff0004.dat")),  # 4th shell Fe SS
                s02='amp',
                e0='enot',
                sigma2='ssfe',
                deltar='alpha*reff',
                _larch=self._larch))
        paths.append(
            feffpath(
                realpath(join(folder, "feff0005.dat")),  # S-S triangle
                s02='amp',
                e0='enot',
                sigma2='ss*1.5',
                deltar='alpha*reff',
                _larch=self._larch))
        paths.append(
            feffpath(
                realpath(join(folder, "feff0006.dat")),  # S-Fe triangle
                s02='amp',
                e0='enot',
                sigma2='ss/2+ssfe',
                deltar='alpha*reff',
                _larch=self._larch))
        paths.append(
            feffpath(
                realpath(join(folder,
                              "feff0012.dat")),  # S-S non-forward linear
                s02='amp',
                e0='enot',
                sigma2='ss*2',
                deltar='alpha*reff',
                _larch=self._larch))
        paths.append(
            feffpath(
                realpath(join(folder,
                              "feff0013.dat")),  # S-S forward scattering
                s02='amp',
                e0='enot',
                sigma2='ss*2',
                deltar='alpha*reff',
                _larch=self._larch))
        paths.append(
            feffpath(
                realpath(join(folder, "feff0014.dat")),  # S-S rattle
                s02='amp',
                e0='enot',
                sigma2='ss*4',
                deltar='alpha*reff',
                _larch=self._larch))

    rx = 4.2
    if firstshell: rx = 2.3

    trans = feffit_transform(kmin=3,
                             kmax=12.956,
                             kw=(2, 1, 3),
                             dk=1,
                             window='hanning',
                             rmin=1.2,
                             rmax=rx,
                             _larch=self._larch)
    dset = feffit_dataset(data=data,
                          pathlist=paths,
                          transform=trans,
                          _larch=self._larch)
    fit = feffit(gds, dset, _larch=self._larch)

    if self.doplot:
        offset = 0.6 * max(dset.data.chir_mag)
        _newplot(dset.data.r,
                 dset.data.chir_mag + offset,
                 xmax=8,
                 xlabel=r'$R \rm\,(\AA)$',
                 label='data',
                 ylabel=r'$|\chi(R)| \rm\,(\AA^{-3})$',
                 title='Fit to ' + self.folder,
                 show_legend=True,
                 _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_mag + offset,
              label='fit',
              _larch=self._larch)
        _plot(dset.data.r, dset.data.chir_re, label='data', _larch=self._larch)
        _plot(dset.model.r,
              dset.model.chir_re,
              label='fit',
              _larch=self._larch)
    #end if

    if self.verbose:
        print feffit_report(fit, _larch=self._larch)
    #end if

    shells = ''
    if firstshell: shells = '_1st'

    write_ascii(join(self.folder, fittest, "fit_" + which + shells + ".k"),
                dset.data.k,
                dset.data.chi,
                dset.model.chi,
                labels="r data_mag fit_mag data_re fit_re",
                _larch=self._larch)
    write_ascii(join(self.folder, fittest, "fit_" + which + shells + ".r"),
                dset.data.r,
                dset.data.chir_mag,
                dset.model.chir_mag,
                dset.data.chir_re,
                dset.model.chir_re,
                labels="r data_mag fit_mag data_re fit_re",
                _larch=self._larch)

    renderer = pystache.Renderer()
    with open(join(self.folder, fittest, 'fit_' + which + shells + '.gp'),
              'w') as inp:
        inp.write(
            renderer.render_path(
                'plot.mustache',  # gnuplot mustache file
                {
                    'material': 'FeS2',
                    'model': which,
                    'fittest': fittest,
                    'shells': shells,
                    'kmin': 3,
                    'kmax': 12.956,
                    'rmin': 1.2,
                    'rmax': rx,
                    'offset': 1,
                }))

    return fit
示例#7
0
def autobk(energy, mu, group=None, rbkg=1, nknots=None, e0=None,
           edge_step=None, kmin=0, kmax=None, kweight=1, dk=0,
           win='hanning', k_std=None, chi_std=None, nfft=2048, kstep=0.05,
           pre_edge_kws=None, debug=False, _larch=None, **kws):

    """Use Autobk algorithm to remove XAFS background
    Options are:
      rbkg -- distance out to which the chi(R) is minimized
    """
    if _larch is None:
        raise Warning("cannot calculate autobk spline -- larch broken?")

    if 'kw' in kws:
        kweight = kws['kw']

    energy = remove_dups(energy)

    # if e0 or edge_step are not specified, get them, either from the
    # passed-in group or from running pre_edge()
    if edge_step is None:
        if _larch.symtable.isgroup(group) and hasattr(group, 'edge_step'):
            edge_step = group.edge_step
    if e0 is None:
        if _larch.symtable.isgroup(group) and hasattr(group, 'e0'):
            e0 = group.e0
    if e0 is None or edge_step is None:
        # need to run pre_edge:
        pre_kws = dict(nnorm=3, nvict=0, pre1=None,
                       pre2=-50., norm1=100., norm2=None)
        if pre_edge_kws is not None:
            pre_kws.update(pre_edge_kws)
        edge_step, e0 = pre_edge(energy, mu, group=group,
                                 _larch=_larch, **pre_kws)

    # get array indices for rkbg and e0: irbkg, ie0
    ie0 = index_nearest(energy, e0)
    rgrid = np.pi/(kstep*nfft)
    if rbkg < 2*rgrid: rbkg = 2*rgrid
    irbkg = int(1.01 + rbkg/rgrid)

    # save ungridded k (kraw) and grided k (kout)
    # and ftwin (*k-weighting) for FT in residual
    kraw = np.sqrt(ETOK*(energy[ie0:] - e0))
    if kmax is None:
        kmax = max(kraw)
    kout  = kstep * np.arange(int(1.01+kmax/kstep), dtype='float64')

    # interpolate provided chi(k) onto the kout grid
    if chi_std is not None and k_std is not None:
        chi_std = np.interp(kout, k_std, chi_std)

    ftwin = kout**kweight * ftwindow(kout, xmin=kmin, xmax=kmax,
                                     window=win, dx=dk)

    # calc k-value and initial guess for y-values of spline params
    nspline = max(4, min(60, 2*int(rbkg*(kmax-kmin)/np.pi) + 1))
    spl_y  = np.zeros(nspline)
    spl_k  = np.zeros(nspline)
    spl_e  = np.zeros(nspline)
    for i in range(nspline):
        q = kmin + i*(kmax-kmin)/(nspline - 1)
        ik = index_nearest(kraw, q)

        i1 = min(len(kraw)-1, ik + 5)
        i2 = max(0, ik - 5)
        spl_k[i] = kraw[ik]
        spl_e[i] = energy[ik+ie0]
        spl_y[i] = (2*mu[ik+ie0] + mu[i1+ie0] + mu[i2+ie0] ) / 4.0

    # get spline represention: knots, coefs, order=3
    # coefs will be varied in fit.
    knots, coefs, order = splrep(spl_k, spl_y)

    # set fit parameters from initial coefficients
    ncoefs = len(coefs)
    params = Group()
    for i in range(ncoefs):
        name = FMT_COEF % i
        p = Parameter(coefs[i], name=name, vary=i<len(spl_y))
        p._getval()
        setattr(params, name, p)

    initbkg, initchi = spline_eval(kraw, mu[ie0:], knots, coefs, order, kout)

    fitkws = dict(ncoefs=len(coefs), chi_std=chi_std,
                  knots=knots, order=order, kraw=kraw, mu=mu[ie0:],
                  irbkg=irbkg, kout=kout, ftwin=ftwin, nfft=nfft)
    # do fit
    fit = Minimizer(__resid, params, fcn_kws=fitkws, _larch=_larch, toler=1.e-4)
    fit.leastsq()

    # write final results
    coefs = [getattr(params, FMT_COEF % i) for i in range(ncoefs)]

    bkg, chi = spline_eval(kraw, mu[ie0:], knots, coefs, order, kout)
    obkg  = np.zeros(len(mu))
    obkg[:ie0] = mu[:ie0]
    obkg[ie0:] = bkg
    if _larch.symtable.isgroup(group):
        group.bkg  = obkg
        group.chie = (mu-obkg)/edge_step
        group.k    = kout
        group.chi  = chi/edge_step
        if debug:
            group.spline_params = params
            ix_bkg = np.zeros(len(mu))
            ix_bkg[:ie0] = mu[:ie0]
            ix_bkg[ie0:] = initbkg
            group.init_bkg = ix_bkg
            group.init_chi = initchi/edge_step
            group.spline_e = spl_e
            group.spline_y = np.array([coefs[i] for i in range(nspline)])
            group.spline_yinit = spl_y
示例#8
0
def autobk(energy, mu=None, group=None, rbkg=1, nknots=None, e0=None,
           edge_step=None, kmin=0, kmax=None, kweight=1, dk=0,
           win='hanning', k_std=None, chi_std=None, nfft=2048, kstep=0.05,
           pre_edge_kws=None, nclamp=4, clamp_lo=1, clamp_hi=1,
           calc_uncertainties=True, err_sigma=1, _larch=None, **kws):
    """Use Autobk algorithm to remove XAFS background

    Parameters:
    -----------
      energy:    1-d array of x-ray energies, in eV, or group
      mu:        1-d array of mu(E)
      group:     output group (and input group for e0 and edge_step).
      rbkg:      distance (in Ang) for chi(R) above
                 which the signal is ignored. Default = 1.
      e0:        edge energy, in eV.  If None, it will be determined.
      edge_step: edge step.  If None, it will be determined.
      pre_edge_kws:  keyword arguments to pass to pre_edge()
      nknots:    number of knots in spline.  If None, it will be determined.
      kmin:      minimum k value   [0]
      kmax:      maximum k value   [full data range].
      kweight:   k weight for FFT.  [1]
      dk:        FFT window window parameter.  [0]
      win:       FFT window function name.     ['hanning']
      nfft:      array size to use for FFT [2048]
      kstep:     k step size to use for FFT [0.05]
      k_std:     optional k array for standard chi(k).
      chi_std:   optional chi array for standard chi(k).
      nclamp:    number of energy end-points for clamp [2]
      clamp_lo:  weight of low-energy clamp [1]
      clamp_hi:  weight of high-energy clamp [1]
      calc_uncertaintites:  Flag to calculate uncertainties in
                            mu_0(E) and chi(k) [True]
      err_sigma: sigma level for uncertainties in mu_0(E) and chi(k) [1]

    Output arrays are written to the provided group.

    Follows the 'First Argument Group' convention.
    """
    msg = _larch.writer.write
    if 'kw' in kws:
        kweight = kws.pop('kw')
    if len(kws) > 0:
        msg('Unrecognized a:rguments for autobk():\n')
        msg('    %s\n' % (', '.join(kws.keys())))
        return
    energy, mu, group = parse_group_args(energy, members=('energy', 'mu'),
                                         defaults=(mu,), group=group,
                                         fcn_name='autobk')
    if len(energy.shape) > 1:
        energy = energy.squeeze()
    if len(mu.shape) > 1:
        mu = mu.squeeze()

    energy = remove_dups(energy)
    # if e0 or edge_step are not specified, get them, either from the
    # passed-in group or from running pre_edge()
    group = set_xafsGroup(group, _larch=_larch)

    if edge_step is None and isgroup(group, 'edge_step'):
        edge_step = group.edge_step
    if e0 is None and isgroup(group, 'e0'):
        e0 = group.e0
    if e0 is None or edge_step is None:
        # need to run pre_edge:
        pre_kws = dict(nnorm=3, nvict=0, pre1=None,
                       pre2=-50., norm1=100., norm2=None)
        if pre_edge_kws is not None:
            pre_kws.update(pre_edge_kws)
        pre_edge(energy, mu, group=group, _larch=_larch, **pre_kws)
        if e0 is None:
            e0 = group.e0
        if edge_step is None:
            edge_step = group.edge_step
    if e0 is None or edge_step is None:
        msg('autobk() could not determine e0 or edge_step!: trying running pre_edge first\n')
        return

    # get array indices for rkbg and e0: irbkg, ie0
    ie0 = index_of(energy, e0)
    rgrid = np.pi/(kstep*nfft)
    if rbkg < 2*rgrid: rbkg = 2*rgrid
    irbkg = int(1.01 + rbkg/rgrid)

    # save ungridded k (kraw) and grided k (kout)
    # and ftwin (*k-weighting) for FT in residual
    enpe = energy[ie0:] - e0
    kraw = np.sign(enpe)*np.sqrt(ETOK*abs(enpe))
    if kmax is None:
        kmax = max(kraw)
    else:
        kmax = max(0, min(max(kraw), kmax))
    kout  = kstep * np.arange(int(1.01+kmax/kstep), dtype='float64')
    iemax = min(len(energy), 2+index_of(energy, e0+kmax*kmax/ETOK)) - 1

    # interpolate provided chi(k) onto the kout grid
    if chi_std is not None and k_std is not None:
        chi_std = np.interp(kout, k_std, chi_std)
    # pre-load FT window
    ftwin = kout**kweight * ftwindow(kout, xmin=kmin, xmax=kmax,
                                     window=win, dx=dk)
    # calc k-value and initial guess for y-values of spline params
    nspl = max(4, min(128, 2*int(rbkg*(kmax-kmin)/np.pi) + 1))
    spl_y, spl_k, spl_e  = np.zeros(nspl), np.zeros(nspl), np.zeros(nspl)
    for i in range(nspl):
        q  = kmin + i*(kmax-kmin)/(nspl - 1)
        ik = index_nearest(kraw, q)
        i1 = min(len(kraw)-1, ik + 5)
        i2 = max(0, ik - 5)
        spl_k[i] = kraw[ik]
        spl_e[i] = energy[ik+ie0]
        spl_y[i] = (2*mu[ik+ie0] + mu[i1+ie0] + mu[i2+ie0] ) / 4.0

    # get spline represention: knots, coefs, order=3
    # coefs will be varied in fit.
    knots, coefs, order = splrep(spl_k, spl_y)

    # set fit parameters from initial coefficients
    params = Group()
    for i in range(len(coefs)):
        name = FMT_COEF % i
        p = Parameter(coefs[i], name=name, vary=i<len(spl_y))
        p._getval()
        setattr(params, name, p)

    initbkg, initchi = spline_eval(kraw[:iemax-ie0+1], mu[ie0:iemax+1],
                                   knots, coefs, order, kout)

    # do fit
    fit = Minimizer(__resid, params, _larch=_larch, toler=1.e-4,
                    fcn_kws = dict(ncoefs=len(coefs), chi_std=chi_std,
                                   knots=knots, order=order,
                                   kraw=kraw[:iemax-ie0+1],
                                   mu=mu[ie0:iemax+1], irbkg=irbkg, kout=kout,
                                   ftwin=ftwin, kweight=kweight,
                                   nfft=nfft, nclamp=nclamp,
                                   clamp_lo=clamp_lo, clamp_hi=clamp_hi))
    fit.leastsq()

    # write final results
    coefs = [getattr(params, FMT_COEF % i) for i in range(len(coefs))]
    bkg, chi = spline_eval(kraw[:iemax-ie0+1], mu[ie0:iemax+1],
                           knots, coefs, order, kout)
    obkg = np.copy(mu)
    obkg[ie0:ie0+len(bkg)] = bkg

    # outputs to group
    group = set_xafsGroup(group, _larch=_larch)
    group.bkg  = obkg
    group.chie = (mu-obkg)/edge_step
    group.k    = kout
    group.chi  = chi/edge_step

    # now fill in 'autobk_details' group
    params.init_bkg = np.copy(mu)
    params.init_bkg[ie0:ie0+len(bkg)] = initbkg
    params.init_chi = initchi/edge_step
    params.knots_e  = spl_e
    params.knots_y  = np.array([coefs[i] for i in range(nspl)])
    params.init_knots_y = spl_y
    params.nfev = params.fit_details.nfev
    params.kmin = kmin
    params.kmax = kmax
    group.autobk_details = params

    # uncertainties in mu0 and chi: can be fairly slow.
    if calc_uncertainties:
        nchi = len(chi)
        nmue = iemax-ie0 + 1
        redchi = params.chi_reduced
        covar = params.covar / redchi
        jac_chi = np.zeros(nchi*nspl).reshape((nspl, nchi))
        jac_bkg = np.zeros(nmue*nspl).reshape((nspl, nmue))

        cvals, cerrs = [], []
        for i in range(len(coefs)):
             par = getattr(params, FMT_COEF % i)
             cvals.append(getattr(par, 'value', 0.0))
             cdel = getattr(par, 'stderr', 0.0)
             if cdel is None:
                 cdel = 0.0
             cerrs.append(cdel/2.0)
        cvals = np.array(cvals)
        cerrs = np.array(cerrs)

        # find derivatives by hand!
        _k = kraw[:nmue]
        _m = mu[ie0:iemax+1]
        for i in range(nspl):
            cval0 = cvals[i]
            cvals[i] = cval0 + cerrs[i]
            bkg1, chi1 = spline_eval(_k, _m, knots, cvals, order, kout)

            cvals[i] = cval0 - cerrs[i]
            bkg2, chi2 = spline_eval(_k, _m, knots, cvals, order, kout)

            cvals[i] = cval0
            jac_chi[i] = (chi1 - chi2) / (2*cerrs[i])
            jac_bkg[i] = (bkg1 - bkg2) / (2*cerrs[i])

        dfchi = np.zeros(nchi)
        dfbkg = np.zeros(nmue)
        for i in range(nspl):
            for j in range(nspl):
                dfchi += jac_chi[i]*jac_chi[j]*covar[i,j]
                dfbkg += jac_bkg[i]*jac_bkg[j]*covar[i,j]

        prob = 0.5*(1.0 + erf(err_sigma/np.sqrt(2.0)))
        dchi = t.ppf(prob, nchi-nspl) * np.sqrt(dfchi*redchi)
        dbkg = t.ppf(prob, nmue-nspl) * np.sqrt(dfbkg*redchi)

        group.delta_chi = dchi
        group.delta_bkg = 0.0*mu
        group.delta_bkg[ie0:ie0+len(dbkg)] = dbkg