Beispiel #1
0
    def test_pi_max_shanks_ind(self):
        """4 * sum((-1)**k * (2 * k+1)**(-1))"""
        nn = 10
        seq = np.array([4*sum((-1)**n/(2*n+1) for n in range(m)) for
                        m in range(1, nn)])

        assert_allclose(shanks(seq, -50), np.pi, atol=1e-8)
Beispiel #2
0
    def __call__(self, s, a=0, b=np.inf):
        """transform f(r, *args) at s

        Parameters
        ----------
        s : scalar
            transform variable, i.e. coordinate to evaluate transform at
        a, b : float, optional
            limits of integration.  default a=0, b=np.inf.  A hankel transform
            is usually from 0 to infinity.  However, if you have a function
            that is defined on [a,b] and zero elsewhere then you can restrict
            integration to that interval (shanks_ind will be ignored if
            b!=np.inf).

        Returns
        -------
        F : float
            Transformed functin evaluated at s.
        err_est : float
            Error estimate.  For each interval (i.e. between bessel zeros
            and any specified points) sum up 200*abs(G-K)**1.5.  The error is
            calculated before any shanks extrapolation so the error is just a
            measure of the difference between the coarse Gauss quadrature and
            the finer Kronrod quadrature.


        """

        integrand = functools.partial(self._integrand, s)

        zeros = self.jn_0s / s

        if not self.points is None:
            #zeros becomes both zeros and interesting points/singularities
            zeros = np.unique(
                list(zeros) + list(self.points[(self.points < zeros[-1])
                                               & (self.points > 0)]))

        if (a != 0) or (b != np.inf):
            zeros = np.unique(zeros.clip(a, b))

        #1st segment
        igral0, err_est0 = gk_quad(integrand, zeros[0], zeros[1], self.args,
                                   self.ng0)
        #remaining segments
        if len(zeros) > 2:
            igralm, err_estm = gk_quad(integrand, zeros[1:-1], zeros[2:],
                                       self.args, self.ng)
        else:
            return igral0[0], err_est0[0]

        if (self.shanks_ind is None) or (b != np.inf):
            igral = igral0 + np.sum(igralm)
        else:
            igralm.cumsum(out=igralm)
            igral = igral0 + shanks(igralm, self.shanks_ind)

        err_est = (200 * np.abs(err_est0))**1.5 + np.sum(
            (200 * np.abs(err_estm))**1.5)
        return igral[0], err_est[0]
Beispiel #3
0
    def test_pi_max_shanks_ind(self):
        """4 * sum((-1)**k * (2 * k+1)**(-1))"""
        nn = 10
        seq = np.array([
            4 * sum((-1)**n / (2 * n + 1) for n in range(m))
            for m in range(1, nn)
        ])

        assert_allclose(shanks(seq, -50), np.pi, atol=1e-8)
Beispiel #4
0
def vcosine_transform(f, s, args=(), m=20, ng=20, shanks_ind=None):
    """Cosine transform of f(x) at transform variable s

    This is a vectorized cosine transform.

    Parameters
    ----------
    f : function or method
        Function to apply cosine trasnform to.  f is called with
        f(x, *args).
    s : 1d array
        Coordinate(s) to evaluate transform at.
    args : tuple, optional
        arguments to pass to f
    m : int, optional
        Number of segments to break the integration interval into.  Each
        segment will be between the zeros of the cos function, Default m=20.
    ng : [2-20, 32, 64, 100], optional
        Number of gauss points to use in integration., Default ng=20.
    shanks_ind : int, optional
        Start position of intervals to start shanks extrapolation.
        Default shanks_ind=None i.e. no extrapolation.
        Be careful when using shanks extrapolation; make sure you only begin
        to use it after the intgrand is well behaved.

    Returns
    -------
    f : 1d array of float
        Value of transform at s

    Notes
    -----
    Careful with singularities.  Because there is no way to increase the
    integration points at a particular spot the infinite behaviur may not be
    captured well. For example x**-0.5 should transform to sqrt(pi/2*w) but
    due to the sinularity at x=0 it does not converge well even using ng=100.



    """


    si = np.atleast_1d(s)

    xk_, wk = gauss_legendre_abscissae_and_weights(ng)

    # integration intervals

    zeros = np.zeros(m + 1, dtype=float)
    zeros[1:] = (2 * np.arange(m) + 1) * np.pi/2

    aj = zeros[0:-1]
    bj = zeros[1:]

    #dims of array:
    # 0 or i dim is each transform coordinate
    # 1 or j dim is each integration interval
    # 2 or k dim is each integration point

    # 2 dim will be summed to get integral of each interval
    # 1 dim will be summed or shanks'ed to give transform at each coord
    #

    si = si[:, np.newaxis, np.newaxis]

    aj = aj[np.newaxis, :, np.newaxis]
    bj = bj[np.newaxis, :, np.newaxis]

    xk_ = xk_[np.newaxis, np.newaxis, :]

    wk = wk[np.newaxis, np.newaxis, :]


    aij = aj / si
    bij = bj / si

    bma = (bij - aij) / 2 # b minus a
    bpa = (aij + bij) /2 # b plus a


    xijk = bma * xk_ + bpa # xj_ are in [-1, 1] so need to transform to [a, b]

    fijk = f(xijk, *args)
    fijk *= np.cos(si * xijk)
#    fijk *= xijk

    igral = bma[:,:,0] * np.sum(fijk * wk, axis=2)



    if shanks_ind is None:
        return igral.sum(axis=1)
    else:
        #extrapolate
        igral.cumsum(axis=1 , out=igral)
        return shanks(igral, shanks_ind)
Beispiel #5
0
def vhankel_transform(f, r, args=(), order=0, m=20, ng=20, shanks_ind=None):
    """Hankel transform of f(r)

    This is a vectorised Hankel transform

    Parameters
    ----------
    f : function or method
        Function to apply hankel trasnform to.  f is called with
        f(s, *args).
    r : 1d array
        Coordinate(s) to evaluate transform at.
    args : tuple, optional
        Arguments to pass to f, default args=().
    order : integer, optional
        Order of hankel transform. Default order=0.
    m : int, optional
        Number of segments to break the integration interval into.  Each
        segment will be between the zeros of the bessel function.
        Default m=20.
    ng : [2-20, 32, 64, 100], optional
        Number of gauss points to use in integration. Default ng=20.
    shanks_ind : int, optional
        Start position of intervals to start shanks extrapolation.
        Default shanks_ind=None i.e. no extrapolation.
        Be careful when using shanks extrapolation; make sure you only begin
        to use it after the intgrand is well behaved.

    Returns
    -------
    f : 1d array of float
        Value of transform at r.

    Notes
    -----
    The Hankel Transform of order :math:`\\nu` is given by:

    .. math:: F_\\nu(s)=\mathcal{H}_\\nu\\{f(r)\\} =
                \\int_0^{\\infty}rf(r)J_\\nu(sr)\\,\\mathrm{d}r

    Provided :math:`\\nu\\gt1/2` the inverse hankel transform is the same as
    the normal transform:

    .. math:: f(r)=\mathcal{H}_{\\nu}^{-1}\\{F_{\\nu}(s)\\} =
                \\int_0^{\\infty}sF_\\nu(s)J_\\nu(sr)\\,\\mathrm{d}s


    Note that because this implementation does not allow for input of
    extra point to break up the integration inteval, there is no way to
    account for singularities and other oscillations.  If you need this control
    then see the HankelTransform class which is not vectorized but provides a
    few more options.


    See Also
    --------
    HankelTransform : Non vectorised Hankel transform.


    References
    ----------
    .. [1] Piessens, Robert. 2000. 'Chapter 9 The Hankel Transform'. In The
           Transforms and Applications Handbook, edited by Alexander
           D. Poularikas, 2nd edition. Boca Raton, USA: CRC Press.


    """


    ri = np.atleast_1d(r)

    xk_, wk = gauss_legendre_abscissae_and_weights(ng)

    # integration intervals
    zeros = np.zeros(m + 1, dtype=float)
    zeros[1:] = jn_zeros(order, m)

    aj = zeros[0:-1]
    bj = zeros[1:]


    ri = ri[:, np.newaxis, np.newaxis]

    aj = aj[np.newaxis, :, np.newaxis]
    bj = bj[np.newaxis, :, np.newaxis]

    xk_ = xk_[np.newaxis, np.newaxis, :]

    wk = wk[np.newaxis, np.newaxis, :]


    aij = aj / ri
    bij = bj / ri

    bma = (bij - aij) / 2 # b minus a
    bpa = (aij + bij) /2 # b plus a


    xijk = bma * xk_ + bpa # xj_ are in [-1, 1] so need to transform to [a, b]

    fijk = f(xijk, *args)
    fijk *= jn(order, ri * xijk)
    fijk *= xijk

    igral = bma[:,:,0] * np.sum(fijk * wk, axis=2)



    if shanks_ind is None:
        return igral.sum(axis=1)
    else:
        #extrapolate
        igral.cumsum(axis=1 , out=igral)
        return shanks(igral, shanks_ind)
Beispiel #6
0
    def __call__(self, s, a=0, b=np.inf):
        """transform f(r, *args) at s

        Parameters
        ----------
        s : scalar
            transform variable, i.e. coordinate to evaluate transform at
        a, b : float, optional
            limits of integration.  default a=0, b=np.inf.  A hankel transform
            is usually from 0 to infinity.  However, if you have a function
            that is defined on [a,b] and zero elsewhere then you can restrict
            integration to that interval (shanks_ind will be ignored if
            b!=np.inf).

        Returns
        -------
        F : float
            Transformed functin evaluated at s.
        err_est : float
            Error estimate.  For each interval (i.e. between bessel zeros
            and any specified points) sum up 200*abs(G-K)**1.5.  The error is
            calculated before any shanks extrapolation so the error is just a
            measure of the difference between the coarse Gauss quadrature and
            the finer Kronrod quadrature.


        """


        integrand = functools.partial(self._integrand, s)

        zeros = self.jn_0s / s

        if not self.points is None:
            #zeros becomes both zeros and interesting points/singularities
            zeros = np.unique(list(zeros) +
                    list(self.points[(self.points < zeros[-1])
                                     & (self.points>0)]))

        if (a!=0) or (b!=np.inf):
            zeros = np.unique(zeros.clip(a, b))

        #1st segment
        igral0, err_est0 = gk_quad(integrand, zeros[0], zeros[1],
                                   self.args, self.ng0)
        #remaining segments
        if len(zeros)>2:
            igralm, err_estm = gk_quad(integrand, zeros[1:-1], zeros[2:],
                                       self.args, self.ng)
        else:
            return igral0[0], err_est0[0]


        if (self.shanks_ind is None) or (b!=np.inf):
            igral = igral0 + np.sum(igralm)
        else:
            igralm.cumsum(out=igralm)
            igral = igral0 + shanks(igralm, self.shanks_ind)

        err_est = (200*np.abs(err_est0))**1.5 + np.sum((200*np.abs(err_estm))**1.5)
        return igral[0], err_est[0]
Beispiel #7
0
def vcosine_transform(f, s, args=(), m=20, ng=20, shanks_ind=None):
    """Cosine transform of f(x) at transform variable s

    This is a vectorized cosine transform.

    Parameters
    ----------
    f : function or method
        Function to apply cosine trasnform to.  f is called with
        f(x, *args).
    s : 1d array
        Coordinate(s) to evaluate transform at.
    args : tuple, optional
        arguments to pass to f
    m : int, optional
        Number of segments to break the integration interval into.  Each
        segment will be between the zeros of the cos function, Default m=20.
    ng : [2-20, 32, 64, 100], optional
        Number of gauss points to use in integration., Default ng=20.
    shanks_ind : int, optional
        Start position of intervals to start shanks extrapolation.
        Default shanks_ind=None i.e. no extrapolation.
        Be careful when using shanks extrapolation; make sure you only begin
        to use it after the intgrand is well behaved.

    Returns
    -------
    f : 1d array of float
        Value of transform at s

    Notes
    -----
    Careful with singularities.  Because there is no way to increase the
    integration points at a particular spot the infinite behaviur may not be
    captured well. For example x**-0.5 should transform to sqrt(pi/2*w) but
    due to the sinularity at x=0 it does not converge well even using ng=100.



    """

    si = np.atleast_1d(s)

    xk_, wk = gauss_legendre_abscissae_and_weights(ng)

    # integration intervals

    zeros = np.zeros(m + 1, dtype=float)
    zeros[1:] = (2 * np.arange(m) + 1) * np.pi / 2

    aj = zeros[0:-1]
    bj = zeros[1:]

    #dims of array:
    # 0 or i dim is each transform coordinate
    # 1 or j dim is each integration interval
    # 2 or k dim is each integration point

    # 2 dim will be summed to get integral of each interval
    # 1 dim will be summed or shanks'ed to give transform at each coord
    #

    si = si[:, np.newaxis, np.newaxis]

    aj = aj[np.newaxis, :, np.newaxis]
    bj = bj[np.newaxis, :, np.newaxis]

    xk_ = xk_[np.newaxis, np.newaxis, :]

    wk = wk[np.newaxis, np.newaxis, :]

    aij = aj / si
    bij = bj / si

    bma = (bij - aij) / 2  # b minus a
    bpa = (aij + bij) / 2  # b plus a

    xijk = bma * xk_ + bpa  # xj_ are in [-1, 1] so need to transform to [a, b]

    fijk = f(xijk, *args)
    fijk *= np.cos(si * xijk)
    #    fijk *= xijk

    igral = bma[:, :, 0] * np.sum(fijk * wk, axis=2)

    if shanks_ind is None:
        return igral.sum(axis=1)
    else:
        #extrapolate
        igral.cumsum(axis=1, out=igral)
        return shanks(igral, shanks_ind)
Beispiel #8
0
def vhankel_transform(f, r, args=(), order=0, m=20, ng=20, shanks_ind=None):
    """Hankel transform of f(r)

    This is a vectorised Hankel transform

    Parameters
    ----------
    f : function or method
        Function to apply hankel trasnform to.  f is called with
        f(s, *args).
    r : 1d array
        Coordinate(s) to evaluate transform at.
    args : tuple, optional
        Arguments to pass to f, default args=().
    order : integer, optional
        Order of hankel transform. Default order=0.
    m : int, optional
        Number of segments to break the integration interval into.  Each
        segment will be between the zeros of the bessel function.
        Default m=20.
    ng : [2-20, 32, 64, 100], optional
        Number of gauss points to use in integration. Default ng=20.
    shanks_ind : int, optional
        Start position of intervals to start shanks extrapolation.
        Default shanks_ind=None i.e. no extrapolation.
        Be careful when using shanks extrapolation; make sure you only begin
        to use it after the intgrand is well behaved.

    Returns
    -------
    f : 1d array of float
        Value of transform at r.

    Notes
    -----
    The Hankel Transform of order :math:`\\nu` is given by:

    .. math:: F_\\nu(s)=\mathcal{H}_\\nu\\{f(r)\\} =
                \\int_0^{\\infty}rf(r)J_\\nu(sr)\\,\\mathrm{d}r

    Provided :math:`\\nu\\gt1/2` the inverse hankel transform is the same as
    the normal transform:

    .. math:: f(r)=\mathcal{H}_{\\nu}^{-1}\\{F_{\\nu}(s)\\} =
                \\int_0^{\\infty}sF_\\nu(s)J_\\nu(sr)\\,\\mathrm{d}s


    Note that because this implementation does not allow for input of
    extra point to break up the integration inteval, there is no way to
    account for singularities and other oscillations.  If you need this control
    then see the HankelTransform class which is not vectorized but provides a
    few more options.


    See Also
    --------
    HankelTransform : Non vectorised Hankel transform.


    References
    ----------
    .. [1] Piessens, Robert. 2000. 'Chapter 9 The Hankel Transform'. In The
           Transforms and Applications Handbook, edited by Alexander
           D. Poularikas, 2nd edition. Boca Raton, USA: CRC Press.


    """

    ri = np.atleast_1d(r)

    xk_, wk = gauss_legendre_abscissae_and_weights(ng)

    # integration intervals
    zeros = np.zeros(m + 1, dtype=float)
    zeros[1:] = jn_zeros(order, m)

    aj = zeros[0:-1]
    bj = zeros[1:]

    ri = ri[:, np.newaxis, np.newaxis]

    aj = aj[np.newaxis, :, np.newaxis]
    bj = bj[np.newaxis, :, np.newaxis]

    xk_ = xk_[np.newaxis, np.newaxis, :]

    wk = wk[np.newaxis, np.newaxis, :]

    aij = aj / ri
    bij = bj / ri

    bma = (bij - aij) / 2  # b minus a
    bpa = (aij + bij) / 2  # b plus a

    xijk = bma * xk_ + bpa  # xj_ are in [-1, 1] so need to transform to [a, b]

    fijk = f(xijk, *args)
    fijk *= jn(order, ri * xijk)
    fijk *= xijk

    igral = bma[:, :, 0] * np.sum(fijk * wk, axis=2)

    if shanks_ind is None:
        return igral.sum(axis=1)
    else:
        #extrapolate
        igral.cumsum(axis=1, out=igral)
        return shanks(igral, shanks_ind)