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]
def check_gk_quad_chunks_extra_dims2(n): """check that gk_quad integrates polynomial of degree 3*n+1 (even) and 3*n+2 (odd)exactly, with multiple intervals with function that returns extra dims. This test is not rigorous because the polynomials formed can be fairly well approximated using lower order schemes """ #a, b = (-0.9, 1.3) a = np.array([-0.9, -0.4, .5]) b = np.array([-0.4, 0.5, 1.3]) coeff = np.arange(1, 3 * n + 1 + (n % 2)) coeff[::2] = coeff[::2] * -1.0 f = np.poly1d(coeff) def g(x): out = f(x) * np.arange(1, 9) return out g_ = g #np.vectorize(g) F = f.integ() exact = np.sum(F(b) - F(a)) * np.arange(1, 9) assert_allclose(gk_quad(g_, a, b, n=n, sum_intervals=True)[0], exact, rtol=1e-3, atol=0)
def check_gk_quad(n): """check that gk_quad integrates polynomial of degree 3*n+1 (even) and 3*n+2 (odd)exactly This test is not rigorous because the ploynmials formed can be fairly well approximated using lower order schemes """ a, b = (-0.9, 1.3) coeff = np.arange(1, 3*n + 1 + (n%2)) coeff[::2] =coeff[::2]*-1.0 f = np.poly1d(coeff) F = f.integ() exact = F(b) - F(a) assert_allclose(gk_quad(f,a,b, n=n)[0], exact, rtol=1e-14,atol=0)
def check_gk_quad(n): """check that gk_quad integrates polynomial of degree 3*n+1 (even) and 3*n+2 (odd)exactly This test is not rigorous because the polynomials formed can be fairly well approximated using lower order schemes """ a, b = (-0.9, 1.3) coeff = np.arange(1, 3 * n + 1 + (n % 2)) coeff[::2] = coeff[::2] * -1.0 f = np.poly1d(coeff) F = f.integ() exact = F(b) - F(a) assert_allclose(gk_quad(f, a, b, n=n)[0], exact, rtol=1e-14, atol=0)
def check_gk_quad_chunks(n): """check that gk_quad integrates polynomial of degree 3*n+1 (even) and 3*n+2 (odd)exactly, with multiple intervals This test is not rigorous because the polynomials formed can be fairly well approximated using lower order schemes """ #a, b = (-0.9, 1.3) a = np.array([-0.9, -0.4, .5]) b = np.array([-0.4, 0.5, 1.3]) coeff = np.arange(1, 3*n + 1 + (n%2)) coeff[::2] =coeff[::2]*-1.0 f = np.poly1d(coeff) F = f.integ() exact = np.sum(F(b) - F(a)) assert_allclose(gk_quad(f,a,b, n=n, sum_intervals=True)[0], exact, rtol=1e-3,atol=0)
def check_gk_quad_chunks(n): """check that gk_quad integrates polynomial of degree 3*n+1 (even) and 3*n+2 (odd)exactly, with multiple intervals This test is not rigorous because the polynomials formed can be fairly well approximated using lower order schemes """ #a, b = (-0.9, 1.3) a = np.array([-0.9, -0.4, .5]) b = np.array([-0.4, 0.5, 1.3]) coeff = np.arange(1, 3 * n + 1 + (n % 2)) coeff[::2] = coeff[::2] * -1.0 f = np.poly1d(coeff) F = f.integ() exact = np.sum(F(b) - F(a)) assert_allclose(gk_quad(f, a, b, n=n, sum_intervals=True)[0], exact, rtol=1e-3, atol=0)
def check_gk_quad_chunks_extra_dims2(n): """check that gk_quad integrates polynomial of degree 3*n+1 (even) and 3*n+2 (odd)exactly, with multiple intervals with function that returns extra dims. This test is not rigorous because the polynomials formed can be fairly well approximated using lower order schemes """ #a, b = (-0.9, 1.3) a = np.array([-0.9, -0.4, .5]) b = np.array([-0.4, 0.5, 1.3]) coeff = np.arange(1, 3*n + 1 + (n%2)) coeff[::2] =coeff[::2]*-1.0 f = np.poly1d(coeff) def g(x): out = f(x)*np.arange(1,9) return out g_ = g#np.vectorize(g) F = f.integ() exact = np.sum(F(b) - F(a)) * np.arange(1,9) assert_allclose(gk_quad(g_,a,b, n=n, sum_intervals=True)[0], exact, rtol=1e-3,atol=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]