def conv(e, mu, kernel='gaussian', fwhm_e=None, efermi=None): """ linear broadening Parameters ---------- e : x-axis (energy) mu : f(x) to convolve with g(x) kernel, mu(energy) kernel : convolution kernel, g(x) 'gaussian' 'lorentzian' fwhm_e: the full width half maximum in eV for the kernel broadening. It is an array of size 'e' with constants or an energy-dependent values determined by a function as 'lin_gamma()' or 'atan_gamma()' """ f = np.copy(mu) z = np.zeros_like(f) if efermi is not None: #ief = index_nearest(e, efermi) ief = np.argmin(np.abs(e-efermi)) f[0:ief] *= 0 if e.shape != fwhm_e.shape: print("Error: 'fwhm_e' does not have the same shape of 'e'") return 0 # linar fit upper part of the spectrum to avoid border effects # polyfit => pf lpf = len(e)/2. cpf = np.polyfit(e[-lpf:], f[-lpf:], 1) fpf = np.poly1d(cpf) # extend upper energy border to 3*fhwm_e[-1] estep = (e[-1] - e[-2]) eup = np.append(e, np.arange(e[-1]+estep, e[-1]+3*fwhm_e[-1], estep)) for n in range(len(f)): #from now on I change e with eup eimin, eimax = get_ene_index(eup, eup[n], 1.5*fwhm_e[n]) if ((eimin is None) or (eimax is None)): if DEBUG: raise IndexError('e[{0}]'.format(n)) if len(range(eimin, eimax)) % 2 == 0: kx = eup[eimin:eimax+1] # odd range centered at the convolution point else: kx = eup[eimin:eimax] ### kernel ### hwhm = fwhm_e[n]/2.0 if ('gauss' in kernel.lower()): ky = gaussian(kx, cen=eup[n], sigma=hwhm) elif ('lor' in kernel.lower()): ky = lorentzian(kx, cen=eup[n], sigma=hwhm) else: raise ValueError("convolution kernel '{0}' not implemented".format(kernel)) ky = ky/ky.sum() # normalize zn = 0 lk = len(kx) for mf, mg in zip( range(-(lk/2), (lk/2)+1), range(lk) ): if ( ((n+mf) >= 0) and ((n+mf) < len(f)) ): zn += f[n+mf] * ky[mg] elif ((n+mf) >= 0): zn += fpf(eup[n+mf]) * ky[mg] z[n] = zn return z
def lsmooth(x, sigma=1, gamma=None, form='lorentzian', npad=None): """convolve a 1-d array with a lorentzian, gaussian, or voigt function. fconvolve(x, sigma=1, gamma=None, form='lorentzian', npad=None) arguments: ------------ x input 1-d array for smoothing. sigma primary width parameter for convolving function gamma secondary width parameter for convolving function form name of convolving function: 'lorentzian' or 'gaussian' or 'voigt' ['lorentzian'] npad number of padding pixels to use [length of x] returns: -------- smoothed 1-d array with same length as input array x """ if npad is None: npad = len(x) wx = arange(2*npad) if form.lower().startswith('gauss'): win = gaussian(wx, cen=npad, sigma=sigma) elif form.lower().startswith('voig'): win = voigt(wx, cen=npad, sigma=sigma, gamma=gamma) else: win = lorentzian(wx, cen=npad, sigma=sigma) xax = concatenate((x[2*npad:0:-1], x, x[-1:-2*npad-1:-1])) out = convolve(win/win.sum(), xax, mode='valid') nextra = int((len(out) - len(x))/2) return (out[nextra:])[:len(x)]
def smooth(x, y, sigma=1, gamma=None, npad=None, form='lorentzian'): """smooth a function y(x) by convolving wih a lorentzian, gaussian, or voigt function. arguments: ------------ x input 1-d array for absicca y input 1-d array for ordinate: data to be smoothed sigma primary width parameter for convolving function gamma secondary width parameter for convolving function delx delta x to use for interpolation [mean of form name of convolving function: 'lorentzian' or 'gaussian' or 'voigt' ['lorentzian'] npad number of padding pixels to use [length of x] returns: -------- 1-d array with same length as input array y """ # make uniform x, y data TINY = 1.e-12 xstep = min(diff(x)) if xstep < TINY: raise Warning('Cannot smooth data: must be strictly increasing ') npad = 5 xmin = xstep * int( (min(x) - npad*xstep)/xstep) xmax = xstep * int( (max(x) + npad*xstep)/xstep) npts = 1 + int(abs(xmax-xmin+xstep*0.1)/xstep) x0 = linspace(xmin, xmax, npts) y0 = interp(x0, x, y) # put sigma in units of 1 for convolving window function sigma *= 1.0 / xstep if gamma is not None: gamma *= 1.0 / xstep wx = arange(2*npts) if form.lower().startswith('gauss'): win = gaussian(wx, cen=npts, sigma=sigma) elif form.lower().startswith('voig'): win = voigt(wx, cen=npts, sigma=sigma, gamma=gamma) else: win = lorentzian(wx, cen=npts, sigma=sigma) y1 = concatenate((y0[npts:0:-1], y0, y0[-1:-npts-1:-1])) y2 = convolve(win/win.sum(), y1, mode='valid') if len(y2) > len(x0): nex = int((len(y2) - len(x0))/2) y2 = (y2[nex:])[:len(x0)] return interp(x, x0, y2)
def conv(e, mu, kernel='gaussian', fwhm_e=None, efermi=None): """ linear broadening Parameters ---------- e : x-axis (energy) mu : f(x) to convolve with g(x) kernel, mu(energy) kernel : convolution kernel, g(x) 'gaussian' 'lorentzian' fwhm_e: the full width half maximum in eV for the kernel broadening. It is an array of size 'e' with constants or an energy-dependent values determined by a function as 'lin_gamma()' or 'atan_gamma()' """ f = np.copy(mu) z = np.zeros_like(f) if efermi is not None: #ief = index_nearest(e, efermi) ief = np.argmin(np.abs(e - efermi)) f[0:ief] *= 0 if e.shape != fwhm_e.shape: print("Error: 'fwhm_e' does not have the same shape of 'e'") return 0 # linar fit upper part of the spectrum to avoid border effects # polyfit => pf lpf = len(e) / 2. cpf = np.polyfit(e[-lpf:], f[-lpf:], 1) fpf = np.poly1d(cpf) # extend upper energy border to 3*fhwm_e[-1] estep = (e[-1] - e[-2]) eup = np.append(e, np.arange(e[-1] + estep, e[-1] + 3 * fwhm_e[-1], estep)) for n in range(len(f)): #from now on I change e with eup eimin, eimax = get_ene_index(eup, eup[n], 1.5 * fwhm_e[n]) if ((eimin is None) or (eimax is None)): if DEBUG: raise IndexError('e[{0}]'.format(n)) if len(range(eimin, eimax)) % 2 == 0: kx = eup[eimin:eimax + 1] # odd range centered at the convolution point else: kx = eup[eimin:eimax] ### kernel ### hwhm = fwhm_e[n] / 2.0 if ('gauss' in kernel.lower()): ky = gaussian(kx, cen=eup[n], sigma=hwhm) elif ('lor' in kernel.lower()): ky = lorentzian(kx, cen=eup[n], sigma=hwhm) else: raise ValueError( "convolution kernel '{0}' not implemented".format(kernel)) ky = ky / ky.sum() # normalize zn = 0 lk = len(kx) for mf, mg in zip(range(-(lk / 2), (lk / 2) + 1), range(lk)): if (((n + mf) >= 0) and ((n + mf) < len(f))): zn += f[n + mf] * ky[mg] elif ((n + mf) >= 0): zn += fpf(eup[n + mf]) * ky[mg] z[n] = zn return z