def _sch_lpmv(n,x): ''' Outputs array of Schmidt Seminormalized Associated Legendre Functions S_{n}^{m} for m<=n. Parameters ---------- n : int Degree of polynomial. x : float Point at which to evaluate Returns ------- array of values for Legendre functions. ''' from scipy.special import lpmv sch=array([1.0]) sch2=array([(-1.0)**m*sqrt((2.0*factorial(n-m))/factorial(n+m)) for m in range(1,n+1)]) sch=append(sch,sch2) if isinstance(x,float) or len(x)==1: leg=lpmv(arange(0,n+1),n,x) return array([sch*leg]).T else: for j in range(0,len(x)): leg=lpmv(range(0,n+1),n,x[j]) if j==0: out=array([sch*leg]).T else: out=append(out,array([sch*leg]).T,axis=1) return out
def _alegendre_deriv(degree, order, val): """Compute the derivative of the associated Legendre polynomial at a value. Parameters ---------- degree : int Degree of spherical harmonic. (Usually) corresponds to 'l' order : int Order of spherical harmonic. (Usually) corresponds to 'm' val : float Value to evaluate the derivative at Returns ------- dPlm : float Associated Legendre function derivative """ from scipy.special import lpmv C = 1 if order < 0: order = abs(order) C = (-1) ** order * factorial(degree - order) / factorial(degree + order) return C * (order * val * lpmv(order, degree, val) + (degree + order) * (degree - order + 1) * np.sqrt(1 - val ** 2) * lpmv(order - 1, degree, val)) / (1 - val ** 2)
def angular_function(self, theta, phi): """Computes the function at angles theta, phi. Parameters ---------- theta : array-like Polar angles, using the physics convention. phi : array-like Azimuthal angle, using the physics convention. """ coefs = self.coefficients result = 0 rank = self.rank for l in range(0, rank+1, 2): for m in range(-l, l+1): j = index_j(l, m) if coefs[j] != 0.0: if m < 0: result += coefs[j] * sqrt(2) \ * sqrt((2*l + 1) * factorial(l + m) \ / (4 * pi * factorial(l - m))) \ * (-1) ** (-m) \ * lpmv(-m, l, cos(theta)) * cos(m * phi) if m == 0: result += coefs[j] \ * sqrt((2*l + 1) * factorial(l - m) \ / (4 * pi * factorial(l + m))) \ * lpmv(m, l, cos(theta)) if m > 0: result += coefs[j] * sqrt(2) \ * sqrt((2*l + 1) * factorial(l - m) \ / (4 * pi * factorial(l + m))) \ * lpmv(m, l, cos(theta)) * sin(m * phi) return result
def NormBaber(aks,bks,m,q): "Computes the normalization constants N and N' of Baber function M!" dsum1=0.0 for l in range(m,len(aks)+m): norm_Plm = 2./(2.*l+1)*special.gamma(l+m+1)/special.gamma(l-m+1) dsum1 += aks[l-m]*bks[l-m]*(-1)**l*norm_Plm x0=0.5 dsuma_0 = sum([aks[l-m]*special.lpmv(m,l,x0) for l in range(m,len(aks)+m)]) dsumb_0 = sum([bks[l-m]*(-1)**l*special.lpmv(m,l,x0) for l in range(m,len(aks)+m)]) Np_over_N = (-1)**m*exp(-2*x0*q)*dsuma_0/dsumb_0 Norma = sqrt(abs(1./(Np_over_N * dsum1))) Normb = Np_over_N * Norma #print 'Np_over_N=', Np_over_N, 'dsuma=', dsuma_0, 'dsumb=', dsumb_0, 'dsum1=', dsum1 return (Norma,Normb)
def spherical_harmonics(m, n, theta, phi): x = np.cos(phi) val = lpmv(m, n, x).astype(complex) val *= np.sqrt((2 * n + 1) / 4.0 / np.pi) val *= np.exp(0.5 * (gammaln(n - m + 1) - gammaln(n + m + 1))) val = val * np.exp(1j * m * theta) return val
def spher_harm_bas(r0, X, Y, Z, order): """ Computes real spherical harmonics on a flattened grid about expansion point r0 = [x0, y0, z0]. Returns: [Y00,Y-11,Y01,Y11,Y-22,Y-12,Y02,Y12,Y22...], rnorm where Yxx is a 1D array of the spherical harmonic evaluated on the grid rnorm is a normalization factor for the spherical harmonics """ # Construct variables from axes; no meshgrid as of 6/4/14; no potential as of 6/12/14 nx,ny,nz=X.shape[0],Y.shape[0],Z.shape[0] x,y,z = np.zeros((nx,ny,nz)),np.zeros((nx,ny,nz)),np.zeros((nx,ny,nz)) x0, y0, z0 = r0 for i in range(nx): for j in range(ny): for k in range(nz): x[i,j,k] = X[i] - x0 y[i,j,k] = Y[j] - y0 z[i,j,k] = Z[k] - z0 x,y,z=np.ravel(x,order='F'),np.ravel(y,order='F'),np.ravel(z,order='F') r,rt=np.sqrt(x*x+y*y+z*z),np.sqrt(x*x+y*y) # Normalize with geometric mean, 3/15/14 (most recently); makes error go down about order of magnitude rsort=np.sort(r) rmin=rsort[1] # first element is 0 rmax=rsort[len(r)-1] rnorm=np.sqrt(rmax*rmin) r=r/rnorm theta,phi=np.zeros(len(r)),np.zeros(len(r)) for i in range(len(z)): theta[i] = mt.atan2(rt[i],z[i]) phi[i] = mt.atan2(y[i],x[i]) # Make the spherical harmonic matrix in sequence of [Y00,Y-11,Y01,Y11,Y-22,Y-12,Y02,Y12,Y22...] Yj = np.zeros((nx*ny*nz,(order+1)**2)) fp = np.sqrt(1/(4*np.pi)) Yj[:,0] = fp*np.sqrt(2) mc = 1 for n in range(1,order+1): for m in range(n+1): ymn = r**n*lpmv(m,n,np.cos(theta)) ymn = fp*ymn*np.sqrt((2*n+1))#/(4*np.pi)) if m==0: Yj[:,mc+n] = ymn else: # Nm is conversion factor to spherical harmonics, # excluding the sqrt(2*n+1/4pi) portion so that there is no coefficient to the m=0 N1 = float(mt.factorial(n-m)) N2 = float(mt.factorial(n+m)) Nm = (-1)**m*np.sqrt(2*N1/N2) psin = Nm*ymn*np.sin(m*phi) pcos = Nm*ymn*np.cos(m*phi) #Yj[:,mc+1+2*(m-1)] = pcos #Yj[:,mc+2+2*(m-1)] = psin Yj[:,mc+n+m] = pcos Yj[:,mc+n-m] = psin mc += 2*n+1 return Yj,rnorm
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 an_P(q, xq, E_1, E_2, R, kappa, a, N): qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 PHI = zeros(len(q)) for K in range(len(q)): rho = sqrt(sum(xq[K]**2)) zenit = arccos(xq[K,2]/rho) azim = arctan2(xq[K,1],xq[K,0]) phi = 0.+0.*1j for n in range(N): for m in range(-n,n+1): P1 = lpmv(abs(m),n,cos(zenit)) Enm = 0. for k in range(len(q)): rho_k = sqrt(sum(xq[k]**2)) zenit_k = arccos(xq[k,2]/rho_k) azim_k = arctan2(xq[k,1],xq[k,0]) P2 = lpmv(abs(m),n,cos(zenit_k)) Enm += q[k]*rho_k**n*factorial(n-abs(m))/factorial(n+abs(m))*P2*exp(-1j*m*azim_k) C2 = (kappa*a)**2*get_K(kappa*a,n-1)/(get_K(kappa*a,n+1) + n*(E_2-E_1)/((n+1)*E_2+n*E_1)*(R/a)**(2*n+1)*(kappa*a)**2*get_K(kappa*a,n-1)/((2*n-1)*(2*n+1))) C1 = Enm/(E_2*E_0*a**(2*n+1)) * (2*n+1)/(2*n-1) * (E_2/((n+1)*E_2+n*E_1))**2 if n==0 and m==0: Bnm = Enm/(E_0*R)*(1/E_2-1/E_1) - Enm*kappa*a/(E_0*E_2*a*(1+kappa*a)) else: Bnm = 1./(E_1*E_0*R**(2*n+1)) * (E_1-E_2)*(n+1)/(E_1*n+E_2*(n+1)) * Enm - C1*C2 phi += Bnm*rho**n*P1*exp(1j*m*azim) PHI[K] = real(phi)/(4*pi) C0 = qe**2*Na*1e-3*1e10/(cal2J) E_P = 0.5*C0*sum(q*PHI) return E_P
def L_fun(theta, l, m): ''' Returns the normalized associated legendre with l,m, and x = cos(theta) ''' if (l+m) >= 170: return np.float64(0.0) else: output = np.sqrt((2*l+1)/(4*math.pi))*\ np.sqrt(np.float64(math.factorial(l-m))/np.float64(math.factorial(l+m))) l_out = lpmv(m,l,np.cos(theta)) return output*l_out
def spherical_harmonics(m, n, theta, phi): """ An implementation of spherical harmonics that overcomes conda compilation issues. See: https://github.com/nipy/dipy/issues/852 """ x = np.cos(phi) val = lpmv(m, n, x).astype(complex) val *= np.sqrt((2 * n + 1) / 4.0 / np.pi) val *= np.exp(0.5 * (gammaln(n - m + 1) - gammaln(n + m + 1))) val = val * np.exp(1j * m * theta) return val
def L_fun(theta, l, m): """ Returns the normalized associated legendre with l,m, and x = cos(theta) """ output = factorial_function(l, m) product = np.sqrt((np.float64(2) * l + np.float64(1)) / (np.float64(4) * math.pi)) * output l_out2 = lpmn(m, np.float64(l), np.cos(theta)) l_out = lpmv(m, np.float64(l), np.cos(theta)) # print l_out, l_out2 return product * l_out
def gradYlm(l, m, pts): pts = numpy.asarray(pts) r, theta, phi = toSph(pts) sinTh = numpy.sin(theta) cosTh = numpy.cos(theta) sinPh = numpy.sin(phi) cosPh = numpy.cos(phi) Nlm = math.sqrt(float((2 * l + 1) * factorial(l - m)) / (4.0 * math.pi * float(factorial(l + m)))) #print "m = ", m, " l = ", l # ============ # The following lines are just for calculating Plm and dPlm, since stupid # scipy won't take m < 0, even though -l <= m <= l are valid mp = abs(m) factor = 1.0 if m < 0: factor = float((-1)**mp * factorial(l - mp)) / float(factorial(l + mp)) plm = lpmv(mp, l, cosTh) if mp == l: dplm = -(l + mp) * (l - mp + 1) * numpy.sqrt(1.0 - cosTh**2) * lpmv(mp - 1, l, cosTh) dplm -= mp * cosTh * plm else: dplm = l * cosTh * plm - (l + mp) * lpmv(mp, l - 1, cosTh) dplm *= factor / (cosTh**2 - 1.0) plm *= factor # done calculating Plm and dPlm # ============== res = numpy.zeros(r.shape + (3, ), dtype = 'complex') res[...,0] = -sinTh * cosTh * cosPh * dplm / r - (1.0j) * m * sinPh * plm / (r * sinTh) res[...,1] = -sinTh * cosTh * sinPh * dplm / r + (1.0j) * m * cosPh * plm / (r * sinTh) res[...,2] = sinTh * sinTh * dplm / r return Nlm * numpy.exp(1.0j * m * phi)[...,numpy.newaxis] * res
def _alegendre_deriv(order, degree, val): """Compute the derivative of the associated Legendre polynomial at a value. Parameters ---------- order : int Order of spherical harmonic. (Usually) corresponds to 'm'. degree : int Degree of spherical harmonic. (Usually) corresponds to 'l'. val : float Value to evaluate the derivative at. Returns ------- dPlm : float Associated Legendre function derivative """ from scipy.special import lpmv assert order >= 0 return (order * val * lpmv(order, degree, val) + (degree + order) * (degree - order + 1.) * np.sqrt(1. - val * val) * lpmv(order - 1, degree, val)) / (1. - val * val)
def _sph_harm(order, degree, az, pol, norm=True): """Evaluate point in specified multipolar moment. [1]_ Equation 4. When using, pay close attention to inputs. Spherical harmonic notation for order/degree, and theta/phi are both reversed in original SSS work compared to many other sources. See mathworld.wolfram.com/SphericalHarmonic.html for more discussion. Note that scipy has ``scipy.special.sph_harm``, but that function is too slow on old versions (< 0.15) for heavy use. Parameters ---------- order : int Order of spherical harmonic. (Usually) corresponds to 'm'. degree : int Degree of spherical harmonic. (Usually) corresponds to 'l'. az : float Azimuthal (longitudinal) spherical coordinate [0, 2*pi]. 0 is aligned with x-axis. pol : float Polar (or colatitudinal) spherical coordinate [0, pi]. 0 is aligned with z-axis. norm : bool If True, include normalization factor. Returns ------- base : complex float The spherical harmonic value. """ from scipy.special import lpmv # Error checks if np.abs(order) > degree: raise ValueError('Absolute value of order must be <= degree') # Ensure that polar and azimuth angles are arrays az = np.asarray(az) pol = np.asarray(pol) if (np.abs(az) > 2 * np.pi).any(): raise ValueError('Azimuth coords must lie in [-2*pi, 2*pi]') if(pol < 0).any() or (pol > np.pi).any(): raise ValueError('Polar coords must lie in [0, pi]') # This is the "seismology" convention on Wikipedia, w/o Condon-Shortley if norm: norm = _sph_harm_norm(order, degree) else: norm = 1. return norm * lpmv(order, degree, np.cos(pol)) * np.exp(1j * order * az)
def sphericalHarmonics(l,m,costh,sinfi,cosfi): import scipy.special as SS # New faster Spherical Harmonics. Checked up to d-orbitals with the Siesta overlap matrix. norm = N.sqrt((2*l+1)/(4*N.pi))*N.sqrt(float(N.math.factorial(l-m))/float(N.math.factorial(l+m))) if m==0: ffi=norm else: expimfi = (cosfi+1.0j*sinfi)**m # Find sin(m fi) and cos(m fi) as im and re parts if m<0: norm = -(-1)**(-m)*N.sqrt(2)*norm ffi = norm * expimfi.imag else: norm = N.sqrt(2)*norm ffi = norm * expimfi.real return SS.lpmv(m,l,costh)*ffi
def createSphrHarm(mu, omega, lMax=8): sphArray = np.zeros((lMax + 1, lMax + 1, len(mu))) for l in range(lMax + 1): for m in range(lMax + 1): # loop over legendre order for i, (mmu, om) in enumerate(zip(mu, omega)): try: C = (2 * l + 1) * float(msc.factorial(l - m)) / \ float(msc.factorial(l + m)) #sphArray[m, l, i] = np.real(C ** (0.5) * spc.lpmv(m, l, mmu) * np.exp(complex(om * m))) sphArray[m, l, i] = np.real(C ** (0.5) * spc.lpmv(m, l, mmu) * np.cos(om * m)) #sphArray[m, l, i] = spc.sph_harm(m, l, mmu, om).real except: pass return sphArray
def _sph_harm(order, degree, az, pol): """Evaluate point in specified multipolar moment. [1]_ Equation 4. When using, pay close attention to inputs. Spherical harmonic notation for order/degree, and theta/phi are both reversed in original SSS work compared to many other sources. See mathworld.wolfram.com/SphericalHarmonic.html for more discussion. Note that scipy has ``scipy.special.sph_harm``, but that function is too slow on old versions (< 0.15) and has a weird bug on newer versions. At some point we should track it down and open a bug report... Parameters ---------- order : int Order of spherical harmonic. (Usually) corresponds to 'm' degree : int Degree of spherical harmonic. (Usually) corresponds to 'l' az : float Azimuthal (longitudinal) spherical coordinate [0, 2*pi]. 0 is aligned with x-axis. pol : float Polar (or colatitudinal) spherical coordinate [0, pi]. 0 is aligned with z-axis. Returns ------- base : complex float The spherical harmonic value at the specified azimuth and polar angles """ from scipy.special import lpmv # Error checks if np.abs(order) > degree: raise ValueError('Absolute value of expansion coefficient must be <= ' 'degree') # Ensure that polar and azimuth angles are arrays az = np.asarray(az) pol = np.asarray(pol) if (az < -2 * np.pi).any() or (az > 2 * np.pi).any(): raise ValueError('Azimuth coords must lie in [-2*pi, 2*pi]') if(pol < 0).any() or (pol > np.pi).any(): raise ValueError('Polar coords must lie in [0, pi]') base = np.sqrt((2 * degree + 1) / (4 * np.pi) * factorial(degree - order) / factorial(degree + order)) * \ lpmv(order, degree, np.cos(pol)) * np.exp(1j * order * az) return base
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 getbr(lats,lons,planet, a, r, Lmax): ph=lons-np.pi th=lats-np.pi/2 costh=np.cos(th) br=np.zeros_like(lats) cosmph=[] sinmph=[] for m in xrange(0,Lmax+1): cosmph.append(np.cos(m*ph)) sinmph.append(np.sin(m*ph)) for L in xrange(1,Lmax+1): for m in xrange(L+1): print "L=",L," m=",m glm=gausscoefficients.gcoeff.get((planet,"g",L,m),0.0) hlm=gausscoefficients.gcoeff.get((planet,"h",L,m),0.0) Glm=gausscoefficients.gcoeff.get((planet,"G",L,m),0.0) Hlm=gausscoefficients.gcoeff.get((planet,"H",L,m),0.0) if(m!=0): schmidt=np.sqrt(2.0*factorial(L-m)/factorial(L+m)) else: schmidt=1.0 legendrep=lpmv(m,L,costh[:,1]) if(L==50 and m==49): print costh[:,1] print legendrep # print costh[:,1] # print "ph=",ph[1,2] # print "ph=",ph[1,2],"m=",m,"cosmph=",cosmph[m][1,2] for i in range(0,np.shape(ph[1,:])[0]): # print np.shape(ph[1,:]) br[:,i]+=(L+1.0)*(((a/r)**(L+2.0))*(glm*cosmph[m][:,i]+hlm*sinmph[m][:,i])+((r/a)**(L))*(Glm*cosmph[m][:,i]+Hlm*sinmph[m][:,i]))*schmidt*legendrep # print cosmph[m][:,i] return br
def test_lpmv(): pts = [] for x in [-0.99, -0.557, 1e-6, 0.132, 1]: pts.extend([ (1, 1, x), (1, -1, x), (-1, 1, x), (-1, -2, x), (1, 1.7, x), (1, -1.7, x), (-1, 1.7, x), (-1, -2.7, x), (1, 10, x), (1, 11, x), (3, 8, x), (5, 11, x), (-3, 8, x), (-5, 11, x), (3, -8, x), (5, -11, x), (-3, -8, x), (-5, -11, x), (3, 8.3, x), (5, 11.3, x), (-3, 8.3, x), (-5, 11.3, x), (3, -8.3, x), (5, -11.3, x), (-3, -8.3, x), (-5, -11.3, x), ]) dataset = [p + (mpmath.legenp(p[1], p[0], p[2]),) for p in pts] dataset = np.array(dataset, dtype=np.float_) evf = lambda mu,nu,x: sc.lpmv(mu.astype(int), nu, x) olderr = np.seterr(invalid='ignore') try: FuncData(evf, dataset, (0,1,2), 3, rtol=1e-10, atol=1e-14).check() finally: np.seterr(**olderr)
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 Get_coef(b,s,order): import numpy as np from scipy import special cof_P = np.zeros((len(b), (order+1)*(order+1))) ms = np.zeros((len(s),4)) for i in range(len(s)): ms[i,:] = np.linspace(s[i], order*s[i], order) i = 0; x = np.sin(b) for n in range(order+1): for m in range(n+1): P = special.lpmv(m,n,x) if m==0: cof_P[:, i] = P*normP(n,m) else: cof_P[:, i] = P*normP(n,m)*np.cos(ms[:,m-1]) i=i+1 cof_P[:, i] = P*normP(n,m)*np.sin(ms[:,m-1]) i=i+1 return cof_P
def spherical_harmonics(m, n, theta, phi): r""" Compute spherical harmonics This may take scalar or array arguments. The inputs will be broadcasted against each other. Parameters ---------- m : int ``|m| <= n`` The order of the harmonic. n : int ``>= 0`` The degree of the harmonic. theta : float [0, 2*pi] The azimuthal (longitudinal) coordinate. phi : float [0, pi] The polar (colatitudinal) coordinate. Returns ------- y_mn : complex float The harmonic $Y^m_n$ sampled at `theta` and `phi`. Notes ----- This is a faster implementation of scipy.special.sph_harm for scipy version < 0.15.0. """ if SCIPY_15_PLUS: return sph_harm(m, n, theta, phi) x = np.cos(phi) val = lpmv(m, n, x).astype(complex) val *= np.sqrt((2 * n + 1) / 4.0 / np.pi) val *= np.exp(0.5 * (gammaln(n - m + 1) - gammaln(n + m + 1))) val = val * np.exp(1j * m * theta) return val
def Plm (x, grado, orden): return special.lpmv(orden, grado, x)
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 _naive_csh_unnormalized(l, m, theta, phi): """ Compute unnormalized SH """ return lpmv(m, l, np.cos(theta)) * np.exp(1j * m * phi)
def evf(mu, nu, x): return sc.lpmv(mu.astype(int), nu, x)
from __future__ import division import numpy as np from scipy.special import lpmv import math cos = np.cos sin = np.sin theta = np.linspace(-np.pi, np.pi, 3) m = np.array([0, 1, 2]) n = np.array([0, 1, 2]) A = lpmv(m, n, cos(theta)) # def legendre_poly(n, m, colatitude): # r'''Calculates the Legendre polynomials through # equation 1-62 of Heiskanen and Moritz(1967) # input > # n, m: int - degree and order of Legendre polynomials # colatitude: array - colatitude coordinates # ''' # colat = np.deg2rad(colatitude) # t = cos(colat) # w1 = (0.5)**n # w2 = np.sqrt((1-t*t)**m) # if type((n-m)/2) == int: # r = int((n-m)/2) # print 1 # else: # r = int((n-m-1)/2) # print 2
def _legendre(n, X): res = [] for m in range(n + 1): res.append(lpmv(m, n, X)) return np.row_stack(res)
def overall(l, m, w, theta, phi): cosstore = normalization(l) * eulers(m, phi) * lpmv(m, l, math.cos(theta)) #may not need to multiply by math.pi again rectstore = normalization(l) * eulers(m, phi) * lpmv(m, l, Rect(theta)) return 2 * math.pi * math.sqrt( (4 * np.pi) / (2 * l + 1)) * cosstore * rectstore
def gscontrol_raw(catd, optcom, n_echos, io_generator, dtrank=4): """ Removes global signal from individual echo `catd` and `optcom` time series This function uses the spatial global signal estimation approach to to removal global signal out of individual echo time series datasets. The spatial global signal is estimated from the optimally combined data after detrending with a Legendre polynomial basis of `order = 0` and `degree = dtrank`. Parameters ---------- catd : (S x E x T) array_like Input functional data optcom : (S x T) array_like Optimally combined functional data (i.e., the output of `make_optcom`) n_echos : :obj:`int` Number of echos in data. Should be the same as `E` dimension of `catd` io_generator : :obj:`tedana.io.OutputGenerator` The output generator for this workflow dtrank : :obj:`int`, optional Specifies degree of Legendre polynomial basis function for estimating spatial global signal. Default: 4 Returns ------- dm_catd : (S x E x T) array_like Input `catd` with global signal removed from time series dm_optcom : (S x T) array_like Input `optcom` with global signal removed from time series """ LGR.info("Applying amplitude-based T1 equilibration correction") RepLGR.info("Global signal regression was applied to the multi-echo " "and optimally combined datasets.") if catd.shape[0] != optcom.shape[0]: raise ValueError( "First dimensions of catd ({0}) and optcom ({1}) do not " "match".format(catd.shape[0], optcom.shape[0])) elif catd.shape[1] != n_echos: raise ValueError("Second dimension of catd ({0}) does not match " "n_echos ({1})".format(catd.shape[1], n_echos)) elif catd.shape[2] != optcom.shape[1]: raise ValueError("Third dimension of catd ({0}) does not match " "second dimension of optcom " "({1})".format(catd.shape[2], optcom.shape[1])) # Legendre polynomial basis for denoising bounds = np.linspace(-1, 1, optcom.shape[-1]) Lmix = np.column_stack([lpmv(0, vv, bounds) for vv in range(dtrank)]) # compute mean, std, mask local to this function # inefficient, but makes this function a bit more modular Gmu = optcom.mean(axis=-1) # temporal mean Gmask = Gmu != 0 # find spatial global signal dat = optcom[Gmask] - Gmu[Gmask][:, np.newaxis] sol = np.linalg.lstsq(Lmix, dat.T, rcond=None)[0] # Legendre basis for detrending detr = dat - np.dot(sol.T, Lmix.T)[0] sphis = (detr).min(axis=1) sphis -= sphis.mean() io_generator.save_file(utils.unmask(sphis, Gmask), "gs img") # find time course ofc the spatial global signal # make basis with the Legendre basis glsig = np.linalg.lstsq(np.atleast_2d(sphis).T, dat, rcond=None)[0] glsig = stats.zscore(glsig, axis=None) glsig_df = pd.DataFrame(data=glsig.T, columns=["global_signal"]) io_generator.save_file(glsig_df, "global signal time series tsv") glbase = np.hstack([Lmix, glsig.T]) # Project global signal out of optimally combined data sol = np.linalg.lstsq(np.atleast_2d(glbase), dat.T, rcond=None)[0] tsoc_nogs = ( dat - np.dot(np.atleast_2d(sol[dtrank]).T, np.atleast_2d(glbase.T[dtrank])) + Gmu[Gmask][:, np.newaxis]) io_generator.save_file(optcom, "has gs combined img") dm_optcom = utils.unmask(tsoc_nogs, Gmask) io_generator.save_file(dm_optcom, "removed gs combined img") # Project glbase out of each echo dm_catd = catd.copy() # don't overwrite catd for echo in range(n_echos): dat = dm_catd[:, echo, :][Gmask] sol = np.linalg.lstsq(np.atleast_2d(glbase), dat.T, rcond=None)[0] e_nogs = dat - np.dot( np.atleast_2d(sol[dtrank]).T, np.atleast_2d(glbase.T[dtrank])) dm_catd[:, echo, :] = utils.unmask(e_nogs, Gmask) return dm_catd, dm_optcom
def compute_g(self): #print("G START ============================================") ncomp = ((self.L * 2)**2) * 2 terms = np.zeros(ncomp, dtype=self.dtype) extent = self.domain.extent min_len = min(extent[0], extent[1], extent[2]) bx = np.array((extent[0], 0.0, 0.0)) by = np.array((0.0, extent[1], 0.0)) bz = np.array((0.0, 0.0, extent[2])) for lx in range(2, self.L*2, 2): rc, vc = self._compute_parameters(lx) kappa = self.kappa kappa2 = kappa*kappa maxt = 3 iterset = range(-1 * maxt, maxt+1) for tx in itertools.product(iterset, iterset, iterset): if (tx[0] != 0) or (tx[1] != 0) or (tx[2] != 0): dx = tx[0]*bx + tx[1]*by + tx[2]*bz dispt = self._cart_to_sph(dx) iradius = 1./dispt[0] radius_coeff = iradius ** (lx + 1.) kappa2radius2 = kappa2 * dispt[0] * dispt[0] #mval = list(range(0, lx+1, 2)) mval = list(range(-1*lx, lx+1, 2)) mxval = [abs(mx) for mx in mval] scipy_p = lpmv(mxval, lx, math.cos(dispt[2])) for mxi, mx in enumerate(mval): assert abs(scipy_p[mxi].imag) < 10.**-16 val = self._hfoo(lx, mx) ynm = val * scipy_p[mxi].real * np.cos(mx * dispt[1]) coeff = ynm * radius_coeff * \ gammaincc(lx + 0.5, kappa2radius2) terms[self.re_lm(lx, mx)] += coeff # add increasingly large outer shells until the values converge for shellx in range(maxt, 20): curr = np.copy(terms[self.re_lm(lx,-lx):self.re_lm(lx,lx+1):]) for tx in shell_iterator(shellx): dx = tx[0]*bx + tx[1]*by + tx[2]*bz dispt = self._cart_to_sph(dx) iradius = 1./dispt[0] radius_coeff = iradius ** (lx + 1.) kappa2radius2 = kappa2 * dispt[0] * dispt[0] #mval = list(range(0, lx+1, 2)) mval = list(range(-1*lx, lx+1, 2)) mxval = [abs(mx) for mx in mval] scipy_p = lpmv(mxval, lx, math.cos(dispt[2])) for mxi, mx in enumerate(mval): assert abs(scipy_p[mxi].imag) < 10.**-16 val = self._hfoo(lx, mx) ynm = val * scipy_p[mxi].real * np.cos(mx * dispt[1]) coeff = ynm * radius_coeff * \ gammaincc(lx + 0.5, kappa2radius2) terms[self.re_lm(lx, mx)] += coeff new_vals = terms[self.re_lm(lx,-lx):self.re_lm(lx,lx+1):] err = np.linalg.norm(curr - new_vals, np.inf) if err < self.eps*0.01: # print("g shellx", shellx, 10.**-15) break if shellx == 20: raise RuntimeError('Periodic Boundary Coefficients did' 'not converge, Please file a bug' 'report.') # explicitly extract the "full" contribution from nearby cells # i.e. the case where the real space part included the nearest # neighbours for lx in range(2, self.L*2, 2): for tx in self.exclude_tuples: if (tx[0] != 0) or (tx[1] != 0) or (tx[2] != 0): dx = tx[0]*bx + tx[1]*by + tx[2]*bz dispt = self._cart_to_sph(dx) iradius = 1./dispt[0] radius_coeff = iradius ** (lx + 1.) #mval = list(range(0, lx+1, 2)) mval = list(range(-1*lx, lx+1, 2)) mxval = [abs(mx) for mx in mval] scipy_p = lpmv(mxval, lx, math.cos(dispt[2])) for mxi, mx in enumerate(mval): assert abs(scipy_p[mxi].imag) < 10.**-16 val = math.sqrt(float(math.factorial( lx - abs(mx)))/math.factorial(lx + abs(mx))) ynm = val * scipy_p[mxi].real * np.cos(mx * dispt[1]) coeff = ynm * radius_coeff terms[self.re_lm(lx, mx)] -= coeff return terms
def assoc_legendre_p_boost_(nu, mu, x): # the boost test data is for integer orders only return lpmv(mu, nu.astype(int), x)
def an_P(q, xq, E_1, E_2, R, kappa, a, N): """ It computes the solvation energy according to Kirkwood-1934. Arguments ---------- q : array, charges. xq : array, positions of the charges. E_1 : float, dielectric constant inside the sphere. E_2 : float, dielectric constant outside the sphere. R : float, radius of the sphere. kappa: float, reciprocal of Debye length. a : float, radius of the Stern Layer. N : int, number of terms desired in the polinomial expansion. Returns -------- E_P : float, solvation energy. """ qe = 1.60217646e-19 Na = 6.0221415e23 E_0 = 8.854187818e-12 cal2J = 4.184 PHI = numpy.zeros(len(q)) for K in range(len(q)): rho = numpy.sqrt(numpy.sum(xq[K]**2)) zenit = numpy.arccos(xq[K, 2] / rho) azim = numpy.arctan2(xq[K, 1], xq[K, 0]) phi = 0. + 0. * 1j for n in range(N): for m in range(-n, n + 1): P1 = special.lpmv(numpy.abs(m), n, numpy.cos(zenit)) Enm = 0. for k in range(len(q)): rho_k = numpy.sqrt(numpy.sum(xq[k]**2)) zenit_k = numpy.arccos(xq[k, 2] / rho_k) azim_k = numpy.arctan2(xq[k, 1], xq[k, 0]) P2 = special.lpmv(numpy.abs(m), n, numpy.cos(zenit_k)) Enm += q[k] * rho_k**n * factorial(n - numpy.abs( m)) / factorial(n + numpy.abs(m)) * P2 * numpy.exp( -1j * m * azim_k) C2 = (kappa * a)**2 * get_K(kappa * a, n - 1) / ( get_K(kappa * a, n + 1) + n * (E_2 - E_1) / ((n + 1) * E_2 + n * E_1) * (R / a)**(2 * n + 1) * (kappa * a)**2 * get_K(kappa * a, n - 1) / ((2 * n - 1) * (2 * n + 1))) C1 = Enm / (E_2 * E_0 * a**(2 * n + 1)) * (2 * n + 1) / ( 2 * n - 1) * (E_2 / ((n + 1) * E_2 + n * E_1))**2 if n == 0 and m == 0: Bnm = Enm / (E_0 * R) * (1 / E_2 - 1 / E_1) - Enm * kappa * a / ( E_0 * E_2 * a * (1 + kappa * a)) else: Bnm = 1. / (E_1 * E_0 * R**(2 * n + 1)) * (E_1 - E_2) * ( n + 1) / (E_1 * n + E_2 * (n + 1)) * Enm - C1 * C2 phi += Bnm * rho**n * P1 * numpy.exp(1j * m * azim) PHI[K] = numpy.real(phi) / (4 * pi) C0 = qe**2 * Na * 1e-3 * 1e10 / (cal2J) E_P = 0.5 * C0 * numpy.sum(q * PHI) return E_P
theta and phi should have the same size This test evaluates Legendre Polynomials for L=5 and M = 5 lpmv is a scipy function implementing Legendre polyomials VW VW2 VW3 are 3 implementation of evaluation of vector spherical harmonics """ Nt = 90 Np = 180 th = linspace(0, pi, Nt) # 1 x Nt ph = linspace(0, 2 * pi, Np) # 1 x Np theta = kron(th, ones(Np)) # 1 x Nt*Np = 1 x Ndir phi = kron(ones(Nt), ph) # 1 x Nt*Np = 1 x Ndir L = 5 M = 5 t = indexvsh(5) # K(L,M) x 2 l = t[:, 0] # K(L,M) x 1 m = t[:, 1] # K(L,M) x 1 x = -cos(theta) # 1 x Ndir Pmm1l, Pmp1l = AFLegendre(L, M, x) LG = lpmv(m.reshape(21, 1, 1), l.reshape(1, 21, 1), x.reshape(1, 1, 16200)) V1, W1 = VW(l, m, x, phi, Pmm1l, Pmp1l) V2, W2 = VW2(l, m, x, phi, Pmm1l, Pmp1l) V3, W3 = VW3(l, m, theta, phi)
def P1sin(nmax, theta): """ Create the Legendre function flavors for FF expansion using spherical waves. Note this is not vectorized so is a bit slow, but it handles the special case of theta = 0 and pi. We primarily use the vectorized version (`P1sin_array`), but call this to handle the special cases. See: Calculating Far-Field Radiation Based on FEKO Spherical Wave Coefficients, draft 10 June 2015. Available at pyuvdata/docs/references/Far_field_spherical_FEKO_draft2.pdf This memo gives a full description of the equations implemented here, including descriptions of the approximations and numerical approaches used. In line comments below are helpful reminders, but see the memo for the full detail. Also see Sokolowski, M. et al, "Calibration and Stokes Imaging with Full Embedded Element Primary Beam Model for the Murchison Widefield Array", PASA, 2017 (10.1017/pasa.2017.54) for details specific to the MWA. Parameters ---------- nmax : int Maximum n from FEKO Q1mn and Q2mn, n must be >=1 theta : float The argument of the cosine or sine function used in the associated Legendre functions, in radians. Returns ------- P_sin : array of float P_{n}^{abs(m)}(cos(theta))/sin(theta) with FEKO order M,N. Shape (nmax ** 2 + 2 * nmax). P1 : array of float P_{n}^{abs(m)+1}(cos(theta)) with FEKO order M,N. Shape (nmax ** 2 + 2 * nmax). """ # initialize for nmax, we have 2(1+...+nmax)+nmax=nmax^2+2*nmax long array P_sin = np.zeros((nmax ** 2 + 2 * nmax)) P1 = np.zeros((nmax ** 2 + 2 * nmax)) # theta arguments cos_th = np.cos(theta) sin_th = np.sin(theta) delta_cos = 1e-6 # for slope estimation # step from 1 to nmax for n in range(1, nmax + 1): # legendre P_{n}^{abs(m)=0...n} (cos_th) orders = np.arange(0, n + 1) orders = orders.reshape(n + 1, 1) P = lpmv(orders, n, cos_th) # THESE ARE THE SAME: # legendre(2,0:0.1:0.2) (matlab) # scipy: # a=np.arange(0,3) # a=a.reshape(3,1) # lpmv(b,2,np.arange(0,0.3,0.1)) # P_{n}^{abs(m)+1} (cos_th) Pm1 = np.append(P[1::], 0) Pm1 = Pm1.reshape(len(Pm1), 1) # P_{n}^{abs(m)}(cos_th)/sin_th Pm_sin = np.zeros((n + 1, 1)) # initialize if cos_th == 1: # special treatment depending on m; # for m=0, Pm_sin=inf so, the product m*Pm_sin is zero; # for m=1, we need a substitution # m>=2, value is 0, so initial values are OK # The first approach, to just use the analytical derivative # is not stable for n>~45 # Instead use slope estimate with a small delta_cos # Pn(cos x)/sin x = -dPn(cos_th)/dcos_th Pm_cos_delta_cos = lpmv(orders, n, cos_th - delta_cos) # backward difference Pm_sin[1, 0] = -(P[0] - Pm_cos_delta_cos[0]) / delta_cos elif cos_th == -1: # The first approach, to just use the analytical derivative # is not stable for n>~45 # Instead use slope estimate with a small delta_cos # Pn(cos x)/sin x = -dPn(cos_th)/dcos_th Pm_cos_delta_cos = lpmv(orders, n, cos_th - delta_cos) # forward difference Pm_sin[1, 0] = -(Pm_cos_delta_cos[0] - P[0]) / delta_cos else: Pm_sin = P / sin_th # accumulate Psin and P1 for the m values ind_start = (n - 1) ** 2 + 2 * (n - 1) # start index to populate ind_stop = n ** 2 + 2 * n # stop index to populate # assign P_sin[np.arange(ind_start, ind_stop)] = np.append( np.flipud(Pm_sin[1::, 0]), Pm_sin ) P1[np.arange(ind_start, ind_stop)] = np.append(np.flipud(Pm1[1::, 0]), Pm1) return P_sin, P1
def Ylm(l, m, THETA, PHI): R = np.abs( np.sqrt( (2 * l + 1) / (4 * np.pi * np.prod(np.arange(l + m, l - m, -1)))) * np.exp(1j * m * PHI) * sp.lpmv(m, l, np.cos(THETA))) return R
import numpy as np from scipy.special import lpmv from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("-m", "--m", dest="m") parser.add_argument("-n", "--n", dest="n") args = parser.parse_args() x = np.linspace(-1, 1, 100) m = int(args.m) n = int(args.n) for i in x: print i, lpmv(n, m, i)
def compute_f(self): ncomp = ((self.L * 2)**2) * 2 terms = np.zeros(ncomp, dtype=self.dtype) extent = self.domain.extent ivolume = 1./(extent[0]*extent[1]*extent[2]) gx = np.array((1./extent[0], 0., 0.)) gy = np.array((0., 1./extent[1], 0.)) gz = np.array((0., 0., 1./extent[2])) gxl = np.linalg.norm(gx) gyl = np.linalg.norm(gy) gzl = np.linalg.norm(gz) for lx in range(2, self.L*2, 2): rc, vc = self._compute_parameters(lx) kappa = self.kappa kappa2 = kappa * kappa mpi2okappa2 = -1.0 * (math.pi ** 2.) / kappa2 ll = 6 if int(ceil(vc/gxl)) < ll: vc = gxl*ll nmax = int(ceil(vc/gxl)) #nmax = 1 for hxi in itertools.product(range(- 1*nmax, nmax+1), range(-1*nmax, nmax+1), range(-1*nmax, nmax+1)): hx = hxi[0]*gz + hxi[1]*gy + hxi[2]*gx dispt = self._cart_to_sph(hx) if 10.**-10 < dispt[0] <= vc: exp_coeff = math.exp(mpi2okappa2 * dispt[0] * dispt[0]) #mval = list(range(0, lx+1, 2)) mval = list(range(-1*lx, lx+1, 2)) mxval = [abs(mx) for mx in mval] scipy_p = lpmv(mxval, lx, math.cos(dispt[2])) vhnm2 = ((dispt[0] ** (lx - 2.)) * ((0 + 1.j) ** lx) * \ (math.pi ** (lx - 0.5))).real coeff = vhnm2 * exp_coeff for mxi, mx in enumerate(mval): val = math.sqrt(float(math.factorial( lx - abs(mx)))/math.factorial(lx + abs(mx))) re_exp = np.cos(mx * dispt[1]) * val assert abs(scipy_p[mxi].imag) < 10.**-16 sph_nm = re_exp * scipy_p[mxi].real contrib = sph_nm * coeff terms[self.re_lm(lx, mx)] += contrib.real for lx in range(2, self.L*2, 2): igamma = rgamma(lx + 0.5) * ivolume for mx in range(-1*lx, lx+1, 2): terms[self.re_lm(lx, mx)] *= igamma return terms
def angular_function(theta, phi): f_lm = np.sqrt(np.math.factorial((2*l + 1)*(l-m))/(4*np.pi*np.math.factorial(l+m)))*lpmv(m, l, np.cos(theta)) g_m = np.exp(np.imag(m*phi)) return f_lm, g_m
def check_spherical_symmetry(samp,l,m,tol): """Check for spherical symmetry by Monte Carlo integration of the spherical harmonic Y_lm over the sample, should be zero unless l=m=0""" thetas, phis= numpy.arctan2(samp.R(),samp.z()), samp.phi() assert numpy.fabs(numpy.sum(special.lpmv(m,l,numpy.cos(thetas))*numpy.cos(m*phis))/samp.size-(l==0)*(m==0)) < tol, 'Sample does not appear to be spherically symmetric, fails spherical harmonics test for (l,m) = ({},{})'.format(l,m) return None
def SphericalHarmonics(self): l, m = self.l, self.m norm = np.sqrt((2 * l + 1) * f(l - m) / 4 / np.pi / f(l + m)) phase = np.exp(1j * m * self.Phi) L = lpmv(m, l, np.cos(self.Theta)) return norm * phase * L
scalars=s, colormap=args.cmap, vmin=vmin, vmax=args.vmax) # plot nodal lines if args.nodal_lines: # Get roots of assoc. Legendre polynomials # this seems to work reasonably well. we basically just find zeros for # too many initial guesses, then take the unique solutions. some of # these aren't zeros (because the root-finder fails) so we discard # them. Nroots = l - np.abs(m) + 2 mu = np.cos(np.linspace(0., np.pi, 5 * Nroots)) mu = np.squeeze([fsolve(lambda z: lpmv(m, l, z), mui) for mui in mu]) mu = np.unique(np.around(mu, decimals=13)) mu = np.array([ mui for mui in mu if np.around(lpmv(m, l, mui), decimals=4) == 0. and np.around(np.abs(mui), decimals=4) != 1. ]) node_kw = {'color': (0., 0., 0.), 'line_width': 0.01, 'tube_radius': 0.01} # 'representation':'wireframe'} r = 1.001 # equatorial for mui in mu: x = r * np.sqrt(1. - mui**2) * cos(ph) y = r * np.sqrt(1. - mui**2) * sin(ph) z = r * mui * np.ones(len(th))
#step adjustment results in smoother curve, but sharp decline around 1 consistent #most likely due to the rectangle function (if n <=1, return 1, else return 0) step = np.pi / 192 while l < 3: overtheta = [0, 0, 0] newset = [] angphi = 0 angtheta = 0 sphcoscalc = [] while angtheta <= math.pi / 2: # print("l = : " + str(l)) # print("phi = : " + str(angphi)) # print("theta = : " + str(angtheta)) store1 = lpmv(m, l, math.cos(angtheta)) store2 = lpmv(m, l, Rect(angtheta)) # print("Cosine Legendre function = : " + str(store1.tolist())) # print("Rect Legendre function = : " + str(store2.tolist())) sphcoscalc.append( normalization(l) * eulers(m, angphi) * lpmv(m, l, math.cos(angtheta))) #list index out of range over1 = overall(l, m, w, angtheta, angphi) #print("Cosine and Rectangle Spherical Harmonic Result: " + str(over1)) overtheta.append(over1) #B9 --> coeffcients (flm * kl0 *pl0(cos(theta))) presum = over1 * (normalization(l) * lpmv(m, l, math.cos(angtheta))) print("New presummed value inserted into set at l:" + str(l) + " and theta: " + str(angtheta) + str(presum))
def lpnm_2(n, m, z): if m > n: return 0.0 return sc.lpmv(m, n, z)
def P1sin(nmax, theta): """Create the Legendre function flavors for FF expansion using spherical wave See: Calculating Far-Field Radiation Based on FEKO Spherical Wave Coefficients, draft 10 June 2015 14/07/2015: ATS - using slope estimator for u=1/-1 (forward/backward difference) Input: 1. theta (rad) is the cos\theta or sin\theta arguments 2. nmax is maximum n from FEKO Q1mn and Q2mn, n must be >=1 Output: 1. P_sin: P_{n}^{|m|}(cos\theta)/sin(theta) with FEKO order M,N 1. P1: P_{n}^{|m|+1}(cos\theta) with FEKO order M,N """ # initialize for nmax, we have 2(1+...+nmax)+nmax=nmax^2+2*nmax long array # Rick 16-3-2017 complex128 is a bit overkill here P_sin = np.zeros((nmax ** 2 + 2 * nmax)) P1 = P_sin * 0 # copy # theta arguments u = np.cos(theta) sin_th = np.sin(theta) delu = 1e-6 # for slope estimation # step from 1 to nmax for n in range(1, nmax + 1): # legendre P_{n}^{|m|=0...n} (u) orders = np.arange(0, n + 1) orders = orders.reshape(n + 1, 1) P = lpmv(orders, n, u) # THESE ARE THE SAME: # legendre(2,0:0.1:0.2) (matlab) # scipy: # a=np.arange(0,3) # a=a.reshape(3,1) # lpmv(b,2,np.arange(0,0.3,0.1)) # P_{n}^{|m|+1} (u) Pm1 = np.append(P[1::], 0) # I should just be able to use orders=np.arange(1,n+1), then append zero? Pm1 = Pm1.reshape(len(Pm1), 1) # FIXME: can probably make this and others 1-D # P_{n}^{|m|}(u)/sin_th # Rick 20-12-2016 complex128 is not really needed here.. Pm_sin = np.zeros((n + 1, 1)) # initialize # parameters # l = np.arange(0, n / 2 + 1) if u == 1: # special treatment depending on m; # for m=0, m=0 Pm_sin=inf so, the product m*Pm_sin is zero; # for m=1, we need a substitution # approach 1: based on E-9 in Harrington, this is not stable # for n>~45 # Pm_sin(2,1)=-sum(((-1).^l.*factorial(2.*n-2.*l).*(n-2.*l))... # ./(2.^n.*factorial(l).*factorial(n-l).*factorial(n-2.*l))); # approach 2: based on slope estimate # Pn(cos x)/sin x = -dPn(u)/du Pu_mdelu = lpmv(orders, n, u - delu) Pm_sin[1, 0] = -(P[0] - Pu_mdelu[0]) / delu # backward difference # m>=2, value is 0, so initial values are OK elif u == -1: # approach 1: based on E-9 in Harrington, this is not stable # for n>~45 # Pm_sin(2,1)=-sum(((-1).^l.*factorial(2.*n-2.*l).*(n-2.*l).*(-1).^(n-2.*l-1))... # ./(2.^n.*factorial(l).*factorial(n-l).*factorial(n-2.*l))); # approach 2: based on slope estimate # Pn(cos x)/sin x = -dPn(u)/du Pu_mdelu = lpmv(orders, n, u - delu) Pm_sin[1, 0] = -(Pu_mdelu[0] - P[0]) / delu # forward difference else: Pm_sin = P / sin_th # accumulate Psin and P1 for the m values ind_start = (n - 1) ** 2 + 2 * (n - 1) # start index to populate ind_stop = n ** 2 + 2 * n # stop index to populate # assign P_sin[np.arange(ind_start, ind_stop)] = np.append(np.flipud(Pm_sin[1::, 0]), Pm_sin) P1[np.arange(ind_start, ind_stop)] = np.append(np.flipud(Pm1[1::, 0]), Pm1) return (P_sin, P1)
def W(l, m): return ((factorial(l - m) / factorial(l + m))**0.5) * lpmv(m, l, 0)
def legendre_p_via_assoc_(nu, x): return lpmv(0, nu, x)
def gscontrol_raw(catd, optcom, n_echos, ref_img, dtrank=4): """ Removes global signal from individual echo `catd` and `optcom` time series This function uses the spatial global signal estimation approach to to removal global signal out of individual echo time series datasets. The spatial global signal is estimated from the optimally combined data after detrending with a Legendre polynomial basis of `order = 0` and `degree = dtrank`. Parameters ---------- catd : (S x E x T) array_like Input functional data optcom : (S x T) array_like Optimally combined functional data (i.e., the output of `make_optcom`) n_echos : :obj:`int` Number of echos in data. Should be the same as `E` dimension of `catd` ref_img : :obj:`str` or img_like Reference image to dictate how outputs are saved to disk dtrank : :obj:`int`, optional Specifies degree of Legendre polynomial basis function for estimating spatial global signal. Default: 4 Returns ------- dm_catd : (S x E x T) array_like Input `catd` with global signal removed from time series dm_optcom : (S x T) array_like Input `optcom` with global signal removed from time series """ LGR.info('Applying amplitude-based T1 equilibration correction') if catd.shape[0] != optcom.shape[0]: raise ValueError( 'First dimensions of catd ({0}) and optcom ({1}) do not ' 'match'.format(catd.shape[0], optcom.shape[0])) elif catd.shape[1] != n_echos: raise ValueError('Second dimension of catd ({0}) does not match ' 'n_echos ({1})'.format(catd.shape[1], n_echos)) elif catd.shape[2] != optcom.shape[1]: raise ValueError('Third dimension of catd ({0}) does not match ' 'second dimension of optcom ' '({1})'.format(catd.shape[2], optcom.shape[1])) # Legendre polynomial basis for denoising bounds = np.linspace(-1, 1, optcom.shape[-1]) Lmix = np.column_stack([lpmv(0, vv, bounds) for vv in range(dtrank)]) # compute mean, std, mask local to this function # inefficient, but makes this function a bit more modular Gmu = optcom.mean(axis=-1) # temporal mean Gmask = Gmu != 0 # find spatial global signal dat = optcom[Gmask] - Gmu[Gmask][:, np.newaxis] sol = np.linalg.lstsq(Lmix, dat.T, rcond=None)[0] # Legendre basis for detrending detr = dat - np.dot(sol.T, Lmix.T)[0] sphis = (detr).min(axis=1) sphis -= sphis.mean() utils.filewrite(utils.unmask(sphis, Gmask), 'T1gs', ref_img) # find time course ofc the spatial global signal # make basis with the Legendre basis glsig = np.linalg.lstsq(np.atleast_2d(sphis).T, dat, rcond=None)[0] glsig = stats.zscore(glsig, axis=None) np.savetxt('glsig.1D', glsig) glbase = np.hstack([Lmix, glsig.T]) # Project global signal out of optimally combined data sol = np.linalg.lstsq(np.atleast_2d(glbase), dat.T, rcond=None)[0] tsoc_nogs = dat - np.dot( np.atleast_2d(sol[dtrank]).T, np.atleast_2d( glbase.T[dtrank])) + Gmu[Gmask][:, np.newaxis] utils.filewrite(optcom, 'tsoc_orig', ref_img) dm_optcom = utils.unmask(tsoc_nogs, Gmask) utils.filewrite(dm_optcom, 'tsoc_nogs', ref_img) # Project glbase out of each echo dm_catd = catd.copy() # don't overwrite catd for echo in range(n_echos): dat = dm_catd[:, echo, :][Gmask] sol = np.linalg.lstsq(np.atleast_2d(glbase), dat.T, rcond=None)[0] e_nogs = dat - np.dot( np.atleast_2d(sol[dtrank]).T, np.atleast_2d(glbase.T[dtrank])) dm_catd[:, echo, :] = utils.unmask(e_nogs, Gmask) return dm_catd, dm_optcom
def P1sin_array(nmax, theta): """ Calculate P^abs(m)_n(cos(theta))/sin(theta) and P^(abs(m)+1)_n(cos(theta)). Similar to the "P1sin" function, but calculates for all theta in one go. At the end of the function, patches are made using the original P1sin function to solve the 0/0 issue. Parameters ---------- nmax : int Maximum n from FEKO Q1mn and Q2mn, n must be >=1 theta : array of float The argument of the cosine or sine functions used in the associated Legendre functions, in radians. Returns ------- P_sin : array of float P_{n}^{abs(m)}(cos(theta))/sin(theta) with FEKO order M,N. Shape (nmax ** 2 + 2 * nmax, theta.size). P1 : array of float P_{n}^{abs(m)+1}(cos(theta)) with FEKO order M,N. Shape (nmax ** 2 + 2 * nmax, theta.size). """ cos_th = np.cos(theta) sin_theta = np.sin(theta) # Make sure that we don't divide by 0 (sin(0) = sin(pi) = 0 ) proper results # are inserted at the end of this function. Set to NaN for now sin_theta[(theta == 0) | (theta == np.pi)] = np.NaN # create at forehand P_sin = np.zeros((nmax ** 2 + 2 * nmax, np.size(theta))) P1 = np.zeros((nmax ** 2 + 2 * nmax, np.size(theta))) for n in range(1, nmax + 1): # legendre P_{n}^{abs(m)=0...n} (cos_th) orders = np.arange(0, n + 1) orders = orders.reshape(n + 1, 1) # fetch entire matrix in one go (for a particular n) # in theory, fetching for all n in one go should also be possible P = lpmv(orders, n, cos_th) # P_{n}^{abs(m)+1} (cos_th) Pm1 = np.vstack([P[1::, :], np.zeros((1, np.size(theta)))]) # P_{n}^{abs(m)}(u)/sin_th Pm_sin = P / sin_theta # accumulate Psin and P1 for the m values # start index to populate ind_start = (n - 1) ** 2 + 2 * (n - 1) # stop index to populate ind_stop = n ** 2 + 2 * n # assign P_sin[np.arange(ind_start, ind_stop), :] = np.vstack( [np.flipud(Pm_sin[1::, :]), Pm_sin] ) P1[np.arange(ind_start, ind_stop), :] = np.vstack([np.flipud(Pm1[1::, :]), Pm1]) # fix for theta = 0 and theta = pi # (properly handled in P1sin, so use that function) P_sin[:, theta == 0] = np.array([P1sin(nmax, 0)[0]]).transpose() P_sin[:, theta == np.pi] = np.array([P1sin(nmax, np.pi)[0]]).transpose() return P_sin.transpose(), P1.transpose()
} } } } """ weave.inline(codel, ['Lag', 'x', 'alpha', 'max_n'], type_converters=weave.converters.blitz, compiler = 'gcc') return Lag if __name__ == '__main__': import sys from scipy import special max_n=100 alpha=1. x=10. Lag = Laguerre_dirty(x,alpha,max_n) for n in range(max_n+1): print 'laguerre=', n, special.eval_genlaguerre(n,alpha,x), Lag[n] m=1 max_l=30 x=0.999 Plm = Plmc(x,m,max_l) for il,l in enumerate(range(m,len(Plm)+m)): print 'Plm=', il,l,special.lpmv(m,l,x),Plm[il]
def angular_prob(the, pee): f_lm = np.sqrt(np.math.factorial((2*l + 1)*(l-m))/(4*np.pi*np.math.factorial(l+m)))*lpmv(m, l, np.cos(the)) g_m = np.exp(np.imag(m*pee)) Y_lm = np.outer(g_m, f_lm) return np.abs(Y_lm)**2
This test evaluates Legendre Polynomials for L=5 and M = 5 lpmv is a scipy function implementing Legendre polyomials VW VW2 VW3 are 3 implementation of evaluation of vector spherical harmonics """ Nt = 90 Np = 180 th = linspace(0,pi,Nt) # 1 x Nt ph = linspace(0,2*pi,Np) # 1 x Np theta = kron(th,ones(Np)) # 1 x Nt*Np = 1 x Ndir phi = kron(ones(Nt), ph) # 1 x Nt*Np = 1 x Ndir L = 5 M = 5 t = indexvsh(5) # K(L,M) x 2 l = t[:,0] # K(L,M) x 1 m = t[:,1] # K(L,M) x 1 x = -cos(theta) # 1 x Ndir Pmm1l, Pmp1l = AFLegendre(L, M, x) LG = lpmv(m.reshape(21,1,1),l.reshape(1,21,1),x.reshape(1,1,16200)) V1,W1 = VW(l,m,x,phi,Pmm1l,Pmp1l) V2,W2 = VW2(l,m,x,phi,Pmm1l,Pmp1l) V3,W3 = VW3(l,m,theta,phi)
def constraint_prefactors(m): # Derivative prefactors on parameters if self.derivative_pres is None: if np.any(self.model_type != ['legendre', 'exponential']): derivatives = [] for i in range(self.N): if i <= m - 1: derivatives.append([0] * len(self.x)) for i in range(self.N - m): if self.model_type == 'normalised_polynomial': mth_order_derivative_term = ( self.y[self.pivot_point] / self.x[self.pivot_point]) \ * np.math.factorial(m + i) \ / np.math.factorial(i) * \ (self.x)**i/(self.x[self.pivot_point])**(i + 1) derivatives.append(mth_order_derivative_term) if self.model_type == 'polynomial': mth_order_derivative_term = np.math.factorial(m+i)\ / np.math.factorial(i) * (self.x)**i derivatives.append(mth_order_derivative_term) if self.model_type == 'log_polynomial': mth_order_derivative_term = np.math.factorial(m+i)\ / np.math.factorial(i) * \ np.log10(self.x/self.x[self.pivot_point])**i derivatives.append(mth_order_derivative_term) if self.model_type == 'loglog_polynomial': mth_order_derivative_term = np.math.factorial(m+i)\ / np.math.factorial(i) * np.log10(self.x)**i derivatives.append(mth_order_derivative_term) if self.model_type == 'difference_polynomial': mth_order_derivative_term = np.math.factorial(m+i)\ / np.math.factorial(i) * ( self.x - self.x[self.pivot_point])**i derivatives.append(mth_order_derivative_term) if self.derivative_pres is not None: if self.args is None: derivatives = self.derivative_pres(m, self.x, self.y, self.N, self.pivot_point) if self.args is not None: derivatives = self.derivative_pres(m, self.x, self.y, self.N, self.pivot_point, *self.args) if self.model_type == 'legendre': interval = np.linspace(-0.999, 0.999, len(self.x)) alps = [] for i in range(self.N): alps.append(lpmv(m, i, interval)) alps = np.array(alps) derivatives = [] for h in range(len(alps)): derivatives.append(((alps[h, :] * (-1)**(m)) / (1 - interval**2)**(m / 2))) derivatives = np.array(derivatives) if self.model_type == 'exponential': derivatives = np.empty([self.N, len(self.x)]) for i in range(self.N): for h in range(len(self.x)): derivatives[i, h] = \ self.y[self.pivot_point] * \ (np.exp(-i*self.x[h]/self.x[self.pivot_point])) * \ (-i/self.x[self.pivot_point])**m derivatives = np.array(derivatives) derivatives = np.array(derivatives).astype(np.double) derivatives = matrix(derivatives) if derivatives.size == (len(self.x), self.N): pass else: derivatives = derivatives.T return derivatives
def _cached_lpmv(*args, **kwargs): return lpmv(*args, **kwargs)