def test_spherical_yn_recurrence_real(self): # http://dlmf.nist.gov/10.51.E1 n = np.array([1, 2, 3, 7, 12]) x = 0.12 assert_allclose( spherical_yn(n - 1, x) + spherical_yn(n + 1, x), (2 * n + 1) / x * spherical_yn(n, x))
def spherical_ddyn(l, z): L = float(l) SphBesR0 = sp.spherical_yn(l, z) dSphBesR1 = sp.spherical_yn(l - 1, z, True) dSphBesR0 = sp.spherical_yn(l, z, True) result = dSphBesR1 + (L + 1) / z**2. * SphBesR0 - (L + 1) / z * dSphBesR0 return result
def riccati_2(n, z, derivative=False): yn = special.spherical_yn(n, z, derivative=derivative) if derivative: yn_p = special.spherical_yn(n, z, derivative=True) return -z * yn_p - yn return -z * yn
def test_spherical_yn_recurrence_complex(self): # https://dlmf.nist.gov/10.51.E1 n = np.array([1, 2, 3, 7, 12]) x = 1.1 + 1.5j assert_allclose( spherical_yn(n - 1, x) + spherical_yn(n + 1, x), (2 * n + 1) / x * spherical_yn(n, x))
def test_spherical_jn_yn_cross_product_2(self): # http://dlmf.nist.gov/10.50.E3 n = np.array([1, 5, 8]) x = np.array([0.1, 1, 10]) left = spherical_jn(n + 2, x) * spherical_yn(n, x) - spherical_jn(n, x) * spherical_yn(n + 2, x) right = (2 * n + 3) / x ** 3 assert_allclose(left, right)
def test_spherical_jn_yn_cross_product_2(self): # https://dlmf.nist.gov/10.50.E3 n = np.array([1, 5, 8]) x = np.array([0.1, 1, 10]) left = (spherical_jn(n + 2, x) * spherical_yn(n, x) - spherical_jn(n, x) * spherical_yn(n + 2, x)) right = (2 * n + 3) / x**3 assert_allclose(left, right)
def F(L, x, Omega2): a = scipy.sqrt((Omega2 * (1 - x**2))) b = 1j * Omega2**0.5 * x coeff = -1j * scipy.sqrt((1 - x**2)) firstTerm = ss.spherical_jn(L - 1, a) / ss.spherical_jn(L, a) secdTerm = (ss.spherical_jn(L, b) + 1j * ss.spherical_yn(L, b)) / ( ss.spherical_jn(L - 1, b) + 1j * ss.spherical_yn(L - 1, b)) return coeff * firstTerm * secdTerm
def test_sph_yn(self): sy1 = spherical_yn(2, 0.2) sy2 = spherical_yn(0, 0.2) assert_almost_equal(sy1,-377.52483,5) # previous values in the system assert_almost_equal(sy2,-4.9003329,5) sphpy = (spherical_yn(0, 0.2) - 2*spherical_yn(2, 0.2))/3 sy3 = spherical_yn(1, 0.2, derivative=True) assert_almost_equal(sy3,sphpy,4) # compare correct derivative val. (correct =-system val).
def test_sph_yn(self): sy1 = spherical_yn(2, 0.2) sy2 = spherical_yn(0, 0.2) assert_almost_equal(sy1, -377.52483, 5) # previous values in the system assert_almost_equal(sy2, -4.9003329, 5) sphpy = (spherical_yn(0, 0.2) - 2 * spherical_yn(2, 0.2)) / 3 sy3 = spherical_yn(1, 0.2, derivative=True) assert_almost_equal(sy3, sphpy, 4) # compare correct derivative val. (correct =-system val).
def test_spherical_jn_yn_cross_product_1(self): # https://dlmf.nist.gov/10.50.E3 n = np.array([1, 5, 8]) x = np.array([0.1, 1, 10]) left = (spherical_jn(n + 1, x) * spherical_yn(n, x) - spherical_jn(n, x) * spherical_yn(n + 1, x)) right = 1/x**2 assert_allclose(left, right)
def riccati_2_single(n, x): """Riccati_2, but only a single n value""" # pre = (np.pi*x/2)**.5 # hn = pre*special.hankel1(n+0.5,x) # hnp = hn/(2*x) + pre*special.h1vp(n+0.5,x) yn = special.spherical_yn(n, x) ynp = special.spherical_yn(n, x, derivative=True) return np.array([x * yn, yn + x * ynp])
def bessel8(n, z): if n == 0: return sp.spherical_jn( n, z, derivative=True) - 1.j * sp.spherical_yn(n, z, derivative=True) else: h21 = sp.spherical_jn(n - 1, z) - 1.j * sp.spherical_yn(n - 1, z) h22 = sp.spherical_jn(n + 1, z) - 1.j * sp.spherical_yn(n + 1, z) return (1. / (2 * n + 1)) * (n * h21 - (n + 1) * h22)
def calc_j(n, k, a): shankel = spherical_jn(n, k * a, derivative=False) + \ 1j * spherical_yn(n, k * a, derivative=False) shankel_d = spherical_jn(n, k * a, derivative=True) + \ 1j * spherical_yn(n, k * a, derivative=True) j = 4 * np.pi * np.power(1j, n) * ( spherical_jn(n, k * a, derivative=False) - spherical_jn(n, k * a, derivative=True) / shankel_d * shankel) return j
def riccati_yn(n, x, derivative=False): if derivative == True: return (spherical_jn(n, x, derivative=False) + (0 + 1j) * spherical_yn(n, x, derivative=False) ) + x * (spherical_jn(n, x, derivative=True) + (0 + 1j) * spherical_yn(n, x, derivative=True)) else: return x * (spherical_jn(n, x, derivative=False) + (0 + 1j) * spherical_yn(n, x, derivative=False))
def bessel7(n, z): if n == 0: return sp.spherical_jn( n, z, derivative=True) + 1.j * sp.spherical_yn(n, z, derivative=True) else: h11 = sp.spherical_jn(n - 1, z) + 1.j * sp.spherical_yn(n - 1, z) h12 = sp.spherical_jn(n + 1, z) + 1.j * sp.spherical_yn(n + 1, z) return (1. / (2 * n + 1)) * (n * h11 - (n + 1) * h12)
def spherical_hn(n, k, z): """nth-order sphericah Henkel function of kth kind Returns h_n^(k)(z) """ if k == 1: return special.spherical_jn(n, z) + 1j * special.spherical_yn(n, z) elif k == 2: return special.spherical_jn(n, z) - 1j * special.spherical_yn(n, z) else: raise ValueError()
def riccati_yn(a_n, a_z, a_d=False): """ The Riccati-Neumann function. return: z * yn(z) (or its derivative) """ if (a_d): return spherical_yn(a_n, a_z) + a_z * spherical_yn(a_n, a_z, True) else: return a_z * spherical_yn(a_n, a_z)
def sph_jnyn(maxn, z): jn = [] djn = [] yn = [] dyn = [] for n in range(0, maxn + 1): jn.append(spherical_jn(n, z)) djn.append(spherical_jn(n, z, derivative=True)) yn.append(spherical_yn(n, z)) dyn.append(spherical_yn(n, z, derivative=True)) return np.array(jn), np.array(djn), np.array(yn), np.array(dyn)
def phase_shift_fixed_range(a, b, l, sign, xi, xf, method='RK45', atol_ode=1e-4, rtol_ode=1e-5): ''' Calculate phase shift of Yukawa potential. This function calculates the phase shift for fixed range [xi, xf]. Inputs: x = alphaX*mX*r. atol_ode and rtol_ode is precision paramters for ODE solver. Outputs: dl : phase shift ''' def f(x, y): return [ y[1], -(a**2 - l * (l + 1.0) / x**2 + sign * np.exp(-x / b) / x) * y[0] ] def jac(x, y): return [[0.0, 1.0], [ -(a**2 - l * (l + 1.0) / x**2 + sign * np.exp(-x / b) / x), 0.0 ]] # solve ODE t_eval = None y0 = [1.0, (l + 1) / xi] sol = solve_ivp(fun=f, t_span=(xi, xf), t_eval=t_eval, y0=y0, jac=jac, method=method, atol=atol_ode, rtol=rtol_ode) # calculate phase shift bl = xf * sol.y[1][-1] / sol.y[0][-1] - 1.0 tandl = (a*xf*spherical_jn(l,a*xf,derivative=True) - bl*spherical_jn(l,a*xf, derivative=False))\ /(a*xf*spherical_yn(l,a*xf,derivative=True) - bl*spherical_yn(l,a*xf, derivative=False)) dl = np.arctan(tandl) return dl
def bessel7(n, z): h1_n = sp.spherical_jn(n, z) + 1.j * sp.spherical_yn(n, z) if n == 0: dh1_n = sp.spherical_jn( n, z, derivative=True) + 1.j * sp.spherical_yn(n, z, derivative=True) zdh1_n = h1_n + z * dh1_n else: h11 = sp.spherical_jn(n - 1, z) + 1.j * sp.spherical_yn(n - 1, z) h12 = sp.spherical_jn(n + 1, z) + 1.j * sp.spherical_yn(n + 1, z) dh1_n = (1. / (2 * n + 1)) * (n * h11 - (n + 1) * h12) zdh1_n = h1_n + z * dh1_n return zdh1_n
def bessel8(n, z): h2_n = sp.spherical_jn(n, z) - 1.j * sp.spherical_yn(n, z) if n == 0: dh2_n = sp.spherical_jn( n, z, derivative=True) - 1.j * sp.spherical_yn(n, z, derivative=True) zdh2_n = h2_n + z * dh2_n else: h21 = sp.spherical_jn(n - 1, z) - 1.j * sp.spherical_yn(n - 1, z) h22 = sp.spherical_jn(n + 1, z) - 1.j * sp.spherical_yn(n + 1, z) dh2_n = (1. / (2 * n + 1)) * (n * h21 - (n + 1) * h22) zdh2_n = h2_n + z * dh2_n return zdh2_n
def test_spherical_bessel_y(): order = np.random.randint(0, 10) value = np.random.rand(1).item() assert (roundScaler(NumCpp.spherical_bessel_yn_Scaler(order, value), NUM_DECIMALS_ROUND) == roundScaler(sp.spherical_yn(order, value).item(), NUM_DECIMALS_ROUND)) shapeInput = np.random.randint(20, 100, [2, ]) shape = NumCpp.Shape(shapeInput[0].item(), shapeInput[1].item()) cArray = NumCpp.NdArray(shape) order = np.random.randint(0, 10) data = np.random.rand(shape.rows, shape.cols) cArray.setArray(data) assert np.array_equal(roundArray(NumCpp.spherical_bessel_yn_Array(order, cArray), NUM_DECIMALS_ROUND), roundArray(sp.spherical_yn(order, data), NUM_DECIMALS_ROUND))
def weights(N, kr, setup): r"""Radial weighing functions. Computes the radial weighting functions for diferent array types (cf. eq.(2.62), Rafaely 2015). For instance for an rigid array .. math:: b_n(kr) = j_n(kr) - \frac{j_n^\prime(kr)}{h_n^{(2)\prime}(kr)}h_n^{(2)}(kr) Parameters ---------- N : int Maximum order. kr : (M,) array_like Wavenumber * radius. setup : {'open', 'card', 'rigid'} Array configuration (open, cardioids, rigid). Returns ------- bn : (M, N+1) numpy.ndarray Radial weights for all orders up to N and the given wavenumbers. """ kr = util.asarray_1d(kr) n = np.arange(N + 1) bns = np.zeros((len(kr), N + 1), dtype=complex) for i, x in enumerate(kr): jn = special.spherical_jn(n, x) if setup == 'open': bn = jn elif setup == 'card': bn = jn - 1j * special.spherical_jn(n, x, derivative=True) elif setup == 'rigid': if x == 0: # hn(x)/hn'(x) -> 0 for x -> 0 bn = jn else: jnd = special.spherical_jn(n, x, derivative=True) hn = jn - 1j * special.spherical_yn(n, x) hnd = jnd - 1j * special.spherical_yn(n, x, derivative=True) bn = jn - jnd / hnd * hn else: raise ValueError('setup must be either: open, card or rigid') bns[i, :] = bn return np.squeeze(bns)
def riccati_3(nmax, x): """Riccati bessel function of the 3rd kind returns (r3, r3'), n=0,1,...,nmax""" x = np.asarray(x) result = np.zeros((2, nmax) + x.shape, dtype=np.complex) for n in range(nmax): yn = special.spherical_yn(n + 1, x) ynp = special.spherical_yn(n + 1, x, derivative=True) result[0, n] = x * yn result[1, n] = yn + x * ynp return result
def spneumann(n, kr): """Spherical Neumann (Bessel second kind) of order n at kr Parameters ---------- n : array_like Order kr: array_like Argument Returns ------- Yv : complex float Spherical Neumann (Bessel second kind) """ n, kr = scalar_broadcast_match(n, kr) if _np.any(n < 0) | _np.any(_np.mod(n, 1) != 0): Yv = _np.full(kr.shape, _np.nan, dtype=_np.complex_) kr_non_zero = kr != 0 Yv[kr_non_zero] = _np.lib.scimath.sqrt(_np.pi / 2 / kr[kr_non_zero]) * neumann(n[kr_non_zero] + 0.5, kr[kr_non_zero]) Yv[kr < 0] = -Yv[kr < 0] else: Yv = scy.spherical_yn(n.astype(_np.int), kr) Yv[_np.isinf(Yv)] = _np.nan # return possible infs as nan to stay consistent return _np.squeeze(Yv)
def riccati3(n, z, derivative=False): """ Riccati function that works with complex argument z """ j = sp.spherical_jn(n, z).astype(CTYPE) y = sp.spherical_yn(n, z).astype(CTYPE) if not derivative: psi = z * (j + 1j * y) return psi else: dj = sp.spherical_jn(n, z, derivative=True).astype(CTYPE) dy = sp.spherical_yn(n, z, derivative=True).astype(CTYPE) # dpsi = j + 1j * y + z * (dj + 1j * dy) return dpsi return
def spherical_hn1(a_n, a_z, a_d=False): """ The spherical Hankel function of the first kind. return: jn + i yn """ return spherical_jn(a_n, a_z, a_d) + 1.0j * spherical_yn(a_n, a_z, a_d)
def spherical_hn2(a_n, a_z, a_d=False): """ The spherical Hankel function of the second kind. return: jn - i yn """ return spherical_jn(a_n, a_z, a_d) - 1.0j * spherical_yn(a_n, a_z, a_d)
def test_spherical_yn_exact(self): # https://dlmf.nist.gov/10.49.E5 # Note: exact expression is numerically stable only for small # n or z >> n. x = np.array([0.12, 1.23, 12.34, 123.45, 1234.5]) assert_allclose(spherical_yn(2, x), (1 / x - 3 / x * x * x) * cos(x) - 3 / x * x * sin(x))
def test_spherical_yn_exact(self): # http://dlmf.nist.gov/10.49.E5 # Note: exact expression is numerically stable only for small # n or z >> n. x = np.array([0.12, 1.23, 12.34, 123.45, 1234.5]) assert_allclose(spherical_yn(2, x), (1/x - 3/x**3)*cos(x) - 3/x**2*sin(x))
def spherical_hn2(n, z, derivative=False): """Spherical Hankel function of the second kind. Parameters ---------- n : int, array_like Order of the spherical Hankel function (n >= 0). z : complex or float, array_like Argument of the spherical Hankel function. derivative : bool, optional If True, the value of the derivative (rather than the function itself) is returned. Returns ------- hn2 : array_like References ---------- http://mathworld.wolfram.com/SphericalHankelFunctionoftheSecondKind.html """ with np.errstate(invalid='ignore'): yi = 1j * scyspecial.spherical_yn(n, z, derivative) return scyspecial.spherical_jn(n, z, derivative) - yi
def spherical_hn2der(n, kr): # hn2der = 0.5*(spherical_hn2(n-1,kr)- (spherical_hn2(n,kr)+kr*spherical_hn2(n+1,kr)/kr)) hn2der = spherical_jn( n, kr, derivative=True) - 1j * spherical_yn(n, kr, derivative=True) return (hn2der)
def bessel(x, n, kind=1, derivative=0): # upto 4th der # for zero value, use non-zero instead x = x.detach().numpy() ''' der_fuc=torch.sin(x)/x j_n_test=der_fuc for n_test in range(0,n): j_n_test=nth_derivative(j_n_test,x,1) j_n_test=j_n_test*(1/x) j_n=j_n_test*((-1)**n)*(x**n) ''' if kind == 1: J_n = spherical_jn(n, x, derivative=derivative) #j_n=nth_derivative(j_n,x,derivative) elif kind == 2: J_n = spherical_yn(n, x, derivative=derivative) else: pass return J_n
def test_spherical_yn_inf_complex(self): # https://dlmf.nist.gov/10.52.E3 n = 7 x = np.array([-inf + 0j, inf + 0j, inf*(1+1j)]) with suppress_warnings() as sup: sup.filter(RuntimeWarning, "invalid value encountered in multiply") assert_allclose(spherical_yn(n, x), np.array([0, 0, inf*(1+1j)]))
def calc_Rn(N, kr): ''' This function calculates Rn = -ikr * e^(ikr) * i^(-n) * hn(kr) , where hn is the nth order spherical Hankel function of the second kind Inputs: N = maximum order kr = product of the wavenumber and the radius of the cylindrical speaker array Outputs: Rn_diag = a diagonal matrix that contains R0 , R1 ..... RN ''' hn = np.zeros((N + 1, )) + 0j Rn = np.zeros((N + 1, )) + 0j for n in range(N + 1): # Because the real and imaginary parts of hn are the spherical Bessel function of the first and the second # kinds respectively hn_re = special.spherical_jn(n, kr, derivative=False) hn_im = special.spherical_yn(n, kr, derivative=False) hn[n] = hn_re - 1j * hn_im Rn[n] = -1j * kr * (math.e**(1j * kr)) * (1j**(-n)) * hn[n] # Rn[n] = 1j*kr*(math.e**(1j*kr))*hn[n] Rn_diag = np.diag(Rn) return Rn_diag
def scattering_amplitude_energy(Evec, U, R, theta, lmax=30): costheta = cos(theta) P = lpmv(0, arange(lmax), costheta) # Legendre polynomial f = zeros(len(Evec), dtype=complex) for ll in range(lmax): kR = sqrt(2*Evec)*R qR = sqrt(2*(Evec+U))*R ## Spherical bessels/hankels, and their derivatives jl = spherical_jn(ll, qR) jlp = spherical_jn(ll, qR, derivative=True) hl = spherical_jn(ll, kR) + 1j*spherical_yn(ll, kR) hlp = spherical_jn(ll, kR, True) + 1j*spherical_yn(ll, kR, True) delt = 0.5*pi - angle((kR*hlp*jl - qR*hl*jlp)/R) f += (-0.5j*R/kR) * (exp(2j*delt)-1) * (2*ll+1) * P[ll] return f
def test_spherical_yn_at_zero_complex(self): # Consistently with numpy: # >>> -np.cos(0)/0 # -inf # >>> -np.cos(0+0j)/(0+0j) # (-inf + nan*j) n = np.array([0, 1, 2, 5, 10, 100]) x = 0 + 0j assert_allclose(spherical_yn(n, x), nan * np.ones(shape=n.shape))
def scattering_amplitude_theta(E, U, R, thetavec, lmax=30): lvec = arange(lmax) P = zeros((len(lvec), len(thetavec))) # Legendre polynomials for jj in range(len(lvec)): P[jj,:] = lpmv(0, lvec[jj], cos(thetavec)) kR = sqrt(2*E)*R qR = sqrt(2*(E+U))*R ## Spherical bessels/hankels, and their derivatives jl = spherical_jn(lvec, qR) jlp = spherical_jn(lvec, qR, derivative=True) hl = spherical_jn(lvec, kR) + 1j*spherical_yn(lvec, kR) hlp = spherical_jn(lvec, kR, True) + 1j*spherical_yn(lvec, kR, True) ## Phase shifts for each l component delt = 0.5*pi - angle((kR*hlp*jl - qR*hl*jlp)/R) coef = (exp(2j*delt)-1) * (2*lvec+1) return (-0.5j*R/kR) * dot(coef, P)
def test_mie_internal_coeffs(): if os.name == 'nt': raise SkipTest() m = 1.5 + 0.1j x = 50. n_stop = miescatlib.nstop(x) al, bl = miescatlib.scatcoeffs(m, x, n_stop) cl, dl = miescatlib.internal_coeffs(m, x, n_stop) n = np.arange(n_stop)+1 jlx = spherical_jn(n, x) jlmx = spherical_jn(n, m*x) hlx = jlx + 1.j * spherical_yn(n, x) assert_allclose(cl, (jlx - hlx * bl) / jlmx, rtol = 1e-6, atol = 1e-6) assert_allclose(dl, (jlx - hlx * al)/ (m * jlmx), rtol = 1e-6, atol = 1e-6)
def dspneumann(n, kr): """Derivative spherical Neumann (Bessel second kind) of order n at kr Parameters ---------- n : array_like Order kr: array_like Argument Returns ------- Yv' : complex float Derivative of spherical Neumann (Bessel second kind) """ n, kr = scalar_broadcast_match(n, kr) if _np.any(n < 0) | _np.any(_np.mod(n, 1) != 0) | _np.any(_np.mod(kr, 1) != 0): return spneumann(n, kr) * n / kr - spneumann(n + 1, kr) else: return scy.spherical_yn(n.astype(_np.int), kr.astype(_np.complex), derivative=True)
def spherical_hn2(n, z): r"""Spherical Hankel function of 2nd kind. Defined as http://dlmf.nist.gov/10.47.E6, .. math:: \hankel{2}{n}{z} = \sqrt{\frac{\pi}{2z}} \Hankel{2}{n + \frac{1}{2}}{z}, where :math:`\Hankel{2}{n}{\cdot}` is the Hankel function of the second kind and n-th order, and :math:`z` its complex argument. Parameters ---------- n : array_like Order of the spherical Hankel function (n >= 0). z : array_like Argument of the spherical Hankel function. """ return spherical_jn(n, z) - 1j * spherical_yn(n, z)
def spherical_yn_(n, x): return spherical_yn(n.astype('l'), x)
def test_spherical_yn_at_zero(self): # http://dlmf.nist.gov/10.52.E2 n = np.array([0, 1, 2, 5, 10, 100]) x = 0 assert_allclose(spherical_yn(n, x), -inf * np.ones(shape=n.shape))
def test_spherical_yn_inf_complex(self): # http://dlmf.nist.gov/10.52.E3 n = 7 x = np.array([-inf + 0j, inf + 0j, inf * (1 + 1j)]) assert_allclose(spherical_yn(n, x), np.array([0, 0, inf * (1 + 1j)]))
def test_spherical_yn_inf_real(self): # http://dlmf.nist.gov/10.52.E3 n = 6 x = np.array([-inf, inf]) assert_allclose(spherical_yn(n, x), np.array([0, 0]))
def test_spherical_yn_recurrence_complex(self): # http://dlmf.nist.gov/10.51.E1 n = np.array([1, 2, 3, 7, 12]) x = 1.1 + 1.5j assert_allclose(spherical_yn(n - 1, x) + spherical_yn(n + 1, x), (2 * n + 1) / x * spherical_yn(n, x))
def df(self, n, z): return spherical_yn(n, z, derivative=True)
def f(self, n, z): return spherical_yn(n, z)
def test_spherical_yn_recurrence_real(self): # https://dlmf.nist.gov/10.51.E1 n = np.array([1, 2, 3, 7, 12]) x = 0.12 assert_allclose(spherical_yn(n - 1, x) + spherical_yn(n + 1,x), (2*n + 1)/x*spherical_yn(n, x))