예제 #1
0
def xas_convolve(energy, norm=None, group=None, form='lorentzian',
                   esigma=1.0, eshift=0.0, _larch=None):
    """
    convolve a normalized mu(E) spectra with a Lorentzian or Gaussian peak
    shape, degrading separation of XANES features.

    This is provided as a complement to xas_deconvolve, and to deliberately
    broaden spectra to compare with spectra measured at lower resolution.

    Arguments
    ----------
    energy:   array of x-ray energies (in eV) or XAFS data group
    norm:     array of normalized mu(E)
    group:    output group
    form:     form of deconvolution function. One of
              'lorentzian' or  'gaussian' ['lorentzian']
    esigma    energy sigma (in eV) to pass to gaussian() or lorentzian() [1.0]
    eshift    energy shift (in eV) to apply to result [0]

    Returns
    -------
    None
       The array 'conv' will be written to the output group.

    Notes
    -----
       Follows the First Argument Group convention, using group members named
       'energy' and 'norm'
    """

    energy, mu, group = parse_group_args(energy, members=('energy', 'norm'),
                                         defaults=(norm,), group=group,
                                         fcn_name='xas_convolve')
    eshift = eshift + 0.5 * esigma

    en  = remove_dups(energy)
    en  = en - en[0]
    estep = max(0.001, 0.001*int(min(en[1:]-en[:-1])*1000.0))

    npad = 1 + int(max(estep*2.01, 50*esigma)/estep)

    npts = npad  + int(max(en) / estep)

    x = np.arange(npts)*estep
    y = interp(en, mu, x, kind='cubic')

    kernel = lorentzian
    if form.lower().startswith('g'):
        kernel = gaussian

    k = kernel(x, center=0, sigma=esigma)
    ret = np.convolve(y, k, mode='full')

    out = interp(x-eshift, ret[:len(x)], en, kind='cubic')

    group = set_xafsGroup(group, _larch=_larch)
    group.conv = out / k.sum()
예제 #2
0
파일: mca.py 프로젝트: mrakitin/xraylarch
    def predict_pileup(self, scale=None):
        """
        predict pileup for a spectrum, save to 'pileup' attribute
        """
        counts = self.counts.astype(int)/1.e6
        pileup = np.convolve(counts, counts, 'full')
        en = self.energy
        ex = en[0] + np.arange(len(pileup))*(en[1] - en[0])
        if scale is None:
            npts = len(en)
            nhalf = int(npts/2) + 1
            nmost = int(7*npts/8.0) - 1
            scale = self.counts[nhalf:].sum()/ pileup[nhalf:nmost].sum()

        self.pileup = interp(ex, scale*pileup, self.energy, kind='cubic')
        self.pileup_scale = scale
예제 #3
0
def xas_deconvolve(energy,
                   norm=None,
                   group=None,
                   form='lorentzian',
                   esigma=1.0,
                   eshift=0.0,
                   smooth=True,
                   sgwindow=None,
                   sgorder=3,
                   _larch=None):
    """XAS spectral deconvolution

    de-convolve a normalized mu(E) spectra with a peak shape, enhancing the
    intensity and separation of peaks of a XANES spectrum.

    The results can be unstable, and noisy, and should be used
    with caution!

    Arguments
    ----------
    energy:   array of x-ray energies (in eV) or XAFS data group
    norm:     array of normalized mu(E)
    group:    output group
    form:     functional form of deconvolution function. One of
              'gaussian' or 'lorentzian' [default]
    esigma    energy sigma to pass to gaussian() or lorentzian()
              [in eV, default=1.0]
    eshift    energy shift to apply to result. [in eV, default=0]
    smooth    whether to smooth result with savitzky_golay method [True]
    sgwindow  window size for savitzky_golay [found from data step and esigma]
    sgorder   order for savitzky_golay [3]

    Returns
    -------
    None
       The array 'deconv' will be written to the output group.

    Notes
    -----
       Support See First Argument Group convention, requiring group
       members 'energy' and 'norm'

       Smoothing with savitzky_golay() requires a window and order.  By
       default, window = int(esigma / estep) where estep is step size for
       the gridded data, approximately the finest energy step in the data.
    """
    if _larch is None:
        raise Warning("cannot deconvolve -- larch broken?")

    energy, mu, group = parse_group_args(energy,
                                         members=('energy', 'norm'),
                                         defaults=(norm, ),
                                         group=group,
                                         fcn_name='xas_deconvolve')
    eshift = eshift + 0.5 * esigma

    en = remove_dups(energy)
    en = en - en[0]
    estep = max(0.001, 0.001 * int(min(en[1:] - en[:-1]) * 1000.0))
    npts = 1 + int(max(en) / estep)

    x = np.arange(npts) * estep
    y = interp(en, mu, x, kind='cubic', _larch=_larch)

    kernel = lorentzian
    if form.lower().startswith('g'):
        kernel = gaussian

    yext = np.concatenate((y, np.arange(len(y)) * y[-1]))
    ret, err = deconvolve(yext, kernel(x, center=0, sigma=esigma))
    nret = min(len(x), len(ret))

    ret = ret[:nret] * yext[nret - 1] / ret[nret - 1]
    if smooth:
        if sgwindow is None:
            sgwindow = int(1.0 * esigma / estep)

        sqwindow = int(sgwindow)
        if sgwindow < (sgorder + 1):
            sgwindow = sgorder + 2
        if sgwindow % 2 == 0:
            sgwindow += 1
        ret = savitzky_golay(ret, sgwindow, sgorder)

    out = interp(x + eshift, ret, en, kind='cubic', _larch=_larch)
    group = set_xafsGroup(group, _larch=_larch)
    group.deconv = out
예제 #4
0
def xas_convolve(energy,
                 norm=None,
                 group=None,
                 form='lorentzian',
                 esigma=1.0,
                 eshift=0.0,
                 _larch=None):
    """
    convolve a normalized mu(E) spectra with a Lorentzian or Gaussian peak
    shape, degrading separation of XANES features.

    This is provided as a complement to xas_deconvolve, and to deliberately
    broaden spectra to compare with spectra measured at lower resolution.

    Arguments
    ----------
    energy:   array of x-ray energies (in eV) or XAFS data group
    norm:     array of normalized mu(E)
    group:    output group
    form:     form of deconvolution function. One of
              'lorentzian' or  'gaussian' ['lorentzian']
    esigma    energy sigma (in eV) to pass to gaussian() or lorentzian() [1.0]
    eshift    energy shift (in eV) to apply to result [0]

    Returns
    -------
    None
       The array 'conv' will be written to the output group.

    Notes
    -----
       Follows the First Argument Group convention, using group members named
       'energy' and 'norm'
    """
    if _larch is None:
        raise Warning("cannot xas_convolve -- larch broken?")

    energy, mu, group = parse_group_args(energy,
                                         members=('energy', 'norm'),
                                         defaults=(norm, ),
                                         group=group,
                                         fcn_name='xas_convolve')
    eshift = eshift + 0.5 * esigma

    en = remove_dups(energy)
    en = en - en[0]
    estep = max(0.001, 0.001 * int(min(en[1:] - en[:-1]) * 1000.0))

    npad = 1 + int(max(estep * 2.01, 50 * esigma) / estep)

    npts = npad + int(max(en) / estep)

    x = np.arange(npts) * estep
    y = interp(en, mu, x, kind='cubic', _larch=_larch)

    kernel = lorentzian
    if form.lower().startswith('g'):
        kernel = gaussian

    k = kernel(x, center=0, sigma=esigma)
    ret = np.convolve(y, k, mode='full')

    out = interp(x - eshift, ret[:len(x)], en, kind='cubic', _larch=_larch)

    group = set_xafsGroup(group, _larch=_larch)
    group.conv = out / k.sum()
