def an_spherical(q, xq, E_1, E_2, E_0, R, N): 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): sph1 = special.sph_harm(m,n,zenit,azim) cons1 = rho**n/(E_1*E_0*R**(2*n+1))*(E_1-E_2)*(n+1)/(E_1*n+E_2*(n+1)) cons2 = 4*pi/(2*n+1) 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]) sph2 = conj(special.sph_harm(m,n,zenit_k,azim_k)) phi += cons1*cons2*q[K]*rho_k**n*sph1*sph2 PHI[K] = real(phi)/(4*pi) return PHI
def make2DGammaPlot(params,n=2,index0=[1,-1,0],poleaxis=[1,1,0],number_of_points=50): """ this is to make the gamma plot cross section using the fitted broken bond model """ thetas = numpy.linspace(0,2*numpy.pi,number_of_points) angles = [] energies = [] phis = [] for theta in thetas: phi = scipy.optimize.fsolve(dotProduct,0.8,args=(theta,index0))[0] phis.append(phi) #print theta, phi nvector = [sin(theta)*cos(phi),sin(theta)*sin(phi),cos(theta)] [h,k,l] = nvector energy = fitFunction(nvector,params) #energies.append(energy) angle = numpy.arccos(numpy.dot(poleaxis,[h,k,l])/(numpy.sqrt((h**2+k**2+l**2)*numpy.dot(poleaxis,poleaxis)))) if numpy.dot(numpy.cross([h,k,l],poleaxis),index0) < 0: angle = -1.0*angle #angles.append(angle) #print angle # plot with poleaxis pointing in +y direction exp_r = abs(0.2200912656713*sph_harm(0, 0,theta,phi) + 0.0032670284794418564*sph_harm(0, 4, theta, phi) + 0.00195264*(sph_harm(-4,4,theta,phi)+sph_harm(4,4,theta,phi))- 0.0023674865858444084*sph_harm(0, 6, theta, phi)+0.00442926*(sph_harm(4,6,theta,phi)+sph_harm(-4,6,theta,phi))-0.00211574*sph_harm(0,8,theta,phi)-0.000795321*(sph_harm(-4,8,theta,phi)+sph_harm(4,8,theta,phi))-0.0012122*(sph_harm(-8,8,theta,phi)+sph_harm(8,8,theta,phi))) pylab.plot(energy*sin(angle),energy*cos(angle),'r.') pylab.plot(exp_r*sin(angle),exp_r*cos(angle),'b.')
def combine_ylm_num(l,m1,m2,a,b,phimax=np.pi,thetamax=2*np.pi,num_points=100): '''returns numerical spherical harmonics as [x,y,z],s where x,y,z are cartesian coordinates and s is realvalue of spherical harmonic or orbital\n plot in the following way\n\n Y,s=Y_lm_num(1,1)\n colormap = cm.ScalarMappable( cmap=pl.get_cmap("cool")) fig = pl.figure(1,figsize=(10,10))\n ax = fig.gca(projection='3d')\n surf = ax.plot_surface(*Y, rstride=2, cstride=2, facecolors=colormap.to_rgba(s), \n linewidth=0.5, antialiased=False)\n lim=0.15 \n ax.set_xlabel('x') \n ax.set_ylabel('y') \n ax.set_zlabel('z') \n ax.set_xlim(-lim,lim) \n ax.set_ylim(-lim,lim) \n ax.set_zlim(-lim,lim) \n ax.set_aspect("equal")''' phi = np.linspace(0, phimax, num_points) theta = np.linspace(0, thetamax, num_points) phi, theta = np.meshgrid(phi, theta) s=1/np.sqrt(2)*np.real(a*sph_harm(m1,l,theta,phi)+b*sph_harm(m2,l,theta,phi)) r=np.abs(s)**2 x = r*np.sin(phi) * np.cos(theta) y = r*np.sin(phi) * np.sin(theta) z = r*np.cos(phi) return [x,y,z],s
def Ylm(l, m, theta, phi): """ The definition we use in our code is the one of Greengard. Namely, we have the following expression for Ylm(t,p):: |m| Ylm(t, p) = sqrt((l-|m|)! / (l+|m|)!).P (cos(t)).exp(i.m.p) l The spherical harmonics defined in scipy is (scipy calls "theta" what we consider to be phi and vice-versa):: S Ylm(p, t) = sqrt(2l+1 / 4.pi).Ylm(t, p) if m >= 0 S Ylm(p, t) = (-1)**m.sqrt(2l+1 / 4.pi).Ylm(t, p) if m < 0 """ from scipy.special import sph_harm assert l >= 0 assert abs(m) <= l prefactor = np.sqrt(4.*np.pi / (2.*l+1.)) if m >= 0: return prefactor * sph_harm(m, l, phi, theta) else: return prefactor * np.conjugate(sph_harm(abs(m), l, phi, theta))
def harmonic(m, l, coor): '''Produce m,l spherical harmonic at coarse and fine coordinates''' Harmonic = namedtuple('Harmonic', 'fine coarse') return Harmonic( special.sph_harm(m, l, coor.fine.theta, coor.fine.phi).real, special.sph_harm(m, l, coor.coarse.theta, coor.coarse.phi).real )
def SphericalHarmonics_sum(x,contrib): "Compute the sum of spherical harmonicsExpect input (theta1, phi1,theta2,phi2) and ((A,l1,m1,l2,m2),...)" ampl = 0 for i in range(contrib.shape[0]): #print("A , m1 : ", contrib[i,0], contrib[i,2]) ampl += contrib[i,0]*sph_harm(contrib[i,1],contrib[i,2],x[0],x[1])*sph_harm(contrib[i,3],contrib[i,4],x[2],x[3]) #print("ampl : ",ampl) prob = np.real(ampl* np.conjugate(ampl)) return prob
def get_coeffs_lm_baselines_from_origin(calfile,l,m,freqs = n.array([.1,]),savefolderpath=None): """ This function calculates the coefficients in front of the lm spherical harmonic for the antenna array described in the calfile. The coefficients are determined by the integral of A(l,m)Y(l,m)exp[-i2pi(ul+vm)]dldm. However, this function only loops over the baselines of the antennas with respect to the origin. """ aa = a.cal.get_aa(calfile, n.array([.150])) #get antenna array im = a.img.Img(size=200, res=.5) #make an image of the sky to get sky coords tx,ty,tz = im.get_top(center=(200,200)) #get coords of the zenith? valid = n.logical_not(tx.mask) tx,ty,tz = tx.flatten(),ty.flatten(),tz.flatten() theta = n.arctan(ty/tx) # using math convention of theta=[0,2pi], phi=[0,pi] phi = n.arccos(n.sqrt(1-tx*tx-ty*ty)) #n.set_printoptions(threshold='nan') #print theta,phi #quit() #beam response for an antenna pointing at (tx,ty,tz) with a polarization in x direction #amp = A(theta) in notes amp = aa[0].bm_response((tx,ty,tz),pol='x')**2 na = len(aa.ants) # number of antennas #coefficient array: rows baselines; cols frequencies coeffs = n.zeros([(na*na-na)/2,len(freqs)],dtype=n.complex) # compute normalization for spherical harmonics Ynorm = special.sph_harm(0,0,0,0) # loop through all baselines baselines = n.zeros([(na*na-na)/2,3]) ll=0 for jj in range(1,na): bx,by,bz = aa.get_baseline(0,jj,'z') #the baseline for antennas 0 and jj print 0,jj,[bx,by,bz] baselines[ll] = [bx,by,bz] kk=0 for fq in freqs: #loop over frequencies phs = n.exp(-2j*n.pi*fq * (bx*tx+by*ty+bz*tz)) #fringe pattern Y = n.array(special.sph_harm(m,l,theta,phi))/Ynorm #using math convention of theta=[0,2pi], phi=[0,pi] Y.shape = phs.shape = amp.shape = im.uv.shape amp = n.where(valid, amp, 0) phs = n.where(valid, phs, 0) Y = n.where(valid, Y, 0) # n.set_printoptions(threshold='nan') # print Y # quit() dc_response = n.sum(amp*Y*phs)/n.sum(amp) #this integrates the amplitude * fringe pattern; units mK? print 'dc = ',dc_response jy_response = n.real(dc_response * 100 / C.pspec.jy2T(fq)) # jy2T converts flux density in jansky to temp in mK print '\t',fq, dc_response, jy_response coeffs[ll,kk] = dc_response kk+=1 ll+=1 if savefolderpath!=None: n.savez_compressed('{0}{1}_data_l_{1}_m_{2}'.format(savefolderpath,calfile,l,m),baselines=baselines,frequencies=freqs,coeffs=coeffs) return baselines,freqs,coeffs
def integrand(mu,phi): theta = np.arccos(mu) if ((m1 >= 0) and (m2>=0)): return np.sin(theta) * np.sin(phi) * c1*sph_harm(m1, n1, phi, theta).real * c2*sph_harm(m2, n2, phi, theta).real elif ((m1 >= 0) and (m2<0)): return np.sin(theta) * np.sin(phi) * c1*sph_harm(m1, n1, phi, theta).real * c2*sph_harm(-m2, n2, phi, theta).imag elif ((m1 < 0) and (m2>=0)): return np.sin(theta) * np.sin(phi) * c1*sph_harm(-m1, n1, phi, theta).imag * c2*sph_harm(m2, n2, phi, theta).real elif ((m1 < 0) and (m2<0)): return np.sin(theta) * np.sin(phi) * c1*sph_harm(-m1, n1, phi, theta).imag * c2*sph_harm(-m2, n2, phi, theta).imag
def sph_harm_set(self): """ Calculate the spherical harmonics, provided n parameters (corresponding to nc = (L+1) * (L+2)/2 with L being the maximal harmonic degree for the set of bvecs of the object Note ---- 1. This was written according to the documentation of mrtrix's 'csdeconv'. The following is taken from there: Note that this program makes use of implied symmetries in the diffusion profile. First, the fact the relative signal profile is real implies that it has conjugate symmetry, i.e. Y(l,-m) = Y(l,m)* (where * denotes the complex conjugate). Second, the diffusion profile should be antipodally symmetric (i.e. S(x) = S(-x)), implying that all odd l components should be zero. Therefore, this program only computes the even elements. Note that the spherical harmonics equations used here differ slightly from those conventionally used, in that the (-1)^m factor has been omitted. This should be taken into account in all subsequent calculations. Each volume in the output image corresponds to a different spherical harmonic component, according to the following convention: [0] Y(0,0) [1] Im {Y(2,2)} [2] Im {Y(2,1)} [3] Y(2,0) [4] Re {Y(2,1)} [5] Re {Y(2,2)} [6] Im {Y(4,4)} [7] Im {Y(4,3)} etc... 2. Take heed that it seems that scipy's sph_harm actually has the order/degree in reverse order than the convention used by mrtrix, so that needs to be taken into account in the calculation below """ # Convert to spherical coordinates: r, theta, phi = geo.cart2sphere(self.bvecs[0, self.b_idx], self.bvecs[1, self.b_idx], self.bvecs[2, self.b_idx]) # Preallocate: b = np.empty((self.model_coeffs.shape[-1], theta.shape[0])) i = 0 # Only even order are taken: for order in np.arange(0, self.L + 1, 2): # Go to L, inclusive! for degree in np.arange(-order, order + 1): # In negative degrees, take the imaginary part: if degree < 0: b[i, :] = np.imag(sph_harm(-1 * degree, order, phi, theta)) else: b[i, :] = np.real(sph_harm(degree, order, phi, theta)) i = i + 1 return b
def integrandZ(mu,phi): theta = np.arccos(mu) if ((m1 >= 0) and (m2>=0)): return abs(np.sin(theta) * np.sin(phi)) * c1*sph_harm(m1, n1, phi, theta).real * c2*sph_harm(m2, n2, phi, theta).real #return abs(np.sqrt(1-mu**2) * np.cos(phi)) * c1*sph_harm(m1, n1, phi, theta).real * c2*sph_harm(m2, n2, phi, theta).real elif ((m1 >= 0) and (m2<0)): return abs(np.sin(theta) * np.sin(phi)) * c1*sph_harm(m1, n1, phi, theta).real * c2*sph_harm(-m2, n2, phi, theta).imag elif ((m1 < 0) and (m2>=0)): return abs(np.sin(theta) * np.sin(phi)) * c1*sph_harm(-m1, n1, phi, theta).imag * c2*sph_harm(m2, n2, phi, theta).real elif ((m1 < 0) and (m2<0)): return abs(np.sin(theta) * np.sin(phi)) * c1*sph_harm(-m1, n1, phi, theta).imag * c2*sph_harm(-m2, n2, phi, theta).imag
def populate_instance_response_matrix(self,truncated_nmax=None, truncated_nmin=None,truncated_lmax=None, truncated_lmin=None, usedefault=1): """ Populate the R matrix for the default range of l and n, or or over the range specified above """ if usedefault == 1: truncated_nmax = self.truncated_nmax truncated_nmin = self.truncated_nmin truncated_lmax = self.truncated_lmax truncated_lmin = self.truncated_lmin lms = self.lms kfilter = self.kfilter else: low_k_cutoff = truncated_nmin*self.Deltak high_k_cutoff = truncated_nmax*self.Deltak self.set_instance_k_filter(truncated_nmax=truncated_nmax,truncated_nmin=truncated_nmin) lms = [(l, m) for l in range(truncated_lmin,truncated_lmax+1) for m in range(-l, l+1)] # Initialize R matrix: NY = (truncated_lmax + 1)**2-(truncated_lmin)**2 # Find the indices of the non-zero elements of the filter ind = np.where(self.kfilter>0) # The n index spans 2x that length, 1st half for the cos coefficients, 2nd half # for the sin coefficients NN = 2*len(ind[1]) R_long = np.zeros([NY,NN], dtype=np.complex128) # In case we need n1, n2, n3 at some point...: # n1, n2, n3 = self.kx[ind]/self.Deltak , self.ky[ind]/self.Deltak, self.kz[ind]/self.Deltak k, theta, phi = self.k[ind], np.arctan2(self.ky[ind],self.kx[ind]), np.arccos(self.kz[ind]/self.k[ind]) # We need to fix the 'nan' theta element that came from having ky=0 theta[np.isnan(theta)] = np.pi/2.0 # Get ready to loop over y y = 0 A = [sph_jn(truncated_lmax,ki)[0] for ki in k] # Loop over y, computing elements of R_yn for i in lms: l = i[0] m = i[1] trigpart = np.cos(np.pi*l/2.0) B = np.asarray([A[ki][l] for ki in range(len(k))]) R_long[y,:NN/2] = 4.0 * np.pi * sph_harm(m,l,theta,phi).reshape(NN/2)*B.reshape(NN/2) * trigpart trigpart = np.sin(np.pi*l/2.0) R_long[y,NN/2:] = 4.0 * np.pi * sph_harm(m,l,theta,phi).reshape(NN/2)*B.reshape(NN/2)* trigpart y = y+1 self.R = np.zeros([NY,len(ind[1])], dtype=np.complex128) self.R = np.append(R_long[:,0:len(ind[1])/2], R_long[:,len(ind[1]):3*len(ind[1])/2], axis=1) return
def real_sph_harm(mm, ll, phi, theta): if mm>0: ans = (1./math.sqrt(2)) * \ (ss.sph_harm(mm, ll, phi, theta) + \ ((-1)**mm) * ss.sph_harm(-mm, ll, phi, theta)) elif mm==0: ans = ss.sph_harm(0, ll, phi, theta) elif mm<0: ans = (1./(math.sqrt(2)*complex(0.,1))) * \ (ss.sph_harm(-mm, ll, phi, theta) - \ ((-1)**mm) * ss.sph_harm(mm, ll, phi, theta)) return ans.real
def zdlm(l,m,x2): if l < m: print 'Error:\nabs(m) must be equal or less than l' return None else: # Kinematics q2 = ((2*np.pi/L)**2)*x2 cm_energy = np.sqrt(q2 + m1**2) + np.sqrt(q2 + m2**2) lab_energy = np.sqrt(cm_energy**2+lab_moment**2) alpha = 1.0/2.0*(1.0+(np.square(m1)-np.square(m2))/np.square(cm_energy)) gamma = 1.0 # lab_energy/cm_energy first_term = sum(np.exp(-r2_array+x2)*(1.0/(r2_array-x2))*(r2_array**(l/2.0))*special.sph_harm(m,l,r_azimuthal,r_polar)) print first_term # Calculate the second term if l == 0: second_term = special.sph_harm(0,0,0.0,0.0)*gamma*np.power(np.pi,3.0/2.0) second_term_bracket = 2 * x2 * integrate.quad(integr_second_term,0,1, args = (x2))[0] - 2 * np.exp(x2) second_term *= second_term_bracket else: second_term = 0 print second_term # Calculate the third term wd = np.inner(w_arr,d) t1 = np.exp(I*2*np.pi*alpha*wd) t2 = np.power(gw2_array,l/2.0) t3 = special.sph_harm(m,l,gw_azimuthal,gw_polar) coef_third_term = t1*t2*t3 third_term_r = integrate.quad(integr_third_term_r,0,1, args = (l,gw2_array,x2,coef_third_term))[0] third_term_i = integrate.quad(integr_third_term_i,0,1, args = (l,gw2_array,x2,coef_third_term))[0] third_term = gamma*np.power(I,l)* (third_term_r + I*third_term_i) print third_term total = first_term + second_term + third_term return total # for i in xrange(len(x2_forplot)): # y_forplot[i] = zdlm(0,0,x2_forplot[i]) # print i
def __call__(self, coords): from scipy.special import sph_harm theta, phi = cart_to_polar_angles(coords) if self.m == 0: return (sph_harm(self.m, self.l, phi, theta)).real vplus = sph_harm(abs(self.m), self.l, phi, theta) vminus = sph_harm(-abs(self.m), self.l, phi, theta) value = np.sqrt(1/2.0) * (self._posneg*vplus + vminus) if self.m < 0: return -value.imag else: return value.real
def real_spherical_harmonic( theta, phi, l, m): assert( m <= l ) assert( l >= 0. ) if m==0: val = sph_harm(m, l, phi, theta) return val.real elif m < 0: val = 1.0j/np.sqrt(2.) * (sph_harm(m,l,phi, theta) - np.power(-1., m ) * sph_harm(-m, l, phi, theta) ) return val.real elif m > 0: val = 1.0/np.sqrt(2.) * (sph_harm(-m,l,phi, theta) + np.power(-1., m ) * sph_harm(m, l, phi, theta) ) return val.real
def spherical_harmonic_real_scipy(l, m, theta, phi): """ real spherical harmonics of degree l and order m """ # note that the definition of `sph_harm` has a different convention for the # usage of the variables phi and theta if m > 0: return (sph_harm(m, l, phi, theta) + (-1)**m * sph_harm(-m, l, phi, theta) ).real / math.sqrt(2) elif m == 0: return sph_harm(0, l, phi, theta).real else: # m < 0 return ((sph_harm(-m, l, phi, theta) - (-1)**m * sph_harm(m, l, phi, theta) ) / csqrt(-2)).real
def spH(): for l in range(4): m=0 for theta in np.arange(0,2*math.pi,0.01): for phi in np.arange(0,math.pi,0.01): print l ,m, theta, phi, sph_harm(m,l,theta,phi)
def coefficients(x, y, z, mass, n, l, m): """ Input: ------ x: Array of particles x-coordiante y: Array of particles y-coordiante z: Array of particles z-coordinate mass: Array with the mass particles n: n l: l m: m r_s: halo scale length Output: ------- var(a): A float number with the variance of the coefficient (S_nlm, T_nlm) evaluated at n,l,m. """ r = np.sqrt(x**2.0+y**2.0+z**2.0)/r_s N = len(r) theta = np.arccos(z/(r*r_s)) phi = np.arctan2(y,x) Y_lm = special.sph_harm(m,l,0,theta) # scipy notation m,l phi_nl = phi_nl_f(r, n, l) Psi = phi_nl*Y_lm*mass if m==0: dm0=1.0 else: dm0=0.0 Anl = Anl_f(n,l) Snlm=(2.-dm0)*Anl*np.sum(Psi.real*np.cos(m*phi)) Tnlm=(2.-dm0)*Anl*np.sum(Psi.real*np.sin(m*phi)) return Snlm, Tnlm
def multi(self,inorm=0, isym=1): """ calculates the coefficients A_lm for themulti pole expansion """ print "using l_max=",self.lmax bnorm=1.0 for l in range(0,self.lmax+1,2): temp=list() for m in range(l+1): #Do the calculation summ=0 #print "-----------------" for val in self.grid: temp2=sfunc.sph_harm(m,l,val[1],val[0]) summ+=temp2.conjugate()*val[3]*val[5] #Y*_lm(theta,phi)*g(thea,phi)*sin(theta)dphi*dtheta if(l==0 and m==0): bnorm=summ print"normalization factor= ",bnorm temp.append([l,m,summ,summ/bnorm]) #print temp[m] self.alm.append(temp) self.writeCoeff("PYcoeff.dat") print "calcualted coefficients" print "-------------------------------------------"
def harm_P(l, m, beta, alpha): """ Associated Legendre polynomial Arguments ========= l = m = beta = alpha = """ import numpy as np P_lm = np.zeros((len(beta), len(alpha)), dtype='complex') from scipy.special import sph_harm mt, lt, bt, at = [], [], [], [] for i in range(len(beta)): for j in range(len(alpha)): mt.append(m); lt.append(l) bt.append(beta[i]); at.append(alpha[j]) dat = sph_harm(mt, lt, bt, at) k = 0 for i in range(len(beta)): for j in range(len(alpha)): P_lm[i,j] = dat[k] k = k + 1 return P_lm
def GetLegendrePoly(conf, theta, phi): """ leg = GetLegendrePoly(conf, theta, phi) Calculates the Legendre polynomials for all {l,m}, and the angles in theta. Parametres ---------- conf : Config object. theta : 1D double array, containing the theta grid. phi : 1D double array, containing the phi grid. Returns ------- leg : 3D double array, containing legendre polinomials evaluated for different l, m and thetas. """ index_iterator = conf.AngularRepresentation.index_iterator nr_lm = (index_iterator.lmax+1)**2 leg = zeros([nr_lm, len(theta), len(phi)], dtype=complex) print "Legendre ..." for i, lm in enumerate(index_iterator.__iter__()): if mod(i,nr_lm/10)==0: print i * 100. / nr_lm, "%" for j, my_theta in enumerate(theta): leg[i,j,:] = sph_harm(lm.m, lm.l, phi, my_theta) return leg
def testExpansionYlmpow(self): """Test the expansion of Ylm into powers""" for (phi, theta) in [(self.phi + dp, self.theta + dt) for dp in (0., 0.25 * np.pi, 0.5 * np.pi, 0.75 * np.pi) for dt in (0., 0.5 * np.pi, np.pi, 1.5 * np.pi)]: utest, umagn = T3D.powexp(np.array([np.sin(phi) * np.cos(theta), np.sin(phi) * np.sin(theta), np.cos(phi)])) self.assertAlmostEqual(umagn, 1) Ylm0 = np.zeros(T3D.NYlm, dtype=complex) # Ylm as power expansions for lm in range(T3D.NYlm): l, m = T3D.ind2Ylm[lm, 0], T3D.ind2Ylm[lm, 1] Ylm0[lm] = sph_harm(m, l, theta, phi) Ylmexp = np.dot(T3D.Ylmpow[lm], utest) self.assertAlmostEqual(Ylm0[lm], Ylmexp, msg="Failure for Ylmpow " "l={} m={}; theta={}, phi={}\n{} != {}".format(l, m, theta, phi, Ylm0[lm], Ylmexp)) # power expansions in Ylm's for p in range(T3D.NYlm): pYlm = np.dot(T3D.powYlm[p], Ylm0) self.assertAlmostEqual(utest[p], pYlm, msg="Failure for powYlm " "{}; theta={}, phi={}\n{} != {}".format(T3D.ind2pow[p], theta, phi, utest[p], pYlm)) # projection (note that Lproj is not symmetric): so this test ensures that v.u and (proj.v).u # give the same value uproj = np.tensordot(T3D.Lproj[-1], utest, axes=(0, 0)) for p in range(T3D.NYlm): self.assertAlmostEqual(utest[p], uproj[p], msg="Projection failure for " "{}\n{} != {}".format(T3D.ind2pow[p], uproj[p], utest[p]))
def Y_lm(self, theta, phi): """ The angular part of the wavefunction, Y_lm(theta, phi). quantum numbers: l, m """ return sph_harm(self.m, self.l, phi, theta)
def test(theta, m, lmax): Plm = compute_normalized_associated_legendre(m, theta, lmax) Plm_p = sph_harm(m, np.arange(m, lmax + 1), 0, theta)[None, :] if not np.allclose(Plm_p, Plm): print Plm_p print Plm return ok_, np.allclose(Plm_p, Plm)
def sph_harm(m, n, az, el): """Compute spherical harmonics Parameters ---------- m : (int) Order of the spherical harmonic. abs(m) <= n n : (int) Degree of the harmonic, sometimes called l. n >= 0 az: (float) Azimuthal (longitudinal) coordinate [0, 2pi], also called Theta. el : (float) Elevation (colatitudinal) coordinate [0, pi], also called Phi. Returns ------- y_mn : (complex float) Complex spherical harmonic of order m and degree n, sampled at theta = az, phi = el """ return scy.sph_harm(m, n, az, el)
def real_sph_harm(ll, mm, phi, theta): """ The real-valued spherical harmonics (adapted from van Haasteren's piccard code) """ if mm > 0: ans = (1.0 / math.sqrt(2)) * (ss.sph_harm(mm, ll, phi, theta) + ((-1) ** mm) * ss.sph_harm(-mm, ll, phi, theta)) elif mm == 0: ans = ss.sph_harm(0, ll, phi, theta) elif mm < 0: ans = (1.0 / (math.sqrt(2) * complex(0.0, 1))) * ( ss.sph_harm(-mm, ll, phi, theta) - ((-1) ** mm) * ss.sph_harm(mm, ll, phi, theta) ) return ans.real
def test_spherical_conversions(): """Test spherical harmonic conversions.""" # Test our real<->complex conversion functions az, pol = np.meshgrid(np.linspace(0, 2 * np.pi, 30), np.linspace(0, np.pi, 20)) for degree in range(1, int_order): for order in range(0, degree + 1): sph = sph_harm(order, degree, az, pol) # ensure that we satisfy the conjugation property assert_allclose(_sh_negate(sph, order), sph_harm(-order, degree, az, pol)) # ensure our conversion functions work sph_real_pos = _sh_complex_to_real(sph, order) sph_real_neg = _sh_complex_to_real(sph, -order) sph_2 = _sh_real_to_complex([sph_real_pos, sph_real_neg], order) assert_allclose(sph, sph_2, atol=1e-7)
def powerSpectrum(records, lmax=40): import scipy.special as spe print '~'*50 print records print '~'*50 key = 'bParts' power = np.zeros(shape=(lmax, len(records))) for iRecord, rec in enumerate(records): es = [rec[key][ii][1] for ii in range(rec['nParts'])] cosTs = [rec[key][ii][2] for ii in range(rec['nParts'])] phis = [rec[key][ii][3] for ii in range(rec['nParts'])] thetas = np.arccos(cosTs) phis = np.array(phis) es = np.array(es) #es /= np.sum(es*es) es /= math.sqrt(np.sum(es*es)) for ll in range(lmax): for mm in range(-ll, ll+1): #note scipy takes opposite unit names from Physics #phi (in scipy) is angle from z-axis flm = np.sum( spe.sph_harm(mm, ll, phis, thetas) * es) #flm = np.sum(np.sin(thetas) * spe.sph_harm(mm, ll, phis, thetas) * es) power[ll,iRecord] += np.abs(flm + np.conj(flm)) power = np.sqrt(power) return power
def real_sph_harm(mm, ll, phi, theta): """ The real-valued spherical harmonics. """ if mm>0: ans = (1./math.sqrt(2)) * \ (ss.sph_harm(mm, ll, phi, theta) + \ ((-1)**mm) * ss.sph_harm(-mm, ll, phi, theta)) elif mm==0: ans = ss.sph_harm(0, ll, phi, theta) elif mm<0: ans = (1./(math.sqrt(2)*complex(0.,1))) * \ (ss.sph_harm(-mm, ll, phi, theta) - \ ((-1)**mm) * ss.sph_harm(mm, ll, phi, theta)) return ans.real
def angular_function(j, theta, phi): """ Returns the values of the spherical harmonics function at given positions specified by colatitude and aximuthal angles. Parameters ---------- j : int The spherical harmonic index. theta : array-like, shape (K, ) The colatitude angles. phi : array-like, shape (K, ) The azimuth angles. Returns ------- f : array-like, shape (K, ) The value of the function at given positions. """ l = sh_degree(j) m = sh_order(j) # We follow here reverse convention about theta and phi w.r.t scipy. sh = sph_harm(np.abs(m), l, phi, theta) if m < 0: return np.sqrt(2) * sh.real if m == 0: return sh.real if m > 0: return np.sqrt(2) * sh.imag
def inverseSphericalHarmonicTransform(coeffs, envmap_height=512, format_='latlong', reduction_type='right'): """ Recovers an EnvironmentMap from a list of coefficients. """ degrees = np.asscalar(np.sqrt(coeffs.shape[0]).astype('int')) - 1 coeffs = addRedundantCoeffs(coeffs, reduction_type)[..., np.newaxis] ch = coeffs.shape[1] if len(coeffs.shape) > 0 else 1 retval = EnvironmentMap(envmap_height, format_) retval.data = np.zeros((retval.data.shape[0], retval.data.shape[1], ch), dtype=np.float32) x, y, z, valid = retval.worldCoordinates() theta = np.arctan2(x, -z) phi = np.arccos(y) for l in range(degrees + 1): for col, m in enumerate(range(-l, l + 1)): Y = sph_harm(m, l, theta, phi) for c in range(ch): retval.data[..., c] += (coeffs[l**2+col, c]*Y).real return retval
def sph_c(xyz, l, m=None): ''' Complex spherial harmonics including the Condon-Shortley phase. https://en.wikipedia.org/wiki/Table_of_spherical_harmonics#Spherical_harmonics input: xyz: cartesian coordinate of shape [n, 3] ''' xyz = np.asarray(xyz, dtype=float) if xyz.ndim == 1: xyz = xyz[None, :] if m: assert -l <= m <= l, "'m' must be in the range of [{},{}]".format(-l, l) r, phi, theta = cart2sph(xyz) N = xyz.shape[0] ylm = [sph_harm(M, l, phi, theta) for M in range(-l, l+1)] if m is None: return np.array(ylm, dtype=complex).T else: return np.array(ylm, dtype=complex).T[:, m+l]
def shd_nm(channels, n, m): """ Calculate the n-the order, m-th degree SHD coefficients for the given Eigenmike em32 channels :param channels: 32 channels of audio from Eigenmike em32 :param n: SHD coefficient order :param m: SHD coefficient degree :return: Non-equalised SHD coefficients (p_nm) for the given em32 recording """ em32 = mc.EigenmikeEM32() estr = em32.returnAsStruct() wts = estr['weights'] ths = estr['thetas'] phs = estr['phis'] pnm = np.zeros(np.shape(channels[0])) * 1j for ind in range(32): cq = channels[ind] wq = wts[ind] tq = ths[ind] pq = phs[ind] Ynm = spec.sph_harm(m, n, pq, tq) pnm += wq * cq * np.conj(Ynm) return pnm
def real_sph_harmonic(j, m, theta, phi): """ Evaluate a real spherical harmonic :param j: The order of the spherical harmonic. These must satisfy |m| < j. :param m: The degree of the spherical harmonic. These must satisfy |m| < j. :param theta: The spherical coordinates of the points at which we want to evaluate the real spherical harmonic. `theta` is the latitude between 0 and pi :param phi: The spherical coordinates of the points at which we want to evaluate the real spherical harmonic. `phi` is the longitude, between 0 and 2*pi :return: The real spherical harmonics evaluated at the points (theta, phi). """ abs_m = abs(m) y = sph_harm(abs_m, j, phi, theta) if m < 0: y = np.sqrt(2) * np.imag(y) elif m > 0: y = np.sqrt(2) * np.real(y) else: y = np.real(y) return y
def sph_harm_array(N, theta, phi, sh_type='real'): # Q = np.max(phi.shape)*theta.shape[np.argmin(phi.shape)] # find number of angles if isinstance(theta, float) or isinstance(theta, int): Q = 1 else: Q = len(theta) Y_mn = np.zeros([Q, (N+1)**2], dtype=complex) for i in range((N+1)**2): # trick from ambiX paper n = np.floor(np.sqrt(i)) m = i - (n**2) - n Y_mn[:,i] = sp.sph_harm(m, n, theta, phi).reshape(1,-1) if sh_type == 'real': Y_mn = np.real((C(N) @ Y_mn.T).T) return np.array(Y_mn)
def sphericalHarmonicTransform(envmap, degrees=None, reduction_type='right'): """ Performs a Spherical Harmonics Transform of `envmap` up to `degree`. """ ch = envmap.data.shape[2] if len(envmap.data.shape) > 2 else 1 if degrees is None: degrees = np.ceil(np.maximum(envmap.shape) / 2.) retval = np.zeros(((degrees + 1)**2, ch), dtype=np.complex) f = envmap.data * envmap.solidAngles()[:, :, np.newaxis] x, y, z, valid = envmap.worldCoordinates() theta = np.arctan2(x, -z) phi = np.arccos(y) for l in tqdm(range(degrees + 1)): for col, m in enumerate(range(-l, l + 1)): Y = sph_harm(m, l, theta, phi) for c in range(ch): retval[l**2 + col, c] = np.nansum(Y * f[:, :, c]) return removeRedundantCoeffs(retval, reduction_type)
def analyse(self, values): """Perform a spherical harmonic transform given a grid and a set of values Arguments: values -- set of complex scalar function values associated with grid points """ if self._shtns: desired_shape = self._shtns.spat_shape[::-1] return self._shtns.analys_cplx( np.array( values, dtype=np.complex128).reshape(desired_shape).transpose()) coefficients = np.zeros((self.l_max + 1) * (self.l_max + 1), dtype=np.complex128) lm = 0 grid = self.grid for l in range(0, self.l_max + 1): for m in range(-l, l + 1): vals = np.conj(sph_harm(m, l, grid[:, 0], grid[:, 1])) vals *= values coefficients[lm] = integrate_values(grid, vals) lm += 1 return coefficients
def _steinhardt_pars(vecs, l_channels, compute_W=False, weights=None): """Compute the Steinhardt bond order parameters (Q and optionally W)""" Qlm = [] Q = np.zeros(len(l_channels)) W = np.zeros(len(l_channels)) # Translate vectors in polar form vecs = np.array(vecs) / np.linalg.norm(vecs, axis=1)[:, None] pols = np.array( [np.arccos(vecs[:, 2]), np.arctan2(vecs[:, 1], vecs[:, 0])]).T # What about weights? if weights is None: weights = np.ones(vecs.shape[0]) / len(vecs) for i, l in enumerate(l_channels): mvals = np.arange(-l, l + 1) Qlm.append( np.sum(sph_harm(mvals[None, :], l, pols[:, 1, None], pols[:, 0, None]) * weights[:, None], axis=0)) Qsum = np.sum(np.conj(Qlm[i]) * Qlm[i]) Q[i] = np.abs(np.sqrt(Qsum * 4 * np.pi / (2 * l + 1.0))) if compute_W: m1, m2, m3 = _valid_triples(l).T ls = np.array([l] * len(m1)) w3j = wigner_3j(ls, m1, ls, m2, ls, m3) W[i] = np.abs( np.sum(w3j * Qlm[i][m1 + l] * Qlm[i][m2 + l] * Qlm[i][m3 + l]) / (Qsum)**1.5) if not compute_W: return Q else: return Q, W
def Plot(self): #Clear figure plt.clf() #Read in m and l m = int(self.Entm.get()) l = int(self.Entl.get()) #Define phi and theta theta = np.linspace(0, np.pi, 101) phi = np.linspace(0, 2 * np.pi, 101) theta, phi = np.meshgrid(theta, phi) #Calculate scalar spherical harmonic Y = scp.sph_harm(m, l, phi, theta) if self.ComplexPartBox.get() == 'Real': Y = Y.real elif self.ComplexPartBox.get() == 'Imag': Y = Y.imag elif self.ComplexPartBox.get() == 'Mod': Y = np.sqrt(Y.real**2 + Y.imag**2) #Normalize to between 0 - 1 Y_norm = (Y - Y.min()) / (Y.max() - Y.min()) #Convert to Cartesian x = np.sin(theta) * np.cos(phi) y = np.sin(theta) * np.sin(phi) z = np.cos(theta) #Setup plot for 3D surface ax = self.Fig.gca(projection='3d') ax.plot_surface(x, y, z, rstride=1, cstride=1, facecolors=cm.seismic(Y_norm)) #Plot ax.set_axis_off() plt.gcf().canvas.draw()
def __init__(self, sh_order, gradients, lb_lambda=0.006): super(Signal2SH, self).__init__() self.sh_order = sh_order self.lb_lambda = lb_lambda self.num_gradients = gradients.shape[0] self.num_coefficients = int( (self.sh_order + 1) * (self.sh_order / 2 + 1)) b = np.zeros((self.num_gradients, self.num_coefficients)) l = np.zeros((self.num_coefficients, self.num_coefficients)) for id_gradient in range(self.num_gradients): id_column = 0 for id_order in range(0, self.sh_order + 1, 2): for id_degree in range(-id_order, id_order + 1): gradients_phi, gradients_theta, gradients_z = cart2sph( gradients[id_gradient, 0], gradients[id_gradient, 1], gradients[id_gradient, 2]) y = sci.sph_harm(np.abs(id_degree), id_order, gradients_phi, gradients_theta) if id_degree < 0: b[id_gradient, id_column] = np.real(y) * np.sqrt(2) elif id_degree == 0: b[id_gradient, id_column] = np.real(y) elif id_degree > 0: b[id_gradient, id_column] = np.imag(y) * np.sqrt(2) l[id_column, id_column] = self.lb_lambda * id_order**2 * (id_order + 1)**2 id_column += 1 b_inv = np.linalg.pinv(np.matmul(b.transpose(), b) + l) self.Signal2SHMat = torch.nn.Parameter(torch.from_numpy( np.matmul(b_inv, b.transpose()).transpose()).float(), requires_grad=False)
def spherical_harm(m, l, theta, phi): r""" Calculate the spherical harmonics using :math:`Y_l^m(\theta, \varphi)` with :math:`\mathbf R\to \{r, \theta, \varphi\}`. .. math:: Y^m_l(\theta,\varphi) = (-1)^m\sqrt{\frac{2l+1}{4\pi} \frac{(l-m)!}{(l+m)!}} e^{i m \theta} P^m_l(\cos(\varphi)) which is the spherical harmonics with the Condon-Shortley phase. Parameters ---------- m : int order of the spherical harmonics l : int degree of the spherical harmonics theta : array_like angle in :math:`x-y` plane (azimuthal) phi : array_like angle from :math:`z` axis (polar) """ # Probably same as: #return (-1) ** m * ( (2*l+1)/(4*pi) * factorial(l-m) / factorial(l+m) ) ** 0.5 \ # * lpmv(m, l, cos(theta)) * exp(1j * m * phi) return sph_harm(m, l, theta, phi) * (-1) ** m
def WaveFunction(x, y, z, n, l, m): # theta is azimuthal angle and phi is polar angle r, phi, theta = CoordinateConverter(x, y, z) # a is the Bohr radius in angstroms a = .529 spherical = special.sph_harm(m, n, theta, phi) LaguerreOrder = 2 * l + 1 LaguerrePoint = (2 * r) / (n * a) laguerre = special.assoc_laguerre(LaguerreOrder, LaguerrePoint) radial = sqrt( (2 / (n * a))**3 * (float(factorial(n - l - 1)) / (float(2 * n * (factorial(n + l))**3)))) * exp(-r / (n * a)) * ((2 * r) / (n * a))**l value = radial * laguerre * spherical probability = abs(value)**2 return probability
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
from scipy.special import sph_harm import numpy as np x = 1 y = 1 z = 1 rxy2 = x * x + y * y rxy = np.sqrt(rxy2) r2 = rxy2 + z * z r = np.sqrt(r2) sinTheta = rxy / r cosTheta = z / r sinPsi = x / rxy cosPsi = y / rxy print("Y6m:") for i in range(-6, 7): print(sph_harm(i, 6, np.arccos(cosPsi), np.arccos(cosTheta))) print("Y4m:") for i in range(-4, 5): print(sph_harm(i, 4, np.arccos(cosPsi), np.arccos(cosTheta)))
r = 0.3 pi = np.pi cos = np.cos sin = np.sin phi, theta = np.mgrid[0:pi:101j, 0:2 * pi:101j] x = r * sin(phi) * cos(theta) y = r * sin(phi) * sin(theta) z = r * cos(phi) mlab.figure(1, bgcolor=(1, 1, 1), fgcolor=(0, 0, 0), size=(400, 300)) mlab.clf() # Represent spherical harmonics on the surface of the sphere for n in range(1, 6): for m in range(n): s = sph_harm(m, n, theta, phi).real mlab.mesh(x - m, y - n, z, scalars=s, colormap='jet') s[s < 0] *= 0.97 s /= s.max() mlab.mesh(s * x - m, s * y - n, s * z + 1.3, scalars=s, colormap='Spectral') mlab.view(90, 70, 6.2, (-1.3, -2.9, 0.25)) mlab.show()
def populate_instance_response_matrix(self, truncated_nmax=None, truncated_nmin=None, truncated_lmax=None, truncated_lmin=None, usedefault=1): """ Populate the R matrix for the default range of l and n, or or over the range specified above """ if usedefault == 1: truncated_nmax = self.truncated_nmax truncated_nmin = self.truncated_nmin truncated_lmax = self.truncated_lmax truncated_lmin = self.truncated_lmin lms = self.lms kfilter = self.kfilter else: low_k_cutoff = truncated_nmin * self.Deltak high_k_cutoff = truncated_nmax * self.Deltak self.set_instance_k_filter(truncated_nmax=truncated_nmax, truncated_nmin=truncated_nmin) lms = [(l, m) for l in range(truncated_lmin, truncated_lmax + 1) for m in range(-l, l + 1)] # Initialize R matrix: NY = (truncated_lmax + 1)**2 - (truncated_lmin)**2 # Find the indices of the non-zero elements of the filter ind = np.where(self.kfilter > 0) # The n index spans 2x that length, 1st half for the cos coefficients, 2nd half # for the sin coefficients NN = 2 * len(ind[1]) R_long = np.zeros([NY, NN], dtype=np.complex128) # In case we need n1, n2, n3 at some point...: # n1, n2, n3 = self.kx[ind]/self.Deltak , self.ky[ind]/self.Deltak, self.kz[ind]/self.Deltak k, theta, phi = self.k[ind], np.arctan2( self.ky[ind], self.kx[ind]), np.arccos(self.kz[ind] / self.k[ind]) # We need to fix the 'nan' theta element that came from having ky=0 theta[np.isnan(theta)] = np.pi / 2.0 # Get ready to loop over y y = 0 A = [sph_jn(truncated_lmax, ki)[0] for ki in k] # Loop over y, computing elements of R_yn for i in lms: l = i[0] m = i[1] trigpart = np.cos(np.pi * l / 2.0) B = np.asarray([A[ki][l] for ki in range(len(k))]) R_long[y, :NN / 2] = 4.0 * np.pi * sph_harm(m, l, theta, phi).reshape( NN / 2) * B.reshape(NN / 2) * trigpart trigpart = np.sin(np.pi * l / 2.0) R_long[y, NN / 2:] = 4.0 * np.pi * sph_harm(m, l, theta, phi).reshape( NN / 2) * B.reshape(NN / 2) * trigpart y = y + 1 self.R = np.zeros([NY, len(ind[1])], dtype=np.complex128) self.R = np.append(R_long[:, 0:len(ind[1]) / 2], R_long[:, len(ind[1]):3 * len(ind[1]) / 2], axis=1) return
def gen_uniform_sample_sph_harm(n_samples, alpha, l, m, NSIDE = 4, savetofile = False, fname ='none'): """ generate a user-defined random number of points on the celestial sphere distributed according to spherical harmonics parameterized by l, m and alpha Parameters ---------- n_samples : int the number of samples to generate alpha: float, array the weight to apply to spherical harmonic i l: int, array the l value for spherical harmonic i m: int, array the m value for spherical harmonic i, limited by l NSIDE: int, must be a power of 2 and no greater than 8 for healpix savetofile: Bool save to file in current directory, true or false fname: string filename to save as, 'none' if savetofile = False Returns ------- numpy ndarray table of RA and DEC in radians sampled from the desired linear combination of spherical harmonics """ x = np.linspace(-np.pi, np.pi, 100) y = np.linspace(-np.pi/2, np.pi/2, 100) X, Y = np.meshgrid(x, y) # Spherical coordinate arrays derived from x, y # Necessary conversions to get Mollweide right phi = x.copy() # physical copy phi[x < 0] = 2 * np.pi + x[x<0] theta = np.pi/2 - y PHI, THETA = np.meshgrid(phi, theta) SH_SP = np.zeros((100,100)) assert len(alpha) == len(l) == len(m) for i in range(len(alpha)): sp_temp = alpha[i]*sph_harm(m[i],l[i], PHI, THETA).real SH_SP = SH_SP+sp_temp #turn the spherical harmonic map into a healpix map hpmap = make_map_vec(THETA, PHI, abs(SH_SP)) theta_out = [] phi_out = [] while len(theta_out)<n_samples: #generate an ra and dec - should be an underlying uniform distribution u = np.random.uniform(0,1) v = np.random.uniform(0,1) ph = 2*np.pi*u th = np.arccos(2*v-1) #calculate the hp index of this theta and phi, and get it's value idx = hp.ang2pix(NSIDE, th, ph) pix_val = hpmap[idx] q = np.random.uniform(min(hpmap), max(hpmap)) print(q) if pix_val>q: theta_out.append(th-np.pi/2) phi_out.append(ph) else: pass c = SkyCoord(ra=phi_out*units.radian, dec=theta_out*units.radian, frame='icrs') ra = c.ra #the sky is weird so wrap the angles at 180 degrees ra = ra.wrap_at(180*units.degree) dec = c.dec out = np.column_stack([ra.radian, dec.radian]) if savetofile==True: if fname == 'none': raise ValueError('invalid file name') else: np.savetxt(fname, out) else: print('generated {} sky direction samples'.format(n_samples)) return out
def compute_alpha(data, l, r_cut, qq_cut): """ Computes alpha for all particles in data. Parameters: data (DataCollection): Ovito class with pipeline computation result. l (int): Spherical Harmonics order for Steinhardt parameter. r_cut (float): radial cutoff for neighbor finder. qq_cut (float): cutoff for product of Steinhardt vectors. Returns: ndarray: value of alpha for each particle. """ natoms = data.particles.count # Total number of atoms. # Compute total number of neighbors of each atom. finder = CutoffNeighborFinder(cutoff=r_cut, data_collection=data) N_neigh = zeros(natoms, dtype=int) for iatom in range(natoms): for neigh in finder.find(iatom): N_neigh[iatom] += 1 N_neigh_total = sum(N_neigh) # Unroll neighbor distances. r_ij = zeros((N_neigh_total, 3)) # Distance vectors to neighbors. d_ij = zeros(N_neigh_total) # Distance to neighbors. neigh_list = zeros(N_neigh_total, dtype=int) # ID of neighbors. ineigh = 0 # Neighbor counter. for iatom in range(natoms): for neigh in finder.find(iatom): r_ij[ineigh] = array(neigh.delta) d_ij[ineigh] = neigh.distance neigh_list[ineigh] = neigh.index ineigh += 1 # Compute spherical harmonics for all neighbors of each atom. phi = arctan2(r_ij[:, 1], r_ij[:, 0]) theta = arccos(r_ij[:, 2] / d_ij) Y = zeros((2 * l + 1, N_neigh_total), dtype=complex) for m in range(-l, l + 1): Y[m + l] = sph_harm(m, l, phi, theta) # Construct Steinhard vector by summing spherical harmonics. q = zeros((natoms, 2 * l + 1), dtype=complex) ineigh = 0 for iatom in range(natoms): q[iatom] = sum(Y[:, ineigh:ineigh + N_neigh[iatom]], axis=1) ineigh += N_neigh[iatom] # Normalization. for m in range(2 * l + 1): q[:, m] /= N_neigh q = (q.T / norm(q, axis=1)).T # Classify bonds as crystal-like or not and compute alpha. alpha = zeros(natoms) # Crystal-like fraction of bonds per atom. ineigh = 0 for iatom in range(natoms): for jatom in neigh_list[ineigh:ineigh + N_neigh[iatom]]: qq = dot(q[iatom], conjugate(q[jatom])).real # Im[qq] always 0. if qq > qq_cut: alpha[iatom] += 1.0 ineigh += 1 alpha /= N_neigh return alpha
import pygmt import numpy as np from scipy.special import sph_harm from numpy.random import random_sample #come up with n random points on a sphere n=10000 x = random_sample(n)-0.5 y = random_sample(n)-0.5 z = random_sample(n)-0.5 lats = np.arccos( z/np.sqrt(x*x+y*y+z*z)) lons = np.arctan2( y, x )+np.pi #evaluate a spherical harmonic on that sphere vals = sph_harm(4,9, lons, lats).real vals = vals/np.amax(vals) lons = lons*180.0/np.pi lats = 90.0-lats*180.0/np.pi #recover the spherical harmonic with contouring fig = pygmt.GMT_Figure("output.ps", figure_range='g', projection='G-75/41/7i', verbosity=2) dataset = fig.blockmean('-I5/5 -Rg', [lons,lats,vals]) grid = fig.surface('-I5/5 -Rg', dataset) c = fig.grd2cpt('-Chot', grid, output=None) fig.grdimage('-E100i', grid, cpt=c) fig.grdcontour('-Wthick,black -C0.2', grid) fig.psxy('-Sp.1c', [lons,lats,vals]) fig.close()
def getLBP3DImage(inputImage, inputMask, **kwargs): """ Compute and return the Local Binary Pattern (LBP) in 3D using spherical harmonics. If ``force2D`` is set to true (= feature extraction in 2D) a warning is logged. LBP is only calculated for voxels segmented in the mask Following settings are possible: - ``lbp3DLevels`` [2]: integer, specifies the the number of levels in spherical harmonics to use. - ``lbp3DIcosphereRadius`` [1]: Float, specifies the radius in which the neighbours should be sampled - ``lbp3DIcosphereSubdivision`` [1]: Integer, specifies the number of subdivisions to apply in the icosphere :return: Yields LBP filtered image for each level, 'lbp-3D-m<level>' and ``kwargs`` (customized settings). Additionally yields the kurtosis image, 'lbp-3D-k' and ``kwargs``. .. note:: LBP can often return only a very small number of different gray levels. A customized bin width is often needed. .. warning:: Requires package ``scipy`` and ``trimesh`` to function. If not available, this filter logs a warning and does not yield an image. References: - Banerjee, J, Moelker, A, Niessen, W.J, & van Walsum, T.W. (2013), "3D LBP-based rotationally invariant region description." In: Park JI., Kim J. (eds) Computer Vision - ACCV 2012 Workshops. ACCV 2012. Lecture Notes in Computer Science, vol 7728. Springer, Berlin, Heidelberg. doi:10.1007/978-3-642-37410-4_3 """ global logger try: from scipy.stats import kurtosis from scipy.ndimage.interpolation import map_coordinates from scipy.special import sph_harm from trimesh.creation import icosphere except ImportError: logger.warning('Could not load required package "scipy" or "trimesh", cannot implement filter LBP 3D') return # Warn the user if features are extracted in 2D, as this function calculates LBP in 3D if kwargs.get('force2D', False): logger.warning('Calculating Local Binary Pattern in 3D, but extracting features in 2D. Use with caution!') label = kwargs.get('label', 1) lbp_levels = kwargs.get('lbp3DLevels', 2) lbp_icosphereRadius = kwargs.get('lbp3DIcosphereRadius', 1) lbp_icosphereSubdivision = kwargs.get('lbp3DIcosphereSubdivision', 1) im_arr = sitk.GetArrayFromImage(inputImage) ma_arr = sitk.GetArrayFromImage(inputMask) # Variables used in the shape comments: # Np Number of voxels # Nv Number of vertices # Vertices icosahedron for spherical sampling coords_icosahedron = numpy.array(icosphere(lbp_icosphereSubdivision, lbp_icosphereRadius).vertices) # shape(Nv, 3) # Corresponding polar coordinates theta = numpy.arccos(numpy.true_divide(coords_icosahedron[:, 2], lbp_icosphereRadius)) phi = numpy.arctan2(coords_icosahedron[:, 1], coords_icosahedron[:, 0]) # Corresponding spherical harmonics coefficients Y_{m, n, theta, phi} Y = sph_harm(0, 0, theta, phi) # shape(Nv,) n_ix = numpy.array(0) for n in range(1, lbp_levels): for m in range(-n, n + 1): n_ix = numpy.append(n_ix, n) Y = numpy.column_stack((Y, sph_harm(m, n, theta, phi))) # shape (Nv, x) where x is the number of iterations in the above loops + 1 # Get labelled coordinates ROI_coords = numpy.where(ma_arr == label) # shape(3, Np) # Interpolate f (samples on the spheres across the entire volume) coords = numpy.array(ROI_coords).T[None, :, :] + coords_icosahedron[:, None, :] # shape(Nv, Np, 3) f = map_coordinates(im_arr, coords.T, order=3) # Shape(Np, Nv) Note that 'Np' and 'Nv' are swapped due to .T # Compute spherical Kurtosis k = kurtosis(f, axis=1) # shape(Np,) # Apply sign function f_centroids = im_arr[ROI_coords] # Shape(Np,) f = numpy.greater_equal(f, f_centroids[:, None]).astype(int) # Shape(Np, Nv) # Compute c_{m,n} coefficients c = numpy.multiply(f[:, :, None], Y[None, :, :]) # Shape(Np, Nv, x) c = c.sum(axis=1) # Shape(Np, x) # Integrate over m f = numpy.multiply(c[:, None, n_ix == 0], Y[None, :, n_ix == 0]) # Shape (Np, Nv, 1) for n in range(1, lbp_levels): f = numpy.concatenate((f, numpy.sum(numpy.multiply(c[:, None, n_ix == n], Y[None, :, n_ix == n]), axis=2, keepdims=True) ), axis=2) # Shape f (Np, Nv, levels) # Compute L2-Norm f = numpy.sqrt(numpy.sum(f ** 2, axis=1)) # shape(Np, levels) # Keep only Real Part f = numpy.real(f) # shape(Np, levels) k = numpy.real(k) # shape(Np,) # Yield the derived images for each level result = numpy.ndarray(im_arr.shape) for l_idx in range(lbp_levels): result[ROI_coords] = f[:, l_idx] # Create a SimpleITK image im = sitk.GetImageFromArray(result) im.CopyInformation(inputImage) yield im, 'lbp-3D-m%d' % (l_idx + 1), kwargs # Yield Kurtosis result[ROI_coords] = k # Create a SimpleITK image im = sitk.GetImageFromArray(result) im.CopyInformation(inputImage) yield im, 'lbp-3D-k', kwargs
def vect2Ylm(v, l): """Projects vectors v on the base of spherical harmonics of degree l.""" spherical = cart2sph(v) return sph_harm( np.arange(l + 1)[:, None], l, spherical[:, 2][None, :], spherical[:, 1][None, :])
from scipy import special import pylab as p import matplotlib.axes3d as p3 phi = linspace(0, 2 * pi, 50) theta = linspace(-pi / 2, pi / 2, 200) ax = [] ay = [] az = [] R = 1.0 for t in theta: polar = float(t) for k in phi: azim = float(k) sph = special.sph_harm(0, 5, azim, polar) # Y(m,l,phi,theta) modulation = 0.2 * abs(sph) r = R * (1 + modulation) x = r * cos(polar) * cos(azim) y = r * cos(polar) * sin(azim) z = r * sin(polar) # print z # print x,y,z ax.append(x) ay.append(y) az.append(z) fig = p.figure() f = p3.Axes3D(fig) f.set_xlabel('X') f.set_ylabel('Y') f.set_zlabel('Z')
def csh(l, m, theta, phi, normalization='quantum', condon_shortley=True): """ Compute Complex Spherical Harmonics (CSH) Y_l^m(theta, phi). Unlike the scipy.special.sph_harm function, we use the common convention that theta is the polar angle (0 to pi) and phi is the azimuthal angle (0 to 2pi). The spherical harmonic 'backbone' is: Y_l^m(theta, phi) = P_l^m(cos(theta)) exp(i m phi) where P_l^m is the associated Legendre function as defined in the scipy library (scipy.special.sph_harm). Various normalization factors can be multiplied with this function. -> seismology: sqrt( ((2 l + 1) * (l - m)!) / (4 pi * (l + m)!) ) -> quantum: (-1)^2 sqrt( ((2 l + 1) * (l - m)!) / (4 pi * (l + m)!) ) -> unnormalized: 1 -> geodesy: sqrt( ((2 l + 1) * (l - m)!) / (l + m)! ) -> nfft: sqrt( (l - m)! / (l + m)! ) The 'quantum' and 'seismology' CSH are normalized so that <Y_l^m, Y_l'^m'> = int_S^2 Y_l^m(theta, phi) Y_l'^m'* dOmega = delta(l, l') delta(m, m') where dOmega is the volume element for the sphere S^2: dOmega = sin(theta) dtheta dphi The 'geodesy' convention have unit power, meaning the norm is equal to the surface area of the unit sphere (4 pi) <Y_l^m, Y_l'^m'> = 4pi delta(l, l') delta(m, m') On each of these normalizations, one can optionally include a Condon-Shortley phase factor: (-1)^m (if m > 0) 1 (otherwise) Note that this is the definition of Condon-Shortley according to wikipedia [1], but other sources call a phase factor of (-1)^m a Condon-Shortley phase (without mentioning the condition m > 0). References: [1] http://en.wikipedia.org/wiki/Spherical_harmonics#Conventions :param l: non-negative integer; the degree of the CSH. :param m: integer, -l <= m <= l; the order of the CSH. :param theta: the colatitude / polar angle, ranging from 0 (North Pole, (X,Y,Z)=(0,0,1)) to pi (South Pole, (X,Y,Z)=(0,0,-1)). :param phi: the longitude / azimuthal angle, ranging from 0 to 2 pi. :param normalization: how to normalize the CSH: 'seismology', 'quantum', 'geodesy', 'unnormalized', 'nfft'. :return: the value of the complex spherical harmonic Y^l_m(theta, phi) """ if normalization == 'quantum': # y = ((-1) ** m) * sph_harm(m, l, theta=phi, phi=theta) y = ((-1) ** m) * sph_harm(m, l, phi, theta) elif normalization == 'seismology': # y = sph_harm(m, l, theta=phi, phi=theta) y = sph_harm(m, l, phi, theta) elif normalization == 'geodesy': # y = np.sqrt(4 * np.pi) * sph_harm(m, l, theta=phi, phi=theta) y = np.sqrt(4 * np.pi) * sph_harm(m, l, phi, theta) elif normalization == 'unnormalized': # y = sph_harm(m, l, theta=phi, phi=theta) / np.sqrt((2 * l + 1) * factorial(l - m) / # (4 * np.pi * factorial(l + m))) y = sph_harm(m, l, phi, theta) / np.sqrt((2 * l + 1) * factorial(l - m) / (4 * np.pi * factorial(l + m))) elif normalization == 'nfft': # y = sph_harm(m, l, theta=phi, phi=theta) / np.sqrt((2 * l + 1) / (4 * np.pi)) y = sph_harm(m, l, phi, theta) / np.sqrt((2 * l + 1) / (4 * np.pi)) else: raise ValueError('Unknown normalization convention:' + str(normalization)) if condon_shortley: # The sph_harm function already includes CS phase return y else: # Cancel the CS phase in sph_harm (i.e. multiply by -1 when m is both odd and greater than 0) return y * ((-1) ** (m * (m > 0)))
def pairSphereHarms(a, b, l): theta, phi = sphang(a, b) print theta, phi return special.sph_harm(np.array(range(-l, l + 1)), l, theta, phi)
def main(): # make environment fw_t = open("time_log",mode="w") t1 = time.time() pot_region,bound_rad,radius,region,nr,gridpx,gridpy,gridpz,x,y,z,xx,yy,zz,a,b,rofi,pot_type,pot_bottom,pot_show_f,si_method,radial_pot_show_f,new_radial_pot_show_f,node_open,node_close,LMAX = make_environment() # make potential V = makepotential(xx,yy,zz,pot_region,pot_type=pot_type,pot_bottom=pot_bottom,pot_show_f=pot_show_f) # surface integral V_radial = surfaceintegral(x,y,z,rofi,V,si_method=si_method,radial_pot_show_f=radial_pot_show_f) V_radial_new = make_V_radial_new(V_radial,rofi,pot_region,bound_rad,new_radial_pot_show_f=new_radial_pot_show_f) vofi = np.array (V_radial_new) # select method of surface integral # make basis node = node_open + node_close nstates = node * LMAX**2 all_basis = make_basis(LMAX,node_open,node_close,nr,a,b,rofi,vofi) #make spherical matrix element Smat = np.zeros((LMAX,LMAX,node,node),dtype = np.float64) hsmat = np.zeros((LMAX,LMAX,node,node),dtype = np.float64) lmat = np.zeros((LMAX,LMAX,node,node), dtype = np.float64) qmat = np.zeros((LMAX,LMAX,node,node), dtype = np.float64) for l1 in range (LMAX): for l2 in range (LMAX): if l1 != l2 : continue for n1 in range (node): for n2 in range (node): if all_basis[l1][n1].l != l1 or all_basis[l2][n2].l != l2: print("error: L is differnt") sys.exit() Smat[l1][l2][n1][n2] = integrate(all_basis[l1][n1].g[:nr] * all_basis[l2][n2].g[:nr],rofi,nr) hsmat[l1][l2][n1][n2] = Smat[l1][l2][n1][n2] * all_basis[l2][n2].e lmat[l1][l2][n1][n2] = all_basis[l1][n1].val * all_basis[l2][n2].slo qmat[l1][l2][n1][n2] = all_basis[l1][n1].val * all_basis[l2][n2].val print("\nSmat") print(Smat) print ("\nhsmat") print (hsmat) print ("\nlmat") print (lmat) print ("\nqmat") print (qmat) hs_L = np.zeros((LMAX,LMAX,node,node)) """ for l1 in range(LMAX): for n1 in range(node): for l2 in range(LMAX): for n2 in range(node): print("{:>8.4f}".format(lmat[l1][l2][n1][n2]),end="") print("") print("") """ print("hs_L") for l1 in range(LMAX): for n1 in range(node): for l2 in range(LMAX): for n2 in range(node): hs_L[l1][l2][n1][n2] = hsmat[l1][l2][n1][n2] + lmat[l1][l2][n1][n2] print("{:>8.4f}".format(hs_L[l1][l2][n1][n2]),end="") print("") t2 = time.time() fw_t.write("make environment, make basis and calculate spherical matrix element\n") fw_t.write("time = {:>11.8}s\n".format(t2-t1)) t1 = time.time() #make not spherical potential my_radial_interfunc = interpolate.interp1d(rofi, V_radial_new) V_ang = np.where(np.sqrt(xx * xx + yy * yy + zz * zz) < rofi[-1] , V - my_radial_interfunc(np.sqrt(xx **2 + yy **2 + zz **2)),0. ) """ for i in range(gridpx): for j in range(gridpy): for k in range(gridpz): print(V_ang[i][j][k],end=" ") print("") print("\n") sys.exit() """ #WARING!!!!!!!!!!!!!!!!!!!!!! """ Fujikata rewrote ~/.local/lib/python3.6/site-packages/scipy/interpolate/interpolate.py line 690~702 To avoid exit with error "A value in x_new is below the interpolation range." """ #!!!!!!!!!!!!!!!!!!!!!!!!!!! """ with open ("V_ang.dat",mode = "w") as fw_a: for i in range(len(V_ang)): fw_a.write("{:>13.8f}".format(xx[50][i][50])) fw_a.write("{:>13.8f}\n".format(V_ang[i][50][50])) """ #mayavi.mlab.plot3d(xx,yy,V_ang) # mlab.contour3d(V_ang,color = (1,1,1),opacity = 0.1) # obj = mlab.volume_slice(V_ang) # mlab.show() ngrid = 10 fw_u = open("umat_gauss.dat",mode="w") umat = np.zeros((node,node,LMAX,LMAX,2 * LMAX + 1,2 * LMAX + 1), dtype = np.complex64) igridpx = ngrid igridpy = ngrid igridpz = ngrid gauss_px,gauss_wx = np.polynomial.legendre.leggauss(igridpx) gauss_py,gauss_wy = np.polynomial.legendre.leggauss(igridpy) gauss_pz,gauss_wz = np.polynomial.legendre.leggauss(igridpz) ix,iy,iz = gauss_px * pot_region[0],gauss_py * pot_region[1],gauss_pz * pot_region[2] ixx,iyy,izz = np.meshgrid(ix,iy,iz) gauss_weight = np.zeros((igridpx,igridpy,igridpz)) for i in range(igridpx): for j in range(igridpy): for k in range(igridpz): gauss_weight[i][j][k] = gauss_wx[i] * gauss_wy[j] * gauss_wz[k] #my_V_ang_inter_func = RegularGridInterpolator((x, y, z), V_ang) #V_ang_i = my_V_ang_inter_func((ixx,iyy,izz)) V_ang_i = np.zeros((igridpx,igridpy,igridpz)) V_ang_i = -1. - my_radial_interfunc(np.sqrt(ixx * ixx + iyy * iyy + izz * izz)) #mlab.contour3d(V_ang_i,color = (1,1,1),opacity = 0.1) #obj = mlab.volume_slice(V_ang_i) #mlab.show() dis = np.sqrt(ixx **2 + iyy **2 + izz **2) dis2 = ixx **2 + iyy **2 + izz **2 theta = np.where( dis != 0., np.arccos(izz / dis), 0.) phi = np.where( iyy**2 + ixx **2 != 0 , np.where(iyy >= 0, np.arccos(ixx / np.sqrt(ixx **2 + iyy **2)), np.pi + np.arccos(ixx / np.sqrt(ixx **2 + iyy **2))), 0.) #phi = np.where( iyy != 0. , phi, 0.) #phi = np.where(iyy > 0, phi,-phi) # region_t = np.where(dis < rofi[-1],1,0) sph_harm_mat = np.zeros((LMAX,2 * LMAX + 1, igridpx,igridpy,igridpz),dtype = np.complex64) for l1 in range (LMAX): for m1 in range (-l1,l1 + 1): sph_harm_mat[l1][m1] = np.where(dis != 0., sph_harm(m1,l1,phi,theta),0.) g_ln_mat = np.zeros((node,LMAX,igridpx,igridpy,igridpz),dtype = np.float64) for n1 in range (node): for l1 in range (LMAX): my_radial_g_inter_func = interpolate.interp1d(rofi,all_basis[l1][n1].g[:nr]) g_ln_mat[n1][l1] = my_radial_g_inter_func(np.sqrt(ixx **2 + iyy **2 + izz **2)) for n1 in range (node): for n2 in range (node): for l1 in range (LMAX): for l2 in range (LMAX): if all_basis[l1][n1].l != l1 or all_basis[l2][n2].l != l2: print("error: L is differnt") sys.exit() # to avoid nan in region where it can not interpolate ie: dis > rofi g_V_g = np.where(dis < rofi[-1], g_ln_mat[n1][l1] * V_ang_i * g_ln_mat[n2][l2], 0.) for m1 in range (-l1,l1+1): for m2 in range (-l2,l2+1): #print("n1 = {} n2 = {} l1 = {} l2 = {} m1 = {} m2 = {}".format(n1,n2,l1,l2,m1,m2)) umat[n1][n2][l1][l2][m1][m2] = np.sum(np.where( dis2 != 0., sph_harm_mat[l1][m1].conjugate() * g_V_g * sph_harm_mat[l2][m2] / dis2 * gauss_weight, 0.)) * pot_region[0] * pot_region[1] * pot_region[2] #print(umat[n1][n2][l1][l2][m1][m2]) count = 0 for l1 in range (LMAX): for l2 in range (LMAX): for m1 in range (-l1,l1+1): for m2 in range (-l2,l2+1): for n1 in range (node): for n2 in range (node): fw_u.write(str(count)) fw_u.write("{:>15.8f}{:>15.8f}\n".format(umat[n1][n2][l1][l2][m1][m2].real,umat[n1][n2][l1][l2][m1][m2].imag)) count += 1 fw_u.close() t2 = time.time() fw_t.write("calculate U-matrix\n") fw_t.write("grid = {:<5} time ={:>11.8}s\n".format(ngrid,t2 - t1)) t1 = time.time() ham_mat = np.zeros((nstates * nstates),dtype = np.float64) qmetric_mat = np.zeros((nstates * nstates),dtype = np.float64) for l1 in range(LMAX): for m1 in range (-l1,l1+1): for n1 in range(node): for l2 in range(LMAX): for m2 in range(-l2,l2+1): for n2 in range(node): if l1 == l2 and m1 == m2 : ham_mat[l1 **2 * node * LMAX**2 * node + (l1 + m1) * node * LMAX**2 * node + n1 * LMAX**2 * node + l2 **2 * node + (l2 + m2) * node + n2] += hs_L[l1][l2][n1][n2] qmetric_mat[l1 **2 * node * LMAX**2 * node + (l1 + m1) * node * LMAX**2 * node + n1 * LMAX**2 * node + l2 **2 * node + (l2 + m2) * node + n2] = qmat[l1][l2][n1][n2] ham_mat[l1 **2 * node * LMAX**2 * node + (l1 + m1) * node * LMAX**2 * node + n1 * LMAX**2 * node + l2 **2 * node + (l2 + m2) * node + n2] += umat[n1][n2][l1][l2][m1][m2].real lambda_mat = np.zeros(nstates * nstates,dtype = np.float64) alphalong = np.zeros(nstates) betalong = np.zeros(nstates) alpha = np.zeros(LMAX**2) beta = np.zeros(LMAX**2) reveclong = np.zeros(nstates * nstates) revec = np.zeros((LMAX**2,nstates)) for e_num in range(1,2): E = e_num * 1 lambda_mat = np.zeros(nstates * nstates,dtype = np.float64) lambda_mat -= ham_mat """ for i in range(nstates): lambda_mat[i + i * nstates] += E """ count = 0 fw_lam = open("lambda.dat",mode="w") for l1 in range(LMAX): for m1 in range (-l1,l1+1): for n1 in range(node): for l2 in range(LMAX): for m2 in range(-l2,l2+1): for n2 in range(node): if l1 == l2 and m1 == m2 : lambda_mat[l1 **2 * node * LMAX**2 * node + (l1 + m1) * node * LMAX**2 * node + n1 * LMAX**2 * node + l2 **2 * node + (l2 + m2) * node + n2] += Smat[l1][l2][n1][n2] * E fw_lam.write(str(count)) fw_lam.write("{:>15.8f}\n".format(lambda_mat[l1 **2 * node * LMAX**2 * node + (l1 + m1) * node * LMAX**2 * node + n1 * LMAX**2 * node + l2 **2 * node + (l2 + m2) * node + n2])) count += 1 fw_lam.close() info = solve_genev(nstates,lambda_mat,qmetric_mat,alphalong,betalong,reveclong) print("info = ",info) print("alphalong") print(alphalong) print("betalong") print(betalong) #print(revec) k = 0 jk = np.zeros(nstates,dtype=np.int32) for i in range(nstates): if abs(betalong[i]) > BETAZERO : jk[k] = i k += 1 if k != LMAX**2: print(" main PANIC: solution of genev has rank k != nchannels ") sys.exit() for k in range(LMAX**2): j = jk[k] alpha[k] = alphalong[j] beta[k] = betalong[j] revec[k] = reveclong[j * nstates : (j + 1) * nstates] fw_revec = open("revec.dat",mode="w") print("revec") for j in range(nstates): fw_revec.write("{:>4}".format(j)) for i in range(LMAX**2): fw_revec.write("{:>13.8f}".format(revec[i][j])) print("{:>11.6f}".format(revec[i][j]),end="") print("") fw_revec.write("\n") print("") fw_revec.close() t2 = time.time() fw_t.write("solve eigenvalue progrem\n") fw_t.write("time = {:>11.8}s\n".format(t2-t1)) fw_t.close()
def sphCalc(Lmax, Lmin=0, res=None, angs=None, XFlag=True): ''' Calculate set of spherical harmonics Ylm(theta,phi) on a grid. Parameters ---------- Lmax : int Maximum L for the set. Ylm calculated for Lmin:Lmax, all m. Lmin : int, optional, default 0 Min L for the set. Ylm calculated for Lmin:Lmax, all m. res : int, optional, default None (Theta, Phi) grid resolution, outputs will be of dim [res,res]. angs : list of 2D np.arrays, [thetea, phi], optional, default None If passed, use these grids for calculation XFlag : bool, optional, default True Flag for output. If true, output is Xarray. If false, np.arrays Note that either res OR angs needs to be passed. Outputs ------- - if XFlag - YlmX 3D Xarray, dims (lm,theta,phi) - else - Ylm, lm 3D np.array of values, dims (lm,theta,phi), plus list of lm pairs Methods ------- Currently set for scipy.special.sph_harm as calculation routine. Example ------- >>> YlmX = sphCalc(2, res = 50) ''' # Set coords based on inputs # TODO: better code here (try/fail?) if angs is None and res: theta, phi = np.meshgrid(np.linspace(0, 2 * np.pi, res), np.linspace(0, np.pi, res)) elif res is None and angs: theta = angs[0] phi = angs[1] else: print('Need to pass either res or angs.') return False # Loop over lm and calculate lm = [] Ylm = [] for l in np.arange(Lmin, Lmax + 1): for m in np.arange(-l, l + 1): lm.append([l, m]) Ylm.append(sph_harm(m, l, theta, phi)) # Return as Xarray or np arrays. if XFlag: # Set indexes QNs = pd.MultiIndex.from_arrays(np.asarray(lm).T, names=['l', 'm']) YlmX = xr.DataArray(np.asarray(Ylm), coords=[('LM', QNs), ('Theta', theta[0, :]), ('Phi', phi[:, 0])]) return YlmX else: return np.asarray(Ylm), np.asarray(lm)
def sph_harm_(m, n, theta, phi): y = sph_harm(m, n, theta, phi) return (y.real, y.imag)
# In[105]: U_tilde(ks_mesh, pp + theta_mesh, Lk, 0, 1, 1, 0).shape # In[106]: sph_harmY(1, 1, ([2, 3, 6]), 7) # In[107]: for i in range(0, len(theta_mesh)): print sph_harmY(1, 1, theta_mesh[i], phi_mesh[i]) # In[108]: sph_harm(1, 1, phi_mesh, theta_mesh) ##### sph_harm does not produce a matrix over theta and phi as we would like, but instead takes corresponding element from theta array and the phi array. To get around this, precalculate and store the spherical harmonics. This will also speed up the program compared to calculating spherical harmonics each time on fly. As has been previously established, calculation of spherical harmonics is time intensive. # In[109]: sph_harm_theta_phi = np.zeros((6, 11, 10, 10), dtype='complex128') # In[110]: sph_harm_1 = np.zeros(10) # In[111]: sph_harm_1[:] = sph_harm(1, 1, phi_mesh, theta_mesh[1])
#!/bin/python #spherical_harmonics.py import scipy as sci import scipy.special as sp import numpy as np import matplotlib import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib import cm, colors # Graphically represent spherical harmonics l = 4 m = 2 theta, phi = 0.6, 0.75 # Some arbitrary values of angles in radians Y42 = sp.sph_harm(m, l, phi, theta) PHI, THETA = np.mgrid[0:2 * np.pi:200j, 0:np.pi:100j] #arrays of angular variables R = np.abs(sp.sph_harm(m, l, PHI, THETA)) #Array with the absolute values of Ylm #Now we convert to cartesian coordinates # for the 3D representation X = R * np.sin(THETA) * np.cos(PHI) Y = R * np.sin(THETA) * np.sin(PHI) Z = R * np.cos(THETA) N = R / R.max( ) # Normalize R for the plot colors to cover the entire range of colormap. fig, ax = plt.subplots(subplot_kw=dict(projection='3d'), figsize=(12, 10)) im = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=cm.jet(N)) ax.set_title(r'$|Y^2_ 4|$', fontsize=20)
def sph_harmY(l, m, theta, phi): if abs(m) <= abs(l): return sph_harm(m, l, phi, theta) else: return 0.0