def d_phi_helper(self, n, l, m, s, theta): """ computes the derivatives of dphi/dr and dYlm/dtheta """ # Radial component # From Eqn. 3.29 in Hernquist and Ostriker 1992 poly_ratio = special.eval_gegenbauer(n-1, 2*l+2.5, ((s-1)/(s+1))) / special.eval_gegenbauer(n, 2*l+1.5, ((s-1)/(s+1))) dphi_dr_factor = (l/s - (2*l+1)/(1+s) + 4*(2*l+1.5)/(1+s)**2 * poly_ratio) # Theta component # From wolfram: https://functions.wolfram.com/Polynomials/SphericalHarmonicY/20/ShowAll.html # Both definitions are okay but this one is faster to compute numerically. l_zeros = np.where((l>=0)) m_zeros = np.where((m<=l-1)) dpot_dtheta = np.zeros_like(dphi_dr_factor) Plm_1 = np.zeros_like(dphi_dr_factor) Plm = special.lpmv(m[l_zeros], l[l_zeros], np.cos(theta)) Plm_1[m_zeros] = special.lpmv(m[m_zeros], l[m_zeros]-1, np.cos(theta)) # check -1 in m-1 gamma_factor = special.gamma(l[l_zeros]-m[l_zeros]+1)**0.5 / special.gamma(l[l_zeros]+m[l_zeros]+1)**0.5 constant = ((2*l+1)/(4*np.pi))**0.5 dpot_dtheta[l_zeros] = constant * gamma_factor * (l[l_zeros]*np.cos(theta) * Plm - (l[l_zeros]+m[l_zeros])*Plm_1) / np.sin(theta) return dphi_dr_factor, dpot_dtheta
def pure_py(xyz, Snlm, Tnlm, nmax, lmax): from scipy.special import lpmv, gegenbauer, eval_gegenbauer, gamma from math import factorial as f Plm = lambda l,m,costh: lpmv(m, l, costh) Ylmth = lambda l,m,costh: np.sqrt((2*l+1)/(4 * np.pi) * f(l-m)/f(l+m)) * Plm(l,m,costh) twopi = 2*np.pi sqrtpi = np.sqrt(np.pi) sqrt4pi = np.sqrt(4*np.pi) r = np.sqrt(np.sum(xyz**2, axis=0)) X = xyz[2]/r # cos(theta) sinth = np.sqrt(1 - X**2) phi = np.arctan2(xyz[1], xyz[0]) xsi = (r - 1) / (r + 1) density = 0 potenti = 0 gradien = np.zeros_like(xyz) sph_gradien = np.zeros_like(xyz) for l in range(lmax+1): r_term1 = r**l / (r*(1+r)**(2*l+3)) r_term2 = r**l / (1+r)**(2*l+1) for m in range(l+1): for n in range(nmax+1): Cn = gegenbauer(n, 2*l+3/2) Knl = 0.5 * n * (n+4*l+3) + (l+1)*(2*l+1) rho_nl = Knl / twopi * sqrt4pi * r_term1 * Cn(xsi) phi_nl = -sqrt4pi * r_term2 * Cn(xsi) density += rho_nl * Ylmth(l,m,X) * (Snlm[n,l,m]*np.cos(m*phi) + Tnlm[n,l,m]*np.sin(m*phi)) potenti += phi_nl * Ylmth(l,m,X) * (Snlm[n,l,m]*np.cos(m*phi) + Tnlm[n,l,m]*np.sin(m*phi)) # derivatives dphinl_dr = (2*sqrtpi*np.power(r,-1 + l)*np.power(1 + r,-3 - 2*l)* (-2*(3 + 4*l)*r*eval_gegenbauer(-1 + n,2.5 + 2*l,(-1 + r)/(1 + r)) + (1 + r)*(l*(-1 + r) + r)*eval_gegenbauer(n,1.5 + 2*l,(-1 + r)/(1 + r)))) sph_gradien[0] += dphinl_dr * Ylmth(l,m,X) * (Snlm[n,l,m]*np.cos(m*phi) + Tnlm[n,l,m]*np.sin(m*phi)) A = np.sqrt((2*l+1) / (4*np.pi)) * np.sqrt(gamma(l-m+1) / gamma(l+m+1)) dYlm_dth = A / sinth * (l*X*Plm(l,m,X) - (l+m)*Plm(l-1,m,X)) sph_gradien[1] += (1/r) * dYlm_dth * phi_nl * (Snlm[n,l,m]*np.cos(m*phi) + Tnlm[n,l,m]*np.sin(m*phi)) sph_gradien[2] += (m/(r*sinth)) * phi_nl * Ylmth(l,m,X) * (-Snlm[n,l,m]*np.sin(m*phi) + Tnlm[n,l,m]*np.cos(m*phi)) cosphi = np.cos(phi) sinphi = np.sin(phi) gradien[0] = sinth*cosphi*sph_gradien[0] + X*cosphi*sph_gradien[1] - sinphi*sph_gradien[2] gradien[1] = sinth*sinphi*sph_gradien[0] + X*sinphi*sph_gradien[1] + cosphi*sph_gradien[2] gradien[2] = X*sph_gradien[0] - sinth*sph_gradien[1] return density, potenti, gradien
def get_potl(lmax, nmax, r): """ get the Hernquist potential value inputs lmax : nmax : r : """ p = np.zeros([lmax + 1, nmax, r.size]) zeta = r_to_zeta(r) #fac = 0.25*(1.0 - x*x); #rfac = 0.5*(1.0 - x); for l in range(0, lmax + 1): lfac = -(r**l) / ((1. + r)**(2. * l + 1.)) for n in range(0, nmax): u = eval_gegenbauer(n, 2.0 * l + 1.5, zeta) p[l][n] = lfac * u return p
def test_roots_gegenbauer(): rootf = lambda a: lambda n, mu: sc.roots_gegenbauer(n, a, mu) evalf = lambda a: lambda n, x: sc.eval_gegenbauer(n, a, x) weightf = lambda a: lambda x: (1 - x**2)**(a - 0.5) vgq = verify_gauss_quad vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 5) vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 25, atol=1e-12) vgq(rootf(-0.25), evalf(-0.25), weightf(-0.25), -1., 1., 100, atol=1e-11) vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 5) vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 25, atol=1e-13) vgq(rootf(0.1), evalf(0.1), weightf(0.1), -1., 1., 100, atol=1e-12) vgq(rootf(1), evalf(1), weightf(1), -1., 1., 5) vgq(rootf(1), evalf(1), weightf(1), -1., 1., 25, atol=1e-13) vgq(rootf(1), evalf(1), weightf(1), -1., 1., 100, atol=1e-12) vgq(rootf(10), evalf(10), weightf(10), -1., 1., 5) vgq(rootf(10), evalf(10), weightf(10), -1., 1., 25, atol=1e-13) vgq(rootf(10), evalf(10), weightf(10), -1., 1., 100, atol=1e-12) vgq(rootf(50), evalf(50), weightf(50), -1., 1., 5, atol=1e-13) vgq(rootf(50), evalf(50), weightf(50), -1., 1., 25, atol=1e-12) vgq(rootf(50), evalf(50), weightf(50), -1., 1., 100, atol=1e-11) # Alpha=170 is where the approximation used in roots_gegenbauer changes vgq(rootf(170), evalf(170), weightf(170), -1., 1., 5, atol=1e-13) vgq(rootf(170), evalf(170), weightf(170), -1., 1., 25, atol=1e-12) vgq(rootf(170), evalf(170), weightf(170), -1., 1., 100, atol=1e-11) vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 5, atol=1e-13) vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 25, atol=1e-12) vgq(rootf(170.5), evalf(170.5), weightf(170.5), -1., 1., 100, atol=1e-11) # Test for failures, e.g. overflows, resulting from large alphas vgq(rootf(238), evalf(238), weightf(238), -1., 1., 5, atol=1e-13) vgq(rootf(238), evalf(238), weightf(238), -1., 1., 25, atol=1e-12) vgq(rootf(238), evalf(238), weightf(238), -1., 1., 100, atol=1e-11) vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 5, atol=1e-12) vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 25, atol=1e-11) vgq(rootf(512.5), evalf(512.5), weightf(512.5), -1., 1., 100, atol=1e-10) # this is a special case that the old code supported. # when alpha = 0, the gegenbauer polynomial is uniformly 0. but it goes # to a scaled down copy of T_n(x) there. vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 5) vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 25) vgq(rootf(0), sc.eval_chebyt, weightf(0), -1., 1., 100, atol=1e-12) x, w = sc.roots_gegenbauer(5, 2, False) y, v, m = sc.roots_gegenbauer(5, 2, True) assert_allclose(x, y, 1e-14, 1e-14) assert_allclose(w, v, 1e-14, 1e-14) muI, muI_err = integrate.quad(weightf(2), -1, 1) assert_allclose(m, muI, rtol=muI_err) assert_raises(ValueError, sc.roots_gegenbauer, 0, 2) assert_raises(ValueError, sc.roots_gegenbauer, 3.3, 2) assert_raises(ValueError, sc.roots_gegenbauer, 3, -.75)
def laguerre_wave_function_mom(p, zeta, n, l): """ Brute force fourier transformation of Laguerre function """ xi = zeta * p * 0.5 x = 0.5 / np.sqrt( 0.25 + xi*xi ) r = 0.0 prefact = np.sqrt( zeta * gamma(n+1) * gamma(n+2*l+3) /np.pi ) * (0.5*zeta) * (2*x)**(2*l+3) * (2*xi)**l * gamma(l+1) for k in range(n+1): r += (-1)**k * (k+1) * (2*x)**k * eval_gegenbauer(k+1, l+1, x) / (gamma(n+1-k) * gamma(2*l+3+k) ) return r*prefact
def gegenbauerReconstruction(self, A, N): # np.set_printoptions(precision=3, suppress=True) entireA = np.hstack((A[1:][::-1], A)) n = np.size(entireA) x = self.chebNodes(n=N) k = np.arange(-A.size + 1, A.size) xx, kk = np.meshgrid(x, k) M = np.exp(1j * kk * np.pi * xx).T fx = M.dot(entireA) cfx = self.chebTransform(fx) # gamma = 1 # print(gamma) l = N # l = 4.5 xx, NN = np.meshgrid(x, np.arange(N)) gx = special.eval_gegenbauer(NN, l, xx) # print(gx) cgx = (self.chebTransform(gx.T)).T # print(cgx) wx = np.power(1 - x * x, l - 0.5) cwx = self.chebTransform(wx) cIx = [] for i in range(gx.shape[0]): cIx.append(np_cheb.chebmul(cwx, cgx[i, :])) # print(cgx[i, :]) cIx = np.asarray(cIx) I = [] h = np.sqrt(np.pi) * special.eval_gegenbauer(np.arange(N), l, 1) * special.gamma(l + 0.5) / special.gamma(l) / ( N + l) for it in cIx: I.append(np.real(self.integrate(it, cfx))) I /= h # print(np.array(I)) # print(gx) plt.plot(x, (gx.T).dot(I)) plt.show()
def phi_nl_f(r, n, l): """ Input: ------ r: Particles coordinates n: n l: l Output: ------- phi_nl: The potential basis. Eq.11 Lowing e.a (2011) """ factor = r**l * (1.+r)**(-2.*l-1.) * np.sqrt(4.*np.pi) s = (r-1.)/(r+1.) C_n = special.eval_gegenbauer(n, 2.*l+3./2., s) return -factor*C_n.real
def bfe_density(self): # Eq 13 in Lowing+11 nlist, llist, mlist, Slist, Tlist = self.nlm_list() Knl = 0.5*nlist*(nlist+4*llist+3) + (llist+1)*(2*llist+1) # Factor in the spherical harmonics that to compute as Ylm(theta) = factor*Plm(theta) rho_total = np.zeros(self.nparticles) # Loop over particle positions for k in range(self.nparticles): rho_nl = np.sqrt(4*np.pi) * Knl * self.s[k]**(llist) / (self.s[k]*(1+self.s[k])**(2*llist+3)) / (2*np.pi) # Eq. 10 # Polynomials Ylm = special.sph_harm(mlist, llist, 0, self.theta[k]).real Xi_nl = special.eval_gegenbauer(nlist, 2*llist+1.5, (self.s[k]-1)/(self.s[k]+1)) # Azymuthal component SpT = Slist * np.cos(mlist * self.phi[k]) + Tlist * np.sin(mlist * self.phi[k]) # Sum over n,l,m rho_total[k] = np.sum(rho_nl * Xi_nl * Ylm * SpT) return rho_total * self.M/self.rs**3
def gottliebShu(sig, N, gam=0.25): """ :param sig: numpy.array input signal. :param N: Number of spectral partial sum or number of overtone. :param gam: Positive real constant. """ lam = gam * N # N が大きいと eval_gegenbauerでオーバーフローする。 x = numpy.linspace(-1.0, 1.0, len(sig)) k = numpy.arange(0, int(N / 2)) ggnbr = eval_gegenbauer(numpy.tile(numpy.vstack(k), len(sig)), lam, x) ggnbr_t = numpy.transpose(ggnbr) h_k_lam = numpy.sqrt(numpy.pi) \ * ggnbr_t[-1] \ * gamma(lam + 0.5) / gamma(lam) / (k + lam) g_hat = numpy.sum( numpy.power(1 - x * x, numpy.abs(lam - 0.5)) * sig * ggnbr, axis=1) / h_k_lam return (numpy.sum(g_hat * ggnbr_t, axis=1), g_hat)
def test_gegenbauer_complex_general(self): assert_mpmath_equal(lambda n, a, x: sc.eval_gegenbauer(n.real, a.real, x), _exception_to_nan(mpmath.gegenbauer), [Arg(-1e3, 1e3), Arg(), ComplexArg()])
def test_gegenbauer_complex(self): assert_mpmath_equal(lambda n, a, x: sc.eval_gegenbauer(int(n), a.real, x), _exception_to_nan(mpmath.gegenbauer), [IntArg(0, 100), Arg(), ComplexArg()])
def phiV(u, a1, a2): """Vector meson light-cone distribution amplitude to second order in the Gegenbauer expansion.""" c1 = eval_gegenbauer(1, 3 / 2., 2 * u - 1) c2 = eval_gegenbauer(2, 3 / 2., 2 * u - 1) return 6 * u * (1 - u) * (1 + a1 * c1 + a2 * c2)
def pure_py(xyz, Snlm, Tnlm, nmax, lmax): from scipy.special import lpmv, gegenbauer, eval_gegenbauer, gamma from math import factorial as f def Plm(l, m, costh): return lpmv(m, l, costh) def Ylmth(l, m, costh): return np.sqrt((2*l+1)/(4 * np.pi) * f(l-m)/f(l+m)) * Plm(l, m, costh) twopi = 2*np.pi sqrtpi = np.sqrt(np.pi) sqrt4pi = np.sqrt(4*np.pi) r = np.sqrt(np.sum(xyz**2, axis=0)) X = xyz[2] / r # cos(theta) sinth = np.sqrt(1 - X**2) phi = np.arctan2(xyz[1], xyz[0]) xsi = (r - 1) / (r + 1) density = 0 potenti = 0 gradien = np.zeros_like(xyz) sph_gradien = np.zeros_like(xyz) for l in range(lmax+1): r_term1 = r**l / (r*(1+r)**(2*l+3)) r_term2 = r**l / (1+r)**(2*l+1) for m in range(l+1): for n in range(nmax+1): Cn = gegenbauer(n, 2*l+3/2) Knl = 0.5 * n * (n+4*l+3) + (l+1)*(2*l+1) rho_nl = Knl / twopi * sqrt4pi * r_term1 * Cn(xsi) phi_nl = -sqrt4pi * r_term2 * Cn(xsi) density += rho_nl * Ylmth(l, m, X) * (Snlm[n, l, m]*np.cos(m*phi) + Tnlm[n, l, m]*np.sin(m*phi)) potenti += phi_nl * Ylmth(l, m, X) * (Snlm[n, l, m]*np.cos(m*phi) + Tnlm[n, l, m]*np.sin(m*phi)) # derivatives dphinl_dr = ( 2*sqrtpi*np.power(r, -1 + l)*np.power(1 + r, -3 - 2*l) * (-2*(3 + 4*l)*r*eval_gegenbauer(-1 + n, 2.5 + 2*l, (-1 + r)/(1 + r)) + (1 + r)*(l*(-1 + r) + r)*eval_gegenbauer(n, 1.5 + 2*l, (-1 + r)/(1 + r)))) sph_gradien[0] += dphinl_dr * Ylmth(l, m, X) * (Snlm[n, l, m]*np.cos(m*phi) + Tnlm[n, l, m]*np.sin(m*phi)) A = np.sqrt((2*l+1) / (4*np.pi)) * np.sqrt(gamma(l-m+1) / gamma(l+m+1)) dYlm_dth = A / sinth * (l*X*Plm(l, m, X) - (l+m)*Plm(l-1, m, X)) sph_gradien[1] += (1/r) * dYlm_dth * phi_nl * (Snlm[n, l, m]*np.cos(m*phi) + Tnlm[n, l, m]*np.sin(m*phi)) sph_gradien[2] += (m/(r*sinth)) * phi_nl * Ylmth(l, m, X) * ( -Snlm[n, l, m]*np.sin(m*phi) + Tnlm[n, l, m]*np.cos(m*phi)) cosphi = np.cos(phi) sinphi = np.sin(phi) gradien[0] = sinth*cosphi*sph_gradien[0] + X*cosphi*sph_gradien[1] - sinphi*sph_gradien[2] gradien[1] = sinth*sinphi*sph_gradien[0] + X*sinphi*sph_gradien[1] + cosphi*sph_gradien[2] gradien[2] = X*sph_gradien[0] - sinth*sph_gradien[1] return density, potenti, gradien
def test_gegenbauer_complex_general(self): assert_mpmath_equal( lambda n, a, x: sc.eval_gegenbauer(n.real, a.real, x), _exception_to_nan(mpmath.gegenbauer), [Arg(-1e3, 1e3), Arg(), ComplexArg()])
def test_gegenbauer_complex(self): assert_mpmath_equal( lambda n, a, x: sc.eval_gegenbauer(int(n), a.real, x), _exception_to_nan(mpmath.gegenbauer), [IntArg(0, 100), Arg(), ComplexArg()])
def phiV(u, a1, a2): """Vector meson light-cone distribution amplitude to second order in the Gegenbauer expansion.""" c1 = eval_gegenbauer(1, 3/2., 2*u-1) c2 = eval_gegenbauer(2, 3/2., 2*u-1) return 6*u * (1-u) * (1 + a1 * c1 + a2 * c2)
def bfe_phi_nl(self, n, l, m, s): # Eq. 11 in Lowing # TBD: Check if I'm missing a sqrt(4*pi) phi_s = s**l / (1+s)**(2*l+1) phi_nl = special.eval_gegenbauer(n, 2*l+1.5, (s-1)/(s+1)) return phi_s * phi_nl * np.sqrt(4*np.pi)
def Dln(r, l, n, Rb): rrb = r / Rb return Bln(l, n, Rb) * (np.power(rrb, l) / np.power(1 + (rrb * rrb), l + 2.5)) * eval_gegenbauer( n - 1, l + 1, rescaled_rho(r, Rb))
def Phinlm(self, n,l,m,r,z,phi): #print('now in Phinlm') r, theta = transform(rho = r, z = z) s = r/1. # 1. is in kpc!!!!! return s**l/((1 + s)**(2*l + 1))*eval_gegenbauer(n, 2*l + 3/2, (s - 1)/(s + 1))*np.cos(m*phi)*lpmv(m, l, np.cos(theta))