def xas_deconvolve(energy, norm=None, group=None, form='gaussian', esigma=1.0, eshift=0.0, _larch=None): """XAS spectral deconvolution This function de-convolves a normalized mu(E) spectra with a peak shape, enhancing separation of XANES features. This can be unstable -- Use results with caution! Arguments ---------- energy: array of x-ray energies, in eV or group norm: array of normalized mu(E) group: output group form: form of deconvolution function. One of 'gaussian' (default) or 'lorentzian' 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] 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' """ 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_deconv') 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='linear', _larch=_larch) kernel = gaussian if form.lower().startswith('lor'): kernel = lorentzian yext = np.concatenate((y, np.arange(len(y))*y[-1])) ret, err = deconvolve(yext, kernel(x, 0, esigma)) nret = min(len(x), len(ret)) ret = ret[:nret]*yext[nret-1]/ret[nret-1] out = _interp(x+eshift, ret, en, kind='linear', _larch=_larch) group = set_xafsGroup(group, _larch=_larch) group.deconv = out
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='cl', 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)
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)