Пример #1
0
 def setup(self,
           s,
           k,
           orders,
           bias=0,
           lowringing=False,
           direction='forward'):
     self.logger.debug('Initialization...')
     self.logsc, self.dlogs, self.ns = self.__class__.calc_log_binning(s)
     logkc = self.__class__.calc_log_binning(k, self.ns)[0]
     kcsc = 10**(self.logsc + logkc)
     self.logger.info(
         'Proposed central k * central s = {:.4g}; ns = {:d}, s-range = {:.4g} - {:.4g}.'
         .format(kcsc, self.ns, self.s[0], self.s[-1]))
     self.preset, self.kcsc = [], []
     for order in orders:
         nkcsc, save, ok = fftlog.fhti(self.ns, order,
                                       self.dlogs * scipy.log(10.), bias,
                                       kcsc, int(lowringing))
         self.kcsc += [nkcsc]
         txt = 'For order {:.3g}, new central k * central s = {:.4g}, ok = {}.'.format(
             order, nkcsc, ok == True)
         self.logger.debug(txt)
         if not ok: raise ValueError(txt)
     self.kcsc = scipy.mean(self.kcsc)
     self.logger.info(
         'New central k * central s = {:.4g}; nk = {:d}, k-range = {:.4g} - {:.4g}.'
         .format(self.kcsc, self.nk, self.k[0], self.k[-1]))
     if not lowringing:
         assert self.kcsc == kcsc, 'New k/s is not the same as given in input.'
     for order in orders:
         save, ok = fftlog.fhti(self.ns, order, self.dlogs * scipy.log(10.),
                                bias, self.kcsc, 0)[1:]
         self.preset += [save]
         if not ok:
             raise ValueError(
                 'FFTlog fails to compute order {:.3g}.'.format(order))
Пример #2
0
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)
Пример #3
0
    def __init__(self, logrmin=-4, logrmax=4, n=64, mu=0, q=0, kr=1, kropt=1):

        self.logrmin = logrmin  # Range of periodic interval
        self.logrmax = logrmax

        self.n = n  # Number of points (Max 4096)
        self.mu = mu  # Order mu of Bessel function
        self.q = q  # Bias exponent: q = 0 is unbiased
        self.kr = kr  # Sensible approximate choice of k_c r_c

        self.kropt = kropt  # Tell fhti to change kr to low-ringing value
        # WARNING: kropt = 3 will fail, as interaction is not supported

        # Forward transform (changed from dir to tdir, as dir is a python fct)
        self.tdir = 1

        # Log-spacing of points
        dlogr = (logrmax - logrmin) / n
        dlnr = dlogr * np.log(10.0)

        kr, wsave, ok = fftlog.fhti(self.n, self.mu, dlnr, self.q, self.kr,
                                    self.kropt)
        print('fftlog.fhti: ok =', bool(ok), '; New kr = ', kr)
Пример #4
0
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
Пример #5
0
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
Пример #6
0
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
Пример #7
0
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
Пример #8
0
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
Пример #9
0
# Log-spacing of points
dlogr = (logrmax - logrmin) / n
dlnr = dlogr * np.log(10.0)

# ### Calculate input function: $r^{\mu+1}\exp\left(-\frac{r^2}{2}\right)$

# In[4]:

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`

# In[5]:

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)