Esempio n. 1
0
 def from_lm_params(cls, params: lm.Parameters) -> NRGParams:
     d = {}
     for k1, k2 in zip(
         ['gamma', 'theta', 'center', 'amp', 'lin', 'const', 'lin_occ'],
         ['g', 'theta', 'mid', 'amp', 'lin', 'const', 'occ_lin']):
         par = params.get(k2, None)
         if par is not None:
             v = par.value
         elif k1 == 'gamma':
             v = 0  # This will cause issues if not set somewhere else, but no better choice here.
         else:
             v = 0 if k1 != 'amp' else 1  # Most things should default to zero except for amp
         d[k1] = v
     return cls(**d)
Esempio n. 2
0
class FeffPathGroup(Group):
    def __init__(self,
                 filename=None,
                 label=None,
                 s02=None,
                 degen=None,
                 e0=None,
                 ei=None,
                 deltar=None,
                 sigma2=None,
                 third=None,
                 fourth=None,
                 _larch=None,
                 **kws):

        kwargs = dict(name='FeffPath: %s' % filename)
        kwargs.update(kws)
        Group.__init__(self, **kwargs)
        self.filename = filename
        self.params = None
        self.label = label
        self.spline_coefs = None
        def_degen = 1

        self._feffdat = None
        if filename is not None:
            self._feffdat = FeffDatFile(filename=filename)
            self.geom = self._feffdat.geom
            def_degen = self._feffdat.degen
            if self.label is None:
                self.label = self.__geom2label()

        self.degen = def_degen if degen is None else degen
        self.s02 = 1.0 if s02 is None else s02
        self.e0 = 0.0 if e0 is None else e0
        self.ei = 0.0 if ei is None else ei
        self.deltar = 0.0 if deltar is None else deltar
        self.sigma2 = 0.0 if sigma2 is None else sigma2
        self.third = 0.0 if third is None else third
        self.fourth = 0.0 if fourth is None else fourth

        self.k = None
        self.chi = None
        if self._feffdat is not None:
            self.create_spline_coefs()

    def __geom2label(self):
        """generate label by hashing path geometry"""
        rep = []
        if self.geom is not None:
            for atom in self.geom:
                rep.extend(atom)
        if self._feffdat is not None:
            rep.append(self._feffdat.degen)
            rep.append(self._feffdat.reff)

        for attr in ('s02', 'e0', 'ei', 'deltar', 'sigma2', 'third', 'fourth'):
            rep.append(getattr(self, attr, '_'))
        s = "|".join([str(i) for i in rep])
        return "p%s" % (b32hash(s)[:8].lower())

    def __copy__(self):
        return FeffPathGroup(filename=self.filename,
                             s02=self.s02,
                             degen=self.degen,
                             e0=self.e0,
                             ei=self.ei,
                             deltar=self.deltar,
                             sigma2=self.sigma2,
                             third=self.third,
                             fourth=self.fourth)

    def __deepcopy__(self, memo):
        return FeffPathGroup(filename=self.filename,
                             s02=self.s02,
                             degen=self.degen,
                             e0=self.e0,
                             ei=self.ei,
                             deltar=self.deltar,
                             sigma2=self.sigma2,
                             third=self.third,
                             fourth=self.fourth)

    @property
    def reff(self):
        return self._feffdat.reff

    @reff.setter
    def reff(self, val):
        pass

    @property
    def nleg(self):
        return self._feffdat.nleg

    @nleg.setter
    def nleg(self, val):
        pass

    @property
    def rmass(self):
        return self._feffdat.rmass

    @rmass.setter
    def rmass(self, val):
        pass

    def __repr__(self):
        if self.filename is not None:
            return '<FeffPath Group %s>' % self.filename
        return '<FeffPath Group (empty)>'

    def create_path_params(self, params=None):
        """
        create Path Parameters within the current lmfit.Parameters namespace
        """
        if params is not None:
            self.params = params
        if self.params is None:
            self.params = Parameters()
        if self.params._asteval.symtable.get('sigma2_debye', None) is None:
            add_sigma2funcs(self.params)
        if self.label is None:
            self.label = self.__geom2label()
        self.store_feffdat()
        for pname in PATH_PARS:
            val = getattr(self, pname)
            attr = 'value'
            if isinstance(val, str):
                attr = 'expr'
            kws = {'vary': False, attr: val}
            parname = fix_varname(PATHPAR_FMT % (pname, self.label))
            self.params.add(parname, **kws)

    def create_spline_coefs(self):
        """pre-calculate spline coefficients for feff data"""
        self.spline_coefs = {}
        fdat = self._feffdat
        self.spline_coefs['pha'] = UnivariateSpline(fdat.k, fdat.pha, s=0)
        self.spline_coefs['amp'] = UnivariateSpline(fdat.k, fdat.amp, s=0)
        self.spline_coefs['rep'] = UnivariateSpline(fdat.k, fdat.rep, s=0)
        self.spline_coefs['lam'] = UnivariateSpline(fdat.k, fdat.lam, s=0)

    def store_feffdat(self):
        """stores data about this Feff path in the Parameters
        symbol table for use as `reff` and in sigma2 calcs
        """
        symtab = self.params._asteval.symtable
        symtab['feffpath'] = self._feffdat
        symtab['reff'] = self._feffdat.reff

    def __path_params(self, **kws):
        """evaluate path parameter value.  Returns
        (degen, s02, e0, ei, deltar, sigma2, third, fourth)
        """
        # put 'reff' and '_feffdat' into the symboltable so that
        # they can be used in constraint expressions
        self.store_feffdat()
        if self.params is None:
            self.create_path_params()
        out = []
        for pname in PATH_PARS:
            val = kws.get(pname, None)
            parname = fix_varname(PATHPAR_FMT % (pname, self.label))
            if val is None:
                val = self.params[parname]._getval()
            out.append(val)
        return out

    def path_paramvals(self, **kws):
        (deg, s02, e0, ei, delr, ss2, c3, c4) = self.__path_params()
        return dict(degen=deg,
                    s02=s02,
                    e0=e0,
                    ei=ei,
                    deltar=delr,
                    sigma2=ss2,
                    third=c3,
                    fourth=c4)

    def report(self):
        "return  text report of parameters"
        tmpvals = self.__path_params()
        pathpars = {}
        for pname in ('degen', 's02', 'e0', 'deltar', 'sigma2', 'third',
                      'fourth', 'ei'):
            parname = fix_varname(PATHPAR_FMT % (pname, self.label))
            if parname in self.params:
                pathpars[pname] = (self.params[parname].value,
                                   self.params[parname].stderr)

        geomlabel = '     atom      x        y        z       ipot'
        geomformat = '    %4s      % .4f, % .4f, % .4f  %i'
        out = ['   Path %s, Feff.dat file = %s' % (self.label, self.filename)]
        out.append(geomlabel)

        for atsym, iz, ipot, amass, x, y, z in self.geom:
            s = geomformat % (atsym, x, y, z, ipot)
            if ipot == 0: s = "%s (absorber)" % s
            out.append(s)

        stderrs = {}
        out.append('     {:7s}= {:s}'.format('reff',
                                             gformat(self._feffdat.reff)))

        for pname in ('degen', 's02', 'e0', 'r', 'deltar', 'sigma2', 'third',
                      'fourth', 'ei'):
            val = strval = getattr(self, pname, 0)
            parname = fix_varname(PATHPAR_FMT % (pname, self.label))
            std = None
            if pname == 'r':
                parname = fix_varname(PATHPAR_FMT % ('deltar', self.label))
                par = self.params.get(parname, None)
                val = par.value + self._feffdat.reff
                strval = 'reff + ' + getattr(self, 'deltar', 0)
                std = par.stderr
            else:
                if pname in pathpars:
                    val, std = pathpars[pname]
                else:
                    par = self.params.get(parname, None)
                    if par is not None:
                        val = par.value
                        std = par.stderr

            if std is None or std <= 0:
                svalue = gformat(val)
            else:
                svalue = "{:s} +/-{:s}".format(gformat(val), gformat(std))
            if pname == 's02':
                pname = 'n*s02'

            svalue = "     {:7s}= {:s}".format(pname, svalue)
            if isinstance(strval, str):
                svalue = "{:s}  '{:s}'".format(svalue, strval)

            if val == 0 and pname in ('third', 'fourth', 'ei'):
                continue
            out.append(svalue)
        return '\n'.join(out)

    def _calc_chi(self,
                  k=None,
                  kmax=None,
                  kstep=None,
                  degen=None,
                  s02=None,
                  e0=None,
                  ei=None,
                  deltar=None,
                  sigma2=None,
                  third=None,
                  fourth=None,
                  debug=False,
                  interp='cubic',
                  **kws):
        """calculate chi(k) with the provided parameters"""
        fdat = self._feffdat
        if fdat.reff < 0.05:
            print('reff is too small to calculate chi(k)')
            return
        # make sure we have a k array
        if k is None:
            if kmax is None:
                kmax = 30.0
            kmax = min(max(fdat.k), kmax)
            if kstep is None: kstep = 0.05
            k = kstep * np.arange(int(1.01 + kmax / kstep), dtype='float64')

        reff = fdat.reff
        # get values for all the path parameters
        (degen, s02, e0, ei, deltar, sigma2, third, fourth)  = \
                self.__path_params(degen=degen, s02=s02, e0=e0, ei=ei,
                                 deltar=deltar, sigma2=sigma2,
                                 third=third, fourth=fourth)

        # create e0-shifted energy and k, careful to look for |e0| ~= 0.
        en = k * k - e0 * ETOK
        if min(abs(en)) < SMALL:
            try:
                en[np.where(abs(en) < 2 * SMALL)] = SMALL
            except ValueError:
                pass
        # q is the e0-shifted wavenumber
        q = np.sign(en) * np.sqrt(abs(en))

        # lookup Feff.dat values (pha, amp, rep, lam)
        if interp.startswith('lin'):
            pha = np.interp(q, fdat.k, fdat.pha)
            amp = np.interp(q, fdat.k, fdat.amp)
            rep = np.interp(q, fdat.k, fdat.rep)
            lam = np.interp(q, fdat.k, fdat.lam)
        else:
            pha = self.spline_coefs['pha'](q)
            amp = self.spline_coefs['amp'](q)
            rep = self.spline_coefs['rep'](q)
            lam = self.spline_coefs['lam'](q)

        if debug:
            self.debug_k = q
            self.debug_pha = pha
            self.debug_amp = amp
            self.debug_rep = rep
            self.debug_lam = lam

        # p = complex wavenumber, and its square:
        pp = (rep + 1j / lam)**2 + 1j * ei * ETOK
        p = np.sqrt(pp)

        # the xafs equation:
        cchi = np.exp(-2 * reff * p.imag - 2 * pp *
                      (sigma2 - pp * fourth / 3) + 1j *
                      (2 * q * reff + pha + 2 * p *
                       (deltar - 2 * sigma2 / reff - 2 * pp * third / 3)))

        cchi = degen * s02 * amp * cchi / (q * (reff + deltar)**2)
        cchi[0] = 2 * cchi[1] - cchi[2]
        # outputs:
        self.k = k
        self.p = p
        self.chi = cchi.imag
        self.chi_imag = -cchi.real
Esempio n. 3
0
class FeffPathGroup(Group):
    def __init__(self, filename=None, _larch=None,
                 label=None, s02=None, degen=None, e0=None,
                 ei=None, deltar=None, sigma2=None,
                 third=None, fourth=None,  **kws):

        kwargs = dict(name='FeffPath: %s' % filename)
        kwargs.update(kws)
        Group.__init__(self, **kwargs)
        self._larch = _larch
        self.filename = filename
        self.params = None
        self.label = label
        self.spline_coefs = None
        def_degen = 1

        self._feffdat = None
        if filename is not None:
            self._feffdat = FeffDatFile(filename=filename, _larch=_larch)
            self.geom  = self._feffdat.geom
            def_degen  = self._feffdat.degen
            if self.label is None:
                self.label = self.__geom2label()

        self.degen = def_degen if degen  is None else degen
        self.s02    = 1.0      if s02    is None else s02
        self.e0     = 0.0      if e0     is None else e0
        self.ei     = 0.0      if ei     is None else ei
        self.deltar = 0.0      if deltar is None else deltar
        self.sigma2 = 0.0      if sigma2 is None else sigma2
        self.third  = 0.0      if third  is None else third
        self.fourth = 0.0      if fourth is None else fourth

        self.k = None
        self.chi = None
        if self._feffdat is not None:
            self.create_spline_coefs()

    def __geom2label(self):
        """generate label by hashing path geometry"""
        rep = []
        if self.geom is not None:
            for atom in self.geom:
                rep.extend(atom)
        if self._feffdat is not None:
            rep.append(self._feffdat.degen)
            rep.append(self._feffdat.reff)

        for attr in ('s02', 'e0', 'ei', 'deltar', 'sigma2', 'third', 'fourth'):
            rep.append(getattr(self, attr, '_'))
        s = "|".join([str(i) for i in rep])
        return "p%s" % (b32hash(s)[:8].lower())

    def __copy__(self):
        return FeffPathGroup(filename=self.filename, _larch=self._larch,
                             s02=self.s02, degen=self.degen, e0=self.e0,
                             ei=self.ei, deltar=self.deltar, sigma2=self.sigma2,
                             third=self.third, fourth=self.fourth)

    def __deepcopy__(self, memo):
        return FeffPathGroup(filename=self.filename, _larch=self._larch,
                             s02=self.s02, degen=self.degen, e0=self.e0,
                             ei=self.ei, deltar=self.deltar, sigma2=self.sigma2,
                             third=self.third, fourth=self.fourth)

    @property
    def reff(self): return self._feffdat.reff

    @reff.setter
    def reff(self, val):  pass

    @property
    def nleg(self): return self._feffdat.nleg

    @nleg.setter
    def nleg(self, val):     pass

    @property
    def rmass(self): return self._feffdat.rmass

    @rmass.setter
    def rmass(self, val):  pass

    def __repr__(self):
        if self.filename is not None:
            return '<FeffPath Group %s>' % self.filename
        return '<FeffPath Group (empty)>'

    def create_path_params(self):
        """
        create Path Parameters within the current fiteval
        """
        self.params = Parameters(asteval=self._larch.symtable._sys.fiteval)
        if self.label is None:
            self.label = self.__geom2label()

        self.store_feffdat()

        for pname in PATH_PARS:
            val =  getattr(self, pname)
            attr = 'value'
            if isinstance(val, six.string_types):
                attr = 'expr'
            kws =  {'vary': False, attr: val}
            parname = fix_varname(PATHPAR_FMT % (pname, self.label))
            self.params.add(parname, **kws)

    def create_spline_coefs(self):
        """pre-calculate spline coefficients for feff data"""
        self.spline_coefs = {}
        fdat = self._feffdat
        self.spline_coefs['pha'] = UnivariateSpline(fdat.k, fdat.pha, s=0)
        self.spline_coefs['amp'] = UnivariateSpline(fdat.k, fdat.amp, s=0)
        self.spline_coefs['rep'] = UnivariateSpline(fdat.k, fdat.rep, s=0)
        self.spline_coefs['lam'] = UnivariateSpline(fdat.k, fdat.lam, s=0)

    def store_feffdat(self):
        """stores data about this Feff path in the fiteval
        symbol table for use as `reff` and in sigma2 calcs
        """
        fiteval = self._larch.symtable._sys.fiteval
        fdat = self._feffdat
        fiteval.symtable['feffpath'] = fdat
        fiteval.symtable['reff']  = fdat.reff
        return fiteval

    def __path_params(self, **kws):
        """evaluate path parameter value.  Returns
        (degen, s02, e0, ei, deltar, sigma2, third, fourth)
        """
        # put 'reff' and '_feffdat' into the symboltable so that
        # they can be used in constraint expressions, and get
        # fiteval evaluator
        self.store_feffdat()

        if self.params is None:
            self.create_path_params()
        out = []
        for pname in PATH_PARS:
            val = kws.get(pname, None)
            parname = fix_varname(PATHPAR_FMT % (pname, self.label))
            if val is None:
                val = self.params[parname]._getval()
            out.append(val)
        return out

    def path_paramvals(self, **kws):
        (deg, s02, e0, ei, delr, ss2, c3, c4) = self.__path_params()
        return dict(degen=deg, s02=s02, e0=e0, ei=ei, deltar=delr,
                    sigma2=ss2, third=c3, fourth=c4)


    def report(self):
        "return  text report of parameters"
        (deg, s02, e0, ei, delr, ss2, c3, c4) = self.__path_params()
        geomlabel  = '     atom      x        y        z       ipot'
        geomformat = '    %4s      % .4f, % .4f, % .4f  %i'
        out = ['   Path %s, Feff.dat file = %s' % (self.label, self.filename)]
        out.append(geomlabel)

        for atsym, iz, ipot, amass, x, y, z in self.geom:
            s = geomformat % (atsym, x, y, z, ipot)
            if ipot == 0: s = "%s (absorber)" % s
            out.append(s)

        stderrs = {}
        out.append('     {:7s}=  {:.5f}'.format('reff', self._feffdat.reff))

        for pname in ('degen', 's02', 'e0', 'r',
                      'deltar', 'sigma2', 'third', 'fourth', 'ei'):
            val = strval = getattr(self, pname, 0)
            parname = fix_varname(PATHPAR_FMT % (pname, self.label))
            std = None
            if pname == 'r':
                parname = fix_varname(PATHPAR_FMT % ('deltar', self.label))
                par = self.params.get(parname, None)
                val = par.value + self._feffdat.reff
                strval = 'reff + ' + getattr(self, 'deltar', 0)
                std = par.stderr
            else:
                par = self.params.get(parname, None)
                if par is not None:
                    val = par.value
                    std = par.stderr
            if std is None  or std <= 0:
                svalue = "{: 5f}".format(val)
            else:
                svalue = "{: 5f} +/- {:5f}".format(val, std)
            if pname == 's02': pname = 'n*s02'

            svalue = "     {:7s}= {:s}".format(pname, svalue)
            if isinstance(strval, six.string_types):
                svalue = "{:s}  '{:s}'".format(svalue, strval)

            if val == 0 and pname in ('third', 'fourth', 'ei'):
                continue
            out.append(svalue)
        return '\n'.join(out)


    def _calc_chi(self, k=None, kmax=None, kstep=None, degen=None, s02=None,
                 e0=None, ei=None, deltar=None, sigma2=None,
                 third=None, fourth=None, debug=False, interp='cubic', **kws):
        """calculate chi(k) with the provided parameters"""
        fdat = self._feffdat
        if fdat.reff < 0.05:
            self._larch.writer.write('reff is too small to calculate chi(k)')
            return
        # make sure we have a k array
        if k is None:
            if kmax is None:
                kmax = 30.0
            kmax = min(max(fdat.k), kmax)
            if kstep is None: kstep = 0.05
            k = kstep * np.arange(int(1.01 + kmax/kstep), dtype='float64')

        reff = fdat.reff
        # get values for all the path parameters
        (degen, s02, e0, ei, deltar, sigma2, third, fourth)  = \
                self.__path_params(degen=degen, s02=s02, e0=e0, ei=ei,
                                 deltar=deltar, sigma2=sigma2,
                                 third=third, fourth=fourth)

        # create e0-shifted energy and k, careful to look for |e0| ~= 0.
        en = k*k - e0*ETOK
        if min(abs(en)) < SMALL:
            try:
                en[np.where(abs(en) < 2*SMALL)] = SMALL
            except ValueError:
                pass
        # q is the e0-shifted wavenumber
        q = np.sign(en)*np.sqrt(abs(en))

        # lookup Feff.dat values (pha, amp, rep, lam)
        if interp.startswith('lin'):
            pha = np.interp(q, fdat.k, fdat.pha)
            amp = np.interp(q, fdat.k, fdat.amp)
            rep = np.interp(q, fdat.k, fdat.rep)
            lam = np.interp(q, fdat.k, fdat.lam)
        else:
            pha = self.spline_coefs['pha'](q)
            amp = self.spline_coefs['amp'](q)
            rep = self.spline_coefs['rep'](q)
            lam = self.spline_coefs['lam'](q)

        if debug:
            self.debug_k   = q
            self.debug_pha = pha
            self.debug_amp = amp
            self.debug_rep = rep
            self.debug_lam = lam

        # p = complex wavenumber, and its square:
        pp   = (rep + 1j/lam)**2 + 1j * ei * ETOK
        p    = np.sqrt(pp)

        # the xafs equation:
        cchi = np.exp(-2*reff*p.imag - 2*pp*(sigma2 - pp*fourth/3) +
                      1j*(2*q*reff + pha +
                          2*p*(deltar - 2*sigma2/reff - 2*pp*third/3) ))

        cchi = degen * s02 * amp * cchi / (q*(reff + deltar)**2)
        cchi[0] = 2*cchi[1] - cchi[2]
        # outputs:
        self.k = k
        self.p = p
        self.chi = cchi.imag
        self.chi_imag = -cchi.real
Esempio n. 4
0
params2 = Parameters()
params2.add('alpha', value= 1,  min=0)
params2.add('power', value= 1)
result2 = minimize(fcn2min, params2, args=(x, data))

# calculate final result
final1 = data + result1.residual

final2 = data + result2.residual

# write error report
report_errors(params1)

pp = pprint.PrettyPrinter(indent=4)
pp.pprint(params1)
print params1.get('alpha')
p=params1.get('alpha')
print "standard error ", p.stderr

total= np.sum(result1.residual)

print "sum of residuals: ", total
#print "xtol: ", result1.xtol
print "reduced chi-square: ", result1.redchi
#print "asteval", result1.asteval
print "message:", result1.message
print "ier:", result1.ier
print "chisqr:", result1.chisqr
print "redchi:", result1.redchi
pp.pprint(result1)