예제 #5
0
    def kk(self, energy=None, mu=None, z=None, edge='K', how='scalar', mback_kws=None):
        """
        Convert mu(E) data into f'(E) and f"(E).  f"(E) is made by
        matching mu(E) to the tabulated values of the imaginary part
        of the scattering factor (Cromer-Liberman), f'(E) is then
        obtained by performing a differential Kramers-Kronig transform
        on the matched f"(E).

          Attributes
            energy:     energy array
            mu:         array with mu(E) data
            z:          Z number of absorber
            edge:       absorption edge, usually 'K' or 'L3'
            mback_kws:  arguments for the mback algorithm

          Returns
            self.f1, self.f2:  CL values over on the input energy grid
            self.fp, self.fpp: matched and KK transformed data on the input energy grid

        References:
          * Cromer-Liberman: http://dx.doi.org/10.1063/1.1674266
          * KK computation: Ohta and Ishida, Applied Spectroscopy 42:6 (1988) 952-957
          * diffKK implementation: http://dx.doi.org/10.1103/PhysRevB.58.11215
          * MBACK (Weng, Waldo, Penner-Hahn): http://dx.doi.org/10.1086/303711
          * Lee and Xiang: http://dx.doi.org/10.1088/0004-637X/702/2/970

        """

        if type(energy).__name__ == 'ndarray': self.energy = energy
        if type(mu).__name__     == 'ndarray': self.mu     = mu
        if z    != None: self.z    = z
        if edge != None: self.edge = edge
        if mback_kws != None: self.mback_kws = mback_kws

        if self.z == None:
            Exception("Z for absorber not provided for diffKK")
        if self.edge == None:
            Exception("absorption edge not provided for diffKK")

        mb_kws = dict(order=3, z=self.z, edge=self.edge, e0=None, emin=None, emax=None,
                      whiteline=False, leexiang=False, tables='chantler',
                      fit_erfc=False, return_f1=True)
        if self.mback_kws is not None:
            mb_kws.update(self.mback_kws)

        start = time.clock()

        mback(self.energy, self.mu, group=self, _larch=self._larch, **mb_kws)

        ## interpolate matched data onto an even grid with an even number of elements (about 1 eV)
        npts = int(self.energy[-1] - self.energy[0]) + (int(self.energy[-1] - self.energy[0])%2)
        self.grid = np.linspace(self.energy[0], self.energy[-1], npts)
        fpp = interp(self.energy, self.f2-self.fpp, self.grid, fill_value=0.0)

        ## do difference KK
        if repr(how).startswith('sca'):
            fp = kkmclr_sca(self.grid, fpp)
        else:
            fp = kkmclr(self.grid, fpp)

        ## interpolate back to original grid and add diffKK result to f1 to make fp array
        self.fp = self.f1 + interp(self.grid, fp, self.energy, fill_value=0.0)

        ## clean up group
        #for att in ('normalization_function', 'weight', 'grid'):
        #    if hasattr(self, att): delattr(self, att)
        finish = time.clock()
        self.time_elapsed = float(finish-start)
예제 #6
0
def xas_deconvolve(energy, norm=None, group=None, form='lorentzian',
                   esigma=1.0, eshift=0.0, smooth=True,
                   sgwindow=None, sgorder=3, _larch=None):
    """XAS spectral deconvolution

    de-convolve a normalized mu(E) spectra with a peak shape, enhancing the
    intensity and separation of peaks of a XANES spectrum.

    The results can be unstable, and noisy, and should be used
    with caution!

    Arguments
    ----------
    energy:   array of x-ray energies (in eV) or XAFS data group
    norm:     array of normalized mu(E)
    group:    output group
    form:     functional form of deconvolution function. One of
              'gaussian' or 'lorentzian' [default]
    esigma    energy sigma to pass to gaussian() or lorentzian()
              [in eV, default=1.0]
    eshift    energy shift to apply to result. [in eV, default=0]
    smooth    whether to smooth result with savitzky_golay method [True]
    sgwindow  window size for savitzky_golay [found from data step and esigma]
    sgorder   order for savitzky_golay [3]

    Returns
    -------
    None
       The array 'deconv' will be written to the output group.

    Notes
    -----
       Support See First Argument Group convention, requiring group
       members 'energy' and 'norm'

       Smoothing with savitzky_golay() requires a window and order.  By
       default, window = int(esigma / estep) where estep is step size for
       the gridded data, approximately the finest energy step in the data.
    """

    energy, mu, group = parse_group_args(energy, members=('energy', 'norm'),
                                         defaults=(norm,), group=group,
                                         fcn_name='xas_deconvolve')
    eshift = eshift + 0.5 * esigma

    en  = remove_dups(energy)
    en  = en - en[0]
    estep = max(0.001, 0.001*int(min(en[1:]-en[:-1])*1000.0))
    npts = 1  + int(max(en) / estep)

    x = np.arange(npts)*estep
    y = interp(en, mu, x, kind='cubic')

    kernel = lorentzian
    if form.lower().startswith('g'):
        kernel = gaussian

    yext = np.concatenate((y, np.arange(len(y))*y[-1]))
    ret, err = deconvolve(yext, kernel(x, center=0, sigma=esigma))
    nret = min(len(x), len(ret))

    ret = ret[:nret]*yext[nret-1]/ret[nret-1]
    if smooth:
        if sgwindow is None:
            sgwindow = int(1.0*esigma/estep)

        sqwindow = int(sgwindow)
        if sgwindow < (sgorder+1):
            sgwindow = sgorder + 2
        if sgwindow % 2 == 0:
            sgwindow += 1
        ret = savitzky_golay(ret, sgwindow, sgorder)

    out = interp(x+eshift, ret, en, kind='cubic')
    group = set_xafsGroup(group, _larch=_larch)
    group.deconv = out
예제 #7
0
파일: diffkk.py 프로젝트: maurov/xraylarch
    def kk(self, energy=None, mu=None, z=None, edge='K', how='scalar', mback_kws=None):
        """
        Convert mu(E) data into f'(E) and f"(E).  f"(E) is made by
        matching mu(E) to the tabulated values of the imaginary part
        of the scattering factor (Cromer-Liberman), f'(E) is then
        obtained by performing a differential Kramers-Kronig transform
        on the matched f"(E).

          Attributes
            energy:     energy array
            mu:         array with mu(E) data
            z:          Z number of absorber
            edge:       absorption edge, usually 'K' or 'L3'
            mback_kws:  arguments for the mback algorithm

          Returns
            self.f1, self.f2:  CL values over on the input energy grid
            self.fp, self.fpp: matched and KK transformed data on the input energy grid

        References:
          * Cromer-Liberman: http://dx.doi.org/10.1063/1.1674266
          * KK computation: Ohta and Ishida, Applied Spectroscopy 42:6 (1988) 952-957
          * diffKK implementation: http://dx.doi.org/10.1103/PhysRevB.58.11215
          * MBACK (Weng, Waldo, Penner-Hahn): http://dx.doi.org/10.1086/303711
          * Lee and Xiang: http://dx.doi.org/10.1088/0004-637X/702/2/970

        """

        if type(energy).__name__ == 'ndarray': self.energy = energy
        if type(mu).__name__     == 'ndarray': self.mu     = mu
        if z    != None: self.z    = z
        if edge != None: self.edge = edge
        if mback_kws != None: self.mback_kws = mback_kws

        if self.z == None:
            Exception("Z for absorber not provided for diffKK")
        if self.edge == None:
            Exception("absorption edge not provided for diffKK")

        mb_kws = dict(order=3, z=self.z, edge=self.edge, e0=None, emin=None, emax=None,
                      whiteline=False, leexiang=False, tables='chantler',
                      fit_erfc=False, return_f1=True)
        if self.mback_kws is not None:
            mb_kws.update(self.mback_kws)

        start = time.clock()

        mback(self.energy, self.mu, group=self, _larch=self._larch, **mb_kws)

        ## interpolate matched data onto an even grid with an even number of elements (about 1 eV)
        npts = int(self.energy[-1] - self.energy[0]) + (int(self.energy[-1] - self.energy[0])%2)
        self.grid = np.linspace(self.energy[0], self.energy[-1], npts)
        fpp = interp(self.energy, self.f2-self.fpp, self.grid, fill_value=0.0)

        ## do difference KK
        if repr(how).startswith('sca'):
            fp = kkmclr_sca(self.grid, fpp)
        else:
            fp = kkmclr(self.grid, fpp)

        ## interpolate back to original grid and add diffKK result to f1 to make fp array
        self.fp = self.f1 + interp(self.grid, fp, self.energy, fill_value=0.0)

        ## clean up group
        #for att in ('normalization_function', 'weight', 'grid'):
        #    if hasattr(self, att): delattr(self, att)
        finish = time.clock()
        self.time_elapsed = float(finish-start)