Beispiel #1
0
def integrand(xi, n, n_p, l):
    """
    Integral to compute the first term in the gof of a BFE.

    \hat{\rho}(x|\gamma)^2

    See Equation 8 in companion notes. 
    """

    factor = (xi + 1)**(2 * l) * (1 - xi)**(2 * l + 3 / 2.)
    gegenbauer1 = special.gegenbauer(n, 2 * l + 3 / 2.)
    gegenbauer2 = special.gegenbauer(n_p, 2 * l + 3 / 2.)

    return factor * gegenbauer1(xi) * gegenbauer2(xi)
Beispiel #2
0
 def compute_eigenvalues(self, mode='envelope'):
     """ Compute the eigenvalues of the integral operator associated with a real valud function of the pairwise distances
     between latent positions """
     self.compute_dimensions_sphere(R=40)
     eigenvalues = []
     beta = (self.d - 2) / 2
     bd = math.gamma(
         self.d / 2) / (math.gamma(1 / 2) * math.gamma(self.d / 2 - 1 / 2))
     for l in range(min(40, len(self.dimensions))):
         Gegen = gegenbauer(l, beta)
         if mode == 'envelope':
             integral = integrate.quad(
                 lambda x: self.compute_envelope(x) * Gegen(x) *
                 (1 - x**2)**(beta - 1 / 2), -1, 1)
         elif mode == 'latitude':
             integral = integrate.quad(
                 lambda x: self.density_latitude(x) * Gegen(x) *
                 (1 - x**2)**(beta - 1 / 2), -1, 1)
         else:
             integral = integrate.quad(
                 lambda x: self.latitude_estimator(x) * Gegen(x) *
                 (1 - x**2)**(beta - 1 / 2), -1, 1)
         cl = (2 * l + self.d - 2) / (self.d - 2)
         eigenvalues.append(cl * bd * integral[0] / self.dimensions[l])
     return eigenvalues
Beispiel #3
0
 def function_gegenbauer(self, t, spectrum):
     """ Returns the value at t of the function with a decomposition 'spectrum' in the gegenbauer basis """
     res = 0
     for i in range(len(spectrum)):
         coeffi = (2 * i + self.d - 2) / (self.d - 2)
         Gegen = gegenbauer(i, (self.d - 2) / 2)
         res += spectrum[i] * coeffi * Gegen(t)
     return res
Beispiel #4
0
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
Beispiel #5
0
def Icom(n, z):
    summation = 0
    for k in range(math.floor(n / 2) + 1):
        l = n - 2 * k
        summation += a(n, k, 3 / 2) * (
            sum([(1. / (l + 2) + 1. / (l + 1) - 2. / (l - j)) *
                 (1 + (-1)**(l - j)) * z**j / 2. for j in range(l)]) +
            (1. / (l + 2) + 1. /
             (l + 1) + 2 * sum([1. / (j + 1) for j in range(l)])) * z**l)
    return 3 * gegenbauer(n, 3 / 2)(z) / 2 - summation
