Last active
November 13, 2020 10:13
-
-
Save ntessore/3dc14068fa07bead5493cbaecb5d9328 to your computer and use it in GitHub Desktop.
FFTLog in Python, using only numpy and scipy.special.loggamma
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
from scipy.fft import rfft, irfft | |
from scipy.special import loggamma | |
# constants | |
LN_2 = np.log(2) | |
LN_10 = np.log(10) | |
def lnkrgood(lnkr, dlnr, mu, q=0.0): | |
# find low-ringing kr | |
xp = (mu+1+q)/2 | |
xm = (mu+1-q)/2 | |
y = np.pi/(2*dlnr) | |
zp = loggamma(xp + 1j*y) | |
zm = loggamma(xm + 1j*y) | |
arg = (LN_2 - lnkr)/dlnr + (zp.imag + zm.imag)/np.pi | |
return lnkr + (arg - np.round(arg))*dlnr | |
def fhtq(f, dlnr, lnkr, mu, q=0.0): | |
'''compute a discrete version of the biased Hankel transform | |
Parameters | |
---------- | |
f : array_like (..., N) | |
Function values. Can be multidimensional, the transform is performed | |
over the last axis. | |
dlnr : float | |
Log-spacing of abscissae. | |
lnkr : float | |
Relation between k and r arrays, `k = exp(lnkr)/r[::-1]`. | |
mu : float | |
Order of the transform. | |
q : float, optional | |
Exponent of power law bias. | |
''' | |
assert np.ndim(f) >= 1, 'f must be array' | |
assert np.isscalar(dlnr), 'dlnr must be scalar' | |
assert np.isscalar(lnkr), 'kr must be scalar' | |
assert np.isscalar(mu), 'mu must be scalar' | |
# size of transform | |
n = np.shape(f)[-1] | |
# compute Hankel transform coefficients | |
a = (mu+1+q)/2 | |
b = (mu+1-q)/2 | |
c = np.arange(0, n//2+1, dtype=float) | |
c *= np.pi/(n*dlnr) | |
u = np.empty(len(c), dtype=complex) | |
v = np.empty(len(c), dtype=complex) | |
u.real[:] = a | |
v.real[:] = b | |
u.imag[:] = c | |
v.imag[:] = c | |
loggamma(u, out=u) | |
loggamma(v, out=v) | |
c *= 2*(lnkr - LN_2) | |
u.real -= v.real | |
u.real += LN_2*q | |
u.imag += v.imag | |
u.imag -= c | |
np.exp(u, out=u) | |
if np.isnan(u[0]): | |
if a > 0: | |
u[0] = 0 | |
else: | |
raise ValueError(f'singular transform') | |
del(v) | |
# Hankel transform via real FFT | |
g = rfft(f, axis=-1) | |
g *= u | |
g = irfft(g, n, axis=-1) | |
g[..., :] = g[..., ::-1] | |
return g |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment