def v2dcosine_transform(f, s1, s2, args=(), m=20, ng=20, shanks_ind=None): """Cosine transform of f(x, y) at transform variable s1, s2 Vectorised 2d cosine transform. Parameters ---------- f : function or method Function to apply 2D cosine trasnform to. f is called with f(x, y, *args). s1, s2 : 1d array Transformation variables. A grid of points will be made. 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=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 sport 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. """ #dims of array: # 0 or i dim is each of the 1st transform coordinate s1 # 1 or j dim is each integration inteval corresponding to s1, a1, b1 # 2 or k dim is each gauss point in interval a1, b1 # 3 or l dim is each of the 2nd transform coordinate s2 # 4 or m dim is each integration interval corresponding to s2, a2, b2 # 5 or n dim is each gauss point in interval a2, b2 # 5 dim will be summed to get integral of each interval a2, b2 # 4 dim will be summed to get shanks'ed to give transform at each s2 coord # 2 dim will be summed to get integral of each interval a1, b1 # 1 dim will be summed to get shanks'ed to give transform at each s1 coord si = np.atleast_1d(s1) sl = np.atleast_1d(s2) xk_, wk = gauss_legendre_abscissae_and_weights(ng) xn_, wn = xk_, wk # integration intervals zeros = np.zeros(m + 1, dtype=float) zeros[1:] = (2 * np.arange(m) + 1) * np.pi/2 aj = am = zeros[0:-1] bj = bm = zeros[1:] si = si[:, None, None, None, None, None] aj = aj[None, :, None, None, None, None] bj = bj[None, :, None, None, None, None] xk_ = xk_[None, None, :, None, None, None] wk = wk[None, None, :, None, None, None] aij = aj / si bij = bj / si bmaij = (bij - aij) / 2 # b minus a bpaij = (aij + bij) /2 # b plus a sl = sl[ None, None, None, :, None, None] am = am[None, None, None, None, :, None] bm = bm[None, None, None, None, :, None] xn_ = xn_[None, None, None, None, None, :] wn = wn[None, None, None, None, None, :] alm = am / sl blm = bm / sl bmalm = (blm - alm) / 2 # b minus a bpalm = (alm + blm) /2 # b plus a xijk = bmaij * xk_ + bpaij # xj_ are in [-1, 1] so need to transform to [a, b] xlmn = bmalm * xn_ + bpalm fijklmn=f(xijk, xlmn, *args) fijklmn*=np.cos(si*xijk) fijklmn*=np.cos(sl*xlmn) fijklmn*=wk fijklmn*=wn fijklmn*=bmaij#[:,:,0,:,:,:] fijklmn*=bmalm#[:,:,:,:,:,0] igral = np.sum(fijklmn, axis=5) if shanks_ind is None: igral = igral.sum(axis=4) else: #extrapolate igral.cumsum(axis=4 , out=igral) igral= np.apply_along_axis(shanks, 4, igral, shanks_ind) igral = np.sum(igral, axis=2) if shanks_ind is None: igral = igral.sum(axis=1) else: #extrapolate igral.cumsum(axis=1 , out=igral) igral= np.apply_along_axis(shanks, 1, igral, shanks_ind) return igral
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)
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)
def v2dcosine_transform(f, s1, s2, args=(), m=20, ng=20, shanks_ind=None): """Cosine transform of f(x, y) at transform variable s1, s2 Vectorised 2d cosine transform. Parameters ---------- f : function or method Function to apply 2D cosine trasnform to. f is called with f(x, y, *args). s1, s2 : 1d array Transformation variables. A grid of points will be made. 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=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 sport 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. """ #dims of array: # 0 or i dim is each of the 1st transform coordinate s1 # 1 or j dim is each integration inteval corresponding to s1, a1, b1 # 2 or k dim is each gauss point in interval a1, b1 # 3 or l dim is each of the 2nd transform coordinate s2 # 4 or m dim is each integration interval corresponding to s2, a2, b2 # 5 or n dim is each gauss point in interval a2, b2 # 5 dim will be summed to get integral of each interval a2, b2 # 4 dim will be summed to get shanks'ed to give transform at each s2 coord # 2 dim will be summed to get integral of each interval a1, b1 # 1 dim will be summed to get shanks'ed to give transform at each s1 coord si = np.atleast_1d(s1) sl = np.atleast_1d(s2) xk_, wk = gauss_legendre_abscissae_and_weights(ng) xn_, wn = xk_, wk # integration intervals zeros = np.zeros(m + 1, dtype=float) zeros[1:] = (2 * np.arange(m) + 1) * np.pi / 2 aj = am = zeros[0:-1] bj = bm = zeros[1:] si = si[:, None, None, None, None, None] aj = aj[None, :, None, None, None, None] bj = bj[None, :, None, None, None, None] xk_ = xk_[None, None, :, None, None, None] wk = wk[None, None, :, None, None, None] aij = aj / si bij = bj / si bmaij = (bij - aij) / 2 # b minus a bpaij = (aij + bij) / 2 # b plus a sl = sl[None, None, None, :, None, None] am = am[None, None, None, None, :, None] bm = bm[None, None, None, None, :, None] xn_ = xn_[None, None, None, None, None, :] wn = wn[None, None, None, None, None, :] alm = am / sl blm = bm / sl bmalm = (blm - alm) / 2 # b minus a bpalm = (alm + blm) / 2 # b plus a xijk = bmaij * xk_ + bpaij # xj_ are in [-1, 1] so need to transform to [a, b] xlmn = bmalm * xn_ + bpalm fijklmn = f(xijk, xlmn, *args) fijklmn *= np.cos(si * xijk) fijklmn *= np.cos(sl * xlmn) fijklmn *= wk fijklmn *= wn fijklmn *= bmaij #[:,:,0,:,:,:] fijklmn *= bmalm #[:,:,:,:,:,0] igral = np.sum(fijklmn, axis=5) if shanks_ind is None: igral = igral.sum(axis=4) else: #extrapolate igral.cumsum(axis=4, out=igral) igral = np.apply_along_axis(shanks, 4, igral, shanks_ind) igral = np.sum(igral, axis=2) if shanks_ind is None: igral = igral.sum(axis=1) else: #extrapolate igral.cumsum(axis=1, out=igral) igral = np.apply_along_axis(shanks, 1, igral, shanks_ind) return igral
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)
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)