def integrate(self, integrand): res = [] for integ, preset in zip(integrand, self.preset): if scipy.isrealobj(integ): res.append(fftlog.fht(integ, preset, self.direction)) else: res.append( fftlog.fht(integ.real, preset, self.direction) + 1j * fftlog.fht(integ.imag, preset, self.direction)) return scipy.asarray(res)
def test_fftlog(): # This is the example provided in `fftlogtest.f` of the original code. It # is the same test that is shown as an example in the gallery. # See the example for more details. # Parameters. logrmin = -4 logrmax = 4 n = 64 mu = 0 q = 0 kr = 1 kropt = 1 tdir = 1 logrc = (logrmin + logrmax)/2 nc = (n + 1)/2.0 dlogr = (logrmax - logrmin)/n dlnr = dlogr*np.log(10.0) # Calculate input function: $r^{\mu+1}\exp\left(-\frac{r^2}{2}\right)$. r = 10**(logrc + (np.arange(1, n+1) - nc)*dlogr) ar = r**(mu + 1)*np.exp(-r**2/2.0) # Initialize FFTLog transform - note fhti resets `kr` kr, xsave, _ = fhti(n, mu, dlnr, q, kr, kropt) assert_allclose(kr, 0.953538967579) logkc = np.log10(kr) - logrc # rk = 10**(logrc - logkc) # Transform # ak = fftl(ar.copy(), xsave, rk, tdir) ak = fht(ar.copy(), xsave, tdir) # Calculate Output function: $k^{\mu+1}\exp\left(-\frac{k^2}{2}\right)$ k = 10**(logkc + (np.arange(1, n+1) - nc)*dlogr) theo = k**(mu + 1)*np.exp(-k**2/2.0) # Check values assert_allclose(theo[theo > 1e-3], ak[theo > 1e-3], rtol=1e-8, atol=5e-5)
def iHankel(k, f, N=4096, order=0.5): """ This routine returns the inverse Hankel transform of order :math:`\\nu` of a log-spaced function. The computation is .. math :: f(r) = \int_0^\infty \ dk \ k \ f(k) \ J_\\nu(kr) .. warning:: Because of log-spacing, an extra `k` factor has been already added in the code. .. warning:: If ``order = 0.5`` it is similar to the 3D Fourier transform of a spherically symmetric function. Parameters ---------- `k`: array Abscissae of function, log-spaced. `f`: array ordinates of function. `N`: int, default = 4096 Number of output points `order`: float, default = 0.5 Order of the transform (Bessel polynomial). Returns ---------- rr: array Frequencies. Fr: array Transformed array. """ # FFT specifics mu = order # Order mu of Bessel function q = 0 # Bias exponent: q = 0 is unbiased kr = 1 # Sensible approximate choice of k_c r_c kropt = 1 # Tell fhti to change kr to low-ringing value tdir = -1 # Backward transform logkc = (np.max(np.log10(k)) + np.min(np.log10(k))) / 2. dlogk = (np.max(np.log10(k)) - np.min(np.log10(k))) / N dlnk = dlogk * np.log(10.) if N % 2 == 0: nc = N / 2 else: nc = (N + 1) / 2 k_t = 10.**(logkc + (np.arange(1, N + 1) - nc) * dlogk) # Initialise function (add k_t extra factor because of log-spacing) funct = si.interp1d(k, f, kind="cubic", bounds_error=False, fill_value=0.) ak = funct(k_t) * k_t # Initialization of transform #kr, xsave, ok = fftlog.fhti(N, mu, dlnk, q, kr, kropt) fft_obj = fftlog.fhti(N, mu, dlnk, q, kr, kropt) kr, xsave = fft_obj[0], fft_obj[1] logrc = np.log10(kr) - logkc # Transform (dividing by a rr extra factor because of log-spacing) Fr = fftlog.fht(ak.copy(), xsave, tdir) if N % 2 == 0: rr = 10.**(logrc + (np.arange(N) - nc) * dlogk) else: rr = 10.**(logrc + (np.arange(1, N + 1) - nc) * dlogk) Fr /= rr return rr, Fr
def iHankel_3D_order(k, f, N=4096, order=0): """ This routine is similar to the Fourier transform in 3D but it can return any order of the Bessel function .. math :: f_\ell(r) = \int_0^\infty \\frac{dk \ k^2}{2\pi^2} \ f(k) \ j_\ell(kr) Parameters ---------- `k`: array Abscissae of function, log-spaced. `f`: array ordinates of function. `N`: int, default = 4096 Number of output points `order`: float, default = 0 Order of the Bessel spherical polynomial. Returns ---------- rr: array Frequencies. Fr: array Transformed array. """ # FFT specifics mu = order + 0.5 # Order mu of Bessel function q = 0 # Bias exponent: q = 0 is unbiased kr = 1 # Sensible approximate choice of k_c r_c kropt = 1 # Tell fhti to change kr to low-ringing value tdir = -1 # Backward transform logkc = (np.max(np.log10(k)) + np.min(np.log10(k))) / 2. dlogk = (np.max(np.log10(k)) - np.min(np.log10(k))) / N dlnk = dlogk * np.log(10.) if N % 2 == 0: nc = N / 2 else: nc = (N + 1) / 2 k_t = 10.**(logkc + (np.arange(1, N + 1) - nc) * dlogk) # Initialise function funct = si.interp1d(k, f, kind="cubic", bounds_error=False, fill_value=0.) ak = funct(k_t) * k_t**1.5 # Initialization of transform #kr, xsave, ok = fftlog.fhti(N, mu, dlnk, q, kr, kropt) fft_obj = fftlog.fhti(N, mu, dlnk, q, kr, kropt) kr, xsave = fft_obj[0], fft_obj[1] logrc = np.log10(kr) - logkc # Transform ar = fftlog.fht(ak.copy(), xsave, tdir) if N % 2 == 0: rr = 10.**(logrc + (np.arange(N) - nc) * dlogk) else: rr = 10.**(logrc + (np.arange(1, N + 1) - nc) * dlogk) Fr = ar / (2. * np.pi * rr)**1.5 return rr, Fr
def Hankel_3D_order(r, f, N=4096, order=0): """ This routine is analogous to the Fourier transform in 3D but it can return any order of the Bessel function .. math :: f_\ell(k) = \int_0^\infty dr \ 4\pi r^2 \ f(r) \ j_\ell(kr) Parameters ---------- `r`: array Abscissae of function, log-spaced. `f`: array ordinates of function. `N`: int, default = 4096 Number of output points `order`: float, default = 0 Order of the Bessel spherical polynomial. Returns ---------- kk: array Frequencies. Fk: array Transformed array. """ mu = order + 0.5 # Order mu of Bessel function q = 0 # Bias exponent: q = 0 is unbiased kr = 1 # Sensible approximate choice of k_c r_c kropt = 1 # Tell fhti to change kr to low-ringing value tdir = 1 # Forward transform logrc = (np.max(np.log10(r)) + np.min(np.log10(r))) / 2. dlogr = (np.max(np.log10(r)) - np.min(np.log10(r))) / N dlnr = dlogr * np.log(10.) if N % 2 == 0: nc = N / 2 else: nc = (N + 1) / 2 r_t = 10.**(logrc + (np.arange(1, N + 1) - nc) * dlogr) # Initialise function funct = si.interp1d(r, f, kind="cubic", bounds_error=False, fill_value=0.) ar = funct(r_t) * (2. * np.pi * r_t)**1.5 # Initialization of transform #kr, xsave, ok = fftlog.fhti(N, mu, dlnr, q, kr, kropt) fft_obj = fftlog.fhti(N, mu, dlnr, q, kr, kropt) kr, xsave = fft_obj[0], fft_obj[1] logkc = np.log10(kr) - logrc # Transform ak = fftlog.fht(ar.copy(), xsave, tdir) if N % 2 == 0: kk = 10.**(logkc + (np.arange(N) - nc) * dlogr) else: kk = 10.**(logkc + (np.arange(1, N + 1) - nc) * dlogr) Fk = ak / kk**1.5 return kk, Fk
def iFFT_iso_3D(k, f, N=4096): """ This routine returns the inverse FFT of a radially symmetric function. It employs the ``FFTlog`` module, which in turn makes use of the Hankel transform: therefore the function that will be actually transformed is :math:`f(k) \ k^{1.5}/(2\pi r)^{1.5}`. N.B. Since the integral is performed in log-space, the exponent of `r` is 1.5 instead of 0.5. The computation is .. math :: f(r) = \int_0^\infty \\frac{dk \ k^2}{2\pi^2} \ f(k) \ j_0(kr) Parameters ---------- `k`: array Abscissae of function, log-spaced. `f`: array ordinates of function. `N`: int, default = 4096 Number of output points Returns ---------- rr: array Frequencies. Fr: array Transformed array. """ # FFT specifics mu = 0.5 # Order mu of Bessel function q = 0 # Bias exponent: q = 0 is unbiased kr = 1 # Sensible approximate choice of k_c r_c kropt = 1 # Tell fhti to change kr to low-ringing value tdir = -1 # Backward transform logkc = (np.max(np.log10(k)) + np.min(np.log10(k))) / 2. dlogk = (np.max(np.log10(k)) - np.min(np.log10(k))) / N dlnk = dlogk * np.log(10.) if N % 2 == 0: nc = N / 2 else: nc = (N + 1) / 2 k_t = 10.**(logkc + (np.arange(1, N + 1) - nc) * dlogk) # Initialise function funct = si.interp1d(k, f, kind="cubic", bounds_error=False, fill_value=0.) ak = funct(k_t) * k_t**1.5 # Initialization of transform #kr, xsave, ok = fftlog.fhti(N, mu, dlnk, q, kr, kropt) fft_obj = fftlog.fhti(N, mu, dlnk, q, kr, kropt) kr, xsave = fft_obj[0], fft_obj[1] logrc = np.log10(kr) - logkc # Transform ar = fftlog.fht(ak.copy(), xsave, tdir) if N % 2 == 0: rr = 10.**(logrc + (np.arange(N) - nc) * dlogk) else: rr = 10.**(logrc + (np.arange(1, N + 1) - nc) * dlogk) Fr = ar / (2 * np.pi * rr)**1.5 return rr, Fr
def FFT_iso_3D(r, f, N=4096): """ This routine returns the FFT of a radially symmetric function. It employs the ``FFTlog`` module, which in turn makes use of the Hankel transform: therefore the function that will be actually transformed is :math:`f(r) \ (2\pi r)^{1.5}/k^{1.5}`. N.B. Since the integral is performed in log-space, the exponent of `r` is 1.5 instead of 0.5. The computation is .. math :: f(k) = \int_0^\infty dr \ 4\pi r^2 \ f(r) \ j_0(kr) Parameters ---------- `r`: array Abscissae of function, log-spaced. `f`: array ordinates of function. `N`: int, default = 4096 Number of output points Returns ---------- kk: array Frequencies. Fk: array Transformed array. """ mu = 0.5 # Order mu of Bessel function q = 0 # Bias exponent: q = 0 is unbiased kr = 1 # Sensible approximate choice of k_c r_c kropt = 1 # Tell fhti to change kr to low-ringing value tdir = 1 # Forward transform logrc = (np.max(np.log10(r)) + np.min(np.log10(r))) / 2. dlogr = (np.max(np.log10(r)) - np.min(np.log10(r))) / N dlnr = dlogr * np.log(10.) if N % 2 == 0: nc = N / 2 else: nc = (N + 1) / 2 r_t = 10.**(logrc + (np.arange(1, N + 1) - nc) * dlogr) # Initialise function funct = si.interp1d(r, f, kind="cubic", bounds_error=False, fill_value=0.) ar = funct(r_t) * (2. * np.pi * r_t)**1.5 # Initialization of transform #kr, xsave, ok = fftlog.fhti(N, mu, dlnr, q, kr, kropt) fft_obj = fftlog.fhti(N, mu, dlnr, q, kr, kropt) kr, xsave = fft_obj[0], fft_obj[1] logkc = np.log10(kr) - logrc # Transform ak = fftlog.fht(ar.copy(), xsave, tdir) if N % 2 == 0: kk = 10.**(logkc + (np.arange(N) - nc) * dlogr) else: kk = 10.**(logkc + (np.arange(1, N + 1) - nc) * dlogr) Fk = ak / kk**1.5 return kk, Fk
kr, wsave, ok = fftlog.fhti(n, mu, dlnr, q, kr, kropt) print('fftlog.fhti: ok =', bool(ok), '; New kr = ', kr) # ### Call `fftlog.fht` (or `fftlog.fhtl`) # In[6]: logkc = np.log10(kr) - logrc print('Central point in k-space at log10(k_c) = ', logkc) # rk = r_c/k_c rk = 10**(logrc - logkc) # Transform #ak = fftlog.fftl(ar.copy(), wsave, rk, tdir) ak = fftlog.fht(ar.copy(), wsave, tdir) # ### Calculate Output function: $k^{\mu+1}\exp\left(-\frac{k^2}{2}\right)$ # In[7]: k = 10**(logkc + (np.arange(1, n + 1) - nc) * dlogr) theo = k**(mu + 1) * np.exp(-k**2 / 2.0) # ### Plot result # In[8]: plt.figure(figsize=(16, 8)) # Transformed result
kr, wsave, ok = fftlog.fhti(n, mu, dlnr, kr, q, kropt) print('fftlog.fhti: ok =', bool(ok), '; New kr = ', kr) # ### Call `fftlog.fht` (or `fftlog.fhtl`) # In[6]: logkc = np.log10(kr) - logrc print('Central point in k-space at log10(k_c) = ', logkc) # rk = r_c/k_c rk = 10**(logrc - logkc) # Transform #ak = fftlog.fftl(ar, tdir, wsave, rk) ak = fftlog.fht(ar.copy(), tdir, wsave) # ### Calculate Output function: $k^{\mu+1}\exp\left(-\frac{k^2}{2}\right)$ # In[7]: k = 10**(logkc + (np.arange(1, n + 1) - nc) * dlogr) theo = k**(mu + 1) * np.exp(-k**2 / 2.0) # ### Plot result # In[8]: plt.figure(figsize=(16, 8)) # Transformed result