Beispiel #6
0
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
Beispiel #7
0
def scf_compute_coeffs_nbody(pos,mass,N,L,a=1.):
        
        """        
        NAME:

           scf_compute_coeffs

        PURPOSE:

           Numerically compute the expansion coefficients for a given triaxial density

        INPUT:

           pos - Positions of particles
           
           m - mass of particles

           N - size of the Nth dimension of the expansion coefficients

           L - size of the Lth and Mth dimension of the expansion coefficients
           
           a - parameter used to shift the basis functions

           radial_order - Number of sample points of the radial integral. If None, radial_order=max(20, N + 3/2L + 1)

           costheta_order - Number of sample points of the costheta integral. If None, If costheta_order=max(20, L + 1)

           phi_order - Number of sample points of the phi integral. If None, If costheta_order=max(20, L + 1)

        OUTPUT:

           (Acos,Asin) - Expansion coefficients for density dens that can be given to SCFPotential.__init__

        HISTORY:

           2020-11-18 - Written - Morgan Bennett

        """ 
        
        n = numpy.arange(0,N)
        l = numpy.arange(0,L)
        m = numpy.arange(0,L)

        r = numpy.sqrt(pos[0]**2+pos[1]**2+pos[2]**2)
        phi = numpy.arctan2(pos[1],pos[0])
        costheta = pos[2]/r

        Anlm= numpy.zeros([2,L,L,L])
        for i,nn in enumerate(n):
            for j,ll in enumerate(l):
                for k,mm in enumerate(m[:j+1]):

                    Plm= lpmv(mm,ll,costheta)

                    cosmphi= numpy.cos(phi*mm)
                    sinmphi= numpy.sin(phi*mm)

                    Ylm= (numpy.sqrt((2.*ll+1)*gamma(ll-mm+1)/gamma(ll+mm+1))*Plm)[None,:]*numpy.array([cosmphi,sinmphi])
                    Ylm= numpy.nan_to_num(Ylm)

                    C= gegenbauer(nn,2.*ll+1.5)
                    Cn= C((r/a-1)/(r/a+1))

                    phinlm= (-(r/a)**ll/(r/a+1)**(2.*ll+1)*Cn)[None,:]*Ylm

                    Sum= numpy.sum(mass[None,:]*phinlm,axis=1)

                    Knl= 0.5*nn*(nn+4.*ll+3.)+(ll+1)*(2.*ll+1.)
                    Inl= (-Knl*4.*numpy.pi/2.**(8.*ll+6.)*gamma(nn+4.*ll+3.)/gamma(nn+1)/(nn+2.*ll+1.5)/gamma(2.*ll+1.5)**2)

                    Anlm[:,i,j,k]= Inl**(-1)*Sum
        
        return 2.*Anlm
def scf_compute_coeffs_nbody(
    pos,
    mass,
    N,
    L,
    a=1.0,
    radial_order=None,
    costheta_order=None,
    phi_order=None,
):
    """Compute SCF Coefficients

    Numerically compute the expansion coefficients for a given triaxial
    density

    Parameters
    ----------
    pos : (3, N) array
        Positions of particles
    m : scalar or (N,) array
        mass of particles
    N : int
        size of the Nth dimension of the expansion coefficients
    L : int
        size of the Lth and Mth dimension of the expansion coefficients
    a : float or Quantity
        parameter used to shift the basis functions

    Returns
    -------
    Acos, Asin : array
        Expansion coefficients for density dens that can be given to
        ``SCFPotential.__init__``

    .. versionadded:: 1.7
       2020-11-18 - Written - Morgan Bennett

    """
    mass = mass.to_value(1e12 * u.solMass)  # :(
    ns = np.arange(0, N)
    ls = np.arange(0, L)
    ms = np.arange(0, L)

    ra = (np.sqrt(np.sum(np.square(pos), axis=0)) / a).to_value(u.one)
    phi = np.arctan2(pos[1], pos[0])
    costheta = (pos[2] / ra / a).to_value(u.one)

    Anlm = np.zeros([2, N, L, L])
    for i, nn in enumerate(ns):
        for j, ll in enumerate(ls):
            for k, mm in enumerate(ms[:j + 1]):

                Plm = lpmv(mm, ll, costheta)

                cosmphi = np.cos(phi * mm)
                sinmphi = np.sin(phi * mm)

                Ylm = (np.sqrt(
                    (2.0 * ll + 1) * gamma(ll - mm + 1) / gamma(ll + mm + 1), )
                       * Plm)[None, :] * np.array([cosmphi, sinmphi])
                Ylm = np.nan_to_num(Ylm)

                C = gegenbauer(nn, 2.0 * ll + 1.5)
                Cn = C(
                    u.Quantity((ra - 1) / (ra + 1),
                               copy=False).to_value(u.one, ), )

                phinlm = (-np.power(ra, ll) /
                          np.power(ra + 1, (2.0 * ll + 1)) * Cn)[None, :] * Ylm

                Sum = np.sum(mass[None, :] * phinlm, axis=1)

                Knl = 0.5 * nn * (nn + 4.0 * ll + 3.0) + (ll + 1) * (2.0 * ll +
                                                                     1.0)
                Inl = (-Knl * 4.0 * np.pi / 2.0**(8.0 * ll + 6.0) *
                       gamma(nn + 4.0 * ll + 3.0) / gamma(nn + 1) /
                       (nn + 2.0 * ll + 1.5) / gamma(2.0 * ll + 1.5)**2)

                Anlm[:, i, j, k] = Inl**(-1) * Sum

    return 2.0 * Anlm
Beispiel #9
0
def Iexp(n, z):
    return V(n) * gegenbauer(n, 3 / 2)(z)