def solve(self, init, x): A = np.zeros([2, 2]) A[0][0] = special.lpmn(self.order, self.degree, self.function(x[0]))[0][self.order][self.degree] A[0][1] = special.lqmn(self.order, self.degree, self.function(x[0]))[0][self.order][self.degree] A[1][0] = self.function.deriv(1)(x[0]) * special.lpmn( self.order, self.degree, self.function( x[0]))[1][self.order][self.degree] A[1][1] = self.function.deriv(1)(x[0]) * special.lqmn( self.order, self.degree, self.function( x[0]))[1][self.order][self.degree] print(A) c = np.linalg.solve(A, init) self.c = c y = np.zeros((len(x), 2)) for i in range(len(x)): for j in range(2): if j == 0: y[i][j] = \ c[0]*special.lpmn(self.order, self.degree, self.function(x[i]))[j][self.order][self.degree] + \ c[1]*special.lqmn(self.order, self.degree, self.function(x[i]))[j][self.order][self.degree] elif j == 1: y[i][j] = \ c[0]*self.function.deriv(1)(x[i])*special.lpmn(self.order, self.degree, self.function(x[i]))[j][self.order][self.degree] + \ c[1]*self.function.deriv(1)(x[i])*special.lqmn(self.order, self.degree, self.function(x[i]))[j][self.order][self.degree] self.x = x self.y = y return y
def lpy1(nmax, z): """ Associated legendre function and its derivatative at z in the 'y-indexing'. (Without Condon-Shortley phase AFAIK.) NOT THOROUGHLY TESTED Parameters ---------- nmax: int The maximum order to which the Legendre functions will be evaluated.. z: float The point at which the Legendre functions are evaluated. output: (P_y, dP_y) TODO y-indexed legendre polynomials and their derivatives """ pmn_plus, dpmn_plus = lpmn(nmax, nmax, z) pmn_minus, dpmn_minus = lpmn(-nmax, nmax, z) nelem = nmax * nmax + 2*nmax P_y = np.empty((nelem,), dtype=np.float_) dP_y = np.empty((nelem,), dtype=np.float_) mn_p_y, mn_n_y = get_y_mn_unsigned(nmax) mn_plus_mask = (mn_p_y >= 0) mn_minus_mask = (mn_n_y >= 0) #print( mn_n_y[mn_minus_mask]) P_y[mn_p_y[mn_plus_mask]] = pmn_plus[mn_plus_mask] P_y[mn_n_y[mn_minus_mask]] = pmn_minus[mn_minus_mask] dP_y[mn_p_y[mn_plus_mask]] = dpmn_plus[mn_plus_mask] dP_y[mn_n_y[mn_minus_mask]] = dpmn_minus[mn_minus_mask] return (P_y, dP_y)
def y(F, n, m, H_0, sign): OmH = H_0 / (4 * np.pi * M) - (1 / 3) Omega = F + OmH kappa = -OmH / (F * (F + 2 * OmH)) nu = -(F + OmH) / (F * (F + 2 * OmH)) xi = np.sqrt(1 + 1 / kappa) #print(1 + 1/kappa) nu = -(F + OmH) / (F * (F + 2 * OmH)) return (n + 1 + sign * m * nu) * lpmn(m, n, xi)[0][m][n] + xi * lpmn( m, n, xi)[1][m][n]
def sph_harm_large(m, n, az, el): """Compute spherical harmonics for large orders > 84 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 Notes ----- Y_n,m (theta, phi) = ((n - m)! * (2l + 1)) / (4pi * (l + m))^0.5 * exp(i m phi) * P_n^m(cos(theta)) as per http://dlmf.nist.gov/14.30 Pmn(z) is the associated Legendre function of the first kind, like scipy.special.lpmv scipy.special.lpmn calculates P(0...m 0...n) and its derivative but won't return +inf at high orders """ if _np.all(_np.abs(m) < 84): return scy.sph_harm(m, n, az, el) else: # TODO: confirm that this uses the correct SH definition mAbs = _np.abs(m) if isinstance(el, _np.ndarray): P = _np.empty(el.size) for k in range(0, el.size): P[k] = scy.lpmn(mAbs, n, _np.cos(el[k]))[0][-1][-1] else: P = scy.lpmn(mAbs, n, _np.cos(el))[0][-1][-1] preFactor1 = _np.sqrt((2 * n + 1) / (4 * _np.pi)) try: preFactor2 = _np.sqrt(fact(n - mAbs) / fact(n + mAbs)) except OverflowError: # integer division for very large orders preFactor2 = _np.sqrt(fact(n - mAbs) // fact(n + mAbs)) Y = preFactor1 * preFactor2 * _np.exp(1j * m * az) * P if m < 0: return _np.conj(Y) else: return Y
def test_legendre(self): xs = np.linspace(0, 1, 10000) ys = np.zeros(10000 * 16) ys2 = np.zeros(10000 * 16) for i in range(xs.shape[0]): if i == 0: print(lpmn(-3, 3, xs[i])[0]) ys[16 * i:16 * (i + 1)] = lpmn(-3, 3, xs[i])[0].flatten() for i in range(xs.shape[0]): for l in range(4): for m in range(0, -l - 1, -1): ys2[i * 16 - m * 4 + l] = pawpyc.legendre(l, m, xs[i]) assert_almost_equal(np.linalg.norm(ys - ys2), 0.0)
def sph_harm_large(m, n, az, el): """Compute spherical harmonics for large orders > 84 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 Y_n,m (theta, phi) = ((n - m)! * (2l + 1)) / (4pi * (l + m))^0.5 * exp(i m phi) * P_n^m(cos(theta)) as per http://dlmf.nist.gov/14.30 Pmn(z) is the associated Legendre function of the first kind, like scipy.special.lpmv scipy.special.lpmn calculates P(0...m 0...n) and its derivative but won't return +inf at high orders """ if _np.all(_np.abs(m) < 84): return scy.sph_harm(m, n, az, el) else: # TODO: confirm that this uses the correct SH definition mAbs = _np.abs(m) if isinstance(el, _np.ndarray): P = _np.empty(el.size) for k in range(0, el.size): P[k] = scy.lpmn(mAbs, n, _np.cos(el[k]))[0][-1][-1] else: P = scy.lpmn(mAbs, n, _np.cos(el))[0][-1][-1] preFactor1 = _np.sqrt((2 * n + 1) / (4 * _np.pi)) try: preFactor2 = _np.sqrt(fact(n - mAbs) / fact(n + mAbs)) except OverflowError: # integer division for very large orders preFactor2 = _np.sqrt(fact(n - mAbs) // fact(n + mAbs)) Y = preFactor1 * preFactor2 * _np.exp(1j * m * az) * P if m < 0: return _np.conj(Y) else: return Y
def getfreq_2(n,m,H_0): fr = np.linspace(0,100,16000)#GHz yr, yr2, yr3 = [], [], [] for f in fr: Omega = f*1e9/(4*np.pi*gamma*M) H_i = H_0 - (4*np.pi/3)*M Omega_H = H_i/(4*np.pi*M) nu = Omega/(Omega_H**2-Omega**2) kappa = Omega_H/(Omega_H**2-Omega**2) xi=np.sqrt(1+1/kappa) yr.append(xi*lpmn(m,n,xi)[1][m][n]/lpmn(m,n,xi)[0][m][n]) yr2.append(-1*(n+1)+m*nu) yr3.append(-1*(n+1)-m*nu)
def y_t(F, n, m, H_0, sign): OmH = H_0 / (4 * np.pi * M) - (1 / 3) kappa = -OmH / (F * (F + 2 * OmH)) nu = -(F + OmH) / (F * (F + 2 * OmH)) xi = np.sqrt(abs(1 + 1 / kappa)) nu = -(F + OmH) / (F * (F + 2 * OmH)) if kappa <= -1: return (n + 1 + sign * m * nu) * lpmn(m, n, xi)[0][m][n] + xi * lpmn( m, n, xi)[1][m][n] else: return -((n + 1 + sign * m * nu) * lpmn(m, n, xi)[0][m][n] + xi * lpmn(m, n, xi)[1][m][n]) return 9 + (3 * O)
def y_2(f, n, m, H_0, sign): Omega = f / (4 * np.pi * gamma * M) #print ('Omega: {}'.format(Omega)) H_i = H_0 - (4 * np.pi / 3) * M Omega_H = H_i / (4 * np.pi * M) #print ('OmegaH: {}'.format(Omega_H)) nu = Omega / (Omega_H**2 - Omega**2) kappa = Omega_H / (Omega_H**2 - Omega**2) xi = np.sqrt(1.0 + 1.0 / kappa) #print (Omega - Omega_H) #return n + 1 + xi*lpmn(m,n,xi)[1][m][n]/lpmn(m,n,xi)[0][m][n] + sign*m*nu return (n + 1 + sign * m * nu) * lpmn(m, n, xi)[0][m][n] + xi * lpmn( m, n, xi)[1][m][n]
def getfreq(n,m,H_0): fr = np.linspace(0,100,16000)#GHz yr, yr2, yr3 = [], [], [] for f in fr: Omega = f*1e9/(4*np.pi*gamma*M) H_i = H_0 - (4*np.pi/3)*M Omega_H = H_i/(4*np.pi*M) nu = Omega/(Omega_H**2-Omega**2) kappa = Omega_H/(Omega_H**2-Omega**2) xi=np.sqrt(1+1/kappa) yr.append(xi*lpmn(m,n,xi)[1][m][n]/lpmn(m,n,xi)[0][m][n]) yr2.append(-1*(n+1)+m*nu) yr3.append(-1*(n+1)-m*nu) f = -1 i=0 if (yr[0]>yr2[0]): while(yr[i]>yr2[i]): i+=1 if i>=len(yr2)-1: break if (yr[i]<yr2[i]): f=fr[i] else: while(yr[i]<yr2[i]): i+=1 if i>=len(yr2)-1: break if (yr[i]>yr2[i]): f=fr[i] i = 0 if (yr[0]>yr3[0]): while(yr[i]>yr3[i]): i+=1 if i>=len(yr3)-1: break if (yr[i]<yr3[i]): f=fr[i] else: while(yr[i]<yr3[i]): i+=1 if i>=len(yr3)-1: break if (yr[i]>yr3[i]): f=fr[i] print(f) if (f<0): print("No resonance below 100GHz") return f
def testNormalizedLpmnValues(self, l_max, num_z): # Points on which the associated Legendre functions areevaluated. z = np.linspace(-0.2, 0.9, num_z) is_normalized = True actual_p_vals = lsp_special.lpmn_values(l_max, l_max, z, is_normalized) # The expected results are obtained from scipy. expected_p_vals = np.zeros((l_max + 1, l_max + 1, num_z)) for i in range(num_z): expected_p_vals[:, :, i] = osp_special.lpmn(l_max, l_max, z[i])[0] def apply_normalization(a): """Applies normalization to the associated Legendre functions.""" num_m, num_l, _ = a.shape a_normalized = np.zeros_like(a) for m in range(num_m): for l in range(num_l): c0 = (2.0 * l + 1.0) * osp_special.factorial(l - m) c1 = (4.0 * np.pi) * osp_special.factorial(l + m) c2 = np.sqrt(c0 / c1) a_normalized[m, l] = c2 * a[m, l] return a_normalized # The results from scipy are not normalized and the comparison requires # normalizing the results. expected_p_vals_normalized = apply_normalization(expected_p_vals) with self.subTest('Test accuracy.'): self.assertAllClose(actual_p_vals, expected_p_vals_normalized, rtol=1e-6, atol=3.2e-6) with self.subTest('Test JIT compatibility'): args_maker = lambda: [z] lsp_special_fn = lambda z: lsp_special.lpmn_values(l_max, l_max, z, is_normalized) self._CompileAndCheck(lsp_special_fn, args_maker)
def _calculate_radial_force(cls, r, phi, theta): if len(cls.__COEFFICIENTS) == 0: cls.import_coefficients( 'D:\Users\\tjh97\Dropbox\Workspace\SatelliteSimulator\Model\egm96_coeff.dat' ) R = constant.RADIUS_OF_EARTH P, P_prime = sp.lpmn(cls.__MODEL_ORDER_N, cls.__MODEL_ORDER_N, sin(theta)) tess = 0 for n in range(2, cls.__MODEL_ORDER_N): for m in range(1, n): C_nm, S_nm = cls.__C[m][n], cls.__S[m][n] C_nm_tilde = -C_nm / (constant.MU * R**n) S_nm_tilde = -S_nm / (constant.MU * R**n) P_mn = P[m][n] tg = C_nm_tilde * cos(m * phi) + S_nm_tilde * sin(m * phi) den = (r / R)**n tess += (n + 1) * P_mn * tg / den # tess += (n+1)*P*(C_nm*cos(m*phi) + S_nm*sin(m*phi))/r**(n+2) # tess = 0 return -(constant.MU / r**2) # *(1/Universe.MU - tess)
def calculate_geopotential(cls, r, phi, theta): if len(cls.__COEFFICIENTS) == 0: cls.import_coefficients( 'D:\Users\\tjh97\Dropbox\Workspace\SatelliteSimulator\Model\egm96_coeff.dat' ) R = constant.RADIUS_OF_EARTH P, P_prime = sp.lpmn(cls.__MODEL_ORDER_N, cls.__MODEL_ORDER_N, sin(theta)) zonal = 0 # for n in range(2, cls.__MODEL_ORDER_N): # J_tilde = -1/(Universe.MU*R**n) # P = sp.lpmv(0, n, sin(theta)) # den = (r/R)**n # # zonal += (J_tilde*P)/den tess = 0 for n in range(2, cls.__MODEL_ORDER_N): for m in range(1, n): C_nm, S_nm = cls.__C[m][n], cls.__S[m][n] C_nm_tilde = -C_nm / (Universe.MU * R**n) S_nm_tilde = -S_nm / (Universe.MU * R**n) P_mn = P[m][n] tg = C_nm_tilde * cos(m * phi) + S_nm_tilde * sin(m * phi) den = (r / R)**n tess += P_mn * tg / den return -(Universe.MU / r) * (1 + zonal + tess)
def egmF(elements, var, init_jd, t, order_used, lc): # translate positions and velocities from GCRS into ITRS frame r1, v1 = GCRS2ITRS(var.r, var.v, init_jd, t / 24. / 3600.) # translate cartesian coordinates into spherical coordinates of positions in ITRS frame r, phi, lamda = coord.cartesian_to_spherical(r1[0], r1[1], r1[2]) phi, lamda = phi.value, lamda.value # get the values of Legendre Polynomials and their derivatives Pmn, Pmn_d = special.lpmn(n, n, np.sin(phi)) Fsc = np.zeros(3) for l in range(1, order_used + 1): for m in range(l + 1): Fsc[0] += -model.GM / r / r * (model.R / r)**l * (l + 1) * Pmn[ m, l] * lc[m, l] * (C[l, m] * np.cos(m * lamda) + S[l, m] * np.sin(m * lamda)) Fsc[1] += model.GM / r * (model.R / r)**l * m * Pmn[m, l] * lc[ m, l] * (S[l, m] * np.cos(m * lamda) - C[l, m] * np.sin(m * lamda)) Fsc[2] += model.GM / r * (model.R / r)**l * Pmn_d[m, l] * lc[ m, l] * np.cos(phi) * (C[l, m] * np.cos(m * lamda) + S[l, m] * np.sin(m * lamda)) Fsc[1] /= r * np.cos(phi) Fsc[2] /= r # translate the force from spherical to cartesian in ITRS frame Fxyz = force_spherical_to_cartesian(Fsc, lamda, phi) # translate the force from ITRS to GCRS frame FF, v = ITRS2GCRS(Fxyz, Fxyz, init_jd, t / 24. / 3600.) # matrix transform from Spherical Coordinates to Cartesian Coordinates return FF
def gridSHexp(V, xri, yri, zri, order): """ V: gridded values xri, yri, zri: relative grid vectors order: max l in the spherical harmonic expansion """ assert xri.ndim == 1 and yri.ndim == 1 and zri.ndim == 1 n_samp = xri.size * yri.size * zri.size assert n_samp >= (order + 1)**2 Y, X, Z = np.meshgrid(yri, xri, zri) for A in [X, Y, Z]: A.shape = (-1, ) #flattening W = V.reshape(-1, ) Phi = np.arctan2(Y, X) # print(Phi) Theta = np.arctan2((X**2 + Y**2)**0.5, Z) R = (X**2 + Y**2 + Z**2)**0.5 r0 = R.max()**0.5 R /= r0 Q = np.empty((n_samp, (order + 1)**2), 'd') Q[:, 0] = 1 # We don't expand on scipy.special.sph_harm # Instead, expand on P_l^m(cos\theta) * (cos(m\phi), sin(m\phi))^T MPhi = (np.atleast_2d(Phi).T) * np.arange(1, order + 1) # print(MPhi) cos_sin_MPhi = np.stack((np.cos(MPhi), np.sin(MPhi)), axis=-1).reshape(n_samp, -1) # print(cos_sin_MPhi) for p in range(n_samp): # print(X[p], Y[p], Z[p]) aslegd = lpmn(order, order, np.cos(Theta[p]))[0] # aslegd is now an upper triangle order+1 by order+1 mat # aslegd[m,l] = P_l^m(Theta[p]) if m<=l else 0 pt_col = 1 for l in range(1, order + 1): r_pl_theta = (R[p]**l) * aslegd[:l + 1, l] # print("\t",r_pl_theta) Q[p, pt_col] = r_pl_theta[0] pt_col += 1 Q[p, pt_col:pt_col + 2 * l] = np.repeat(r_pl_theta[1:], 2) * cos_sin_MPhi[p, :2 * l] pt_col += 2 * l assert pt_col == (order + 1)**2 # print(Q) # print(W) fit = lstsq(Q, W) rms = (fit[1] / n_samp)**0.5 rescale = [1] for l in range(1, order + 1): rescale = rescale + [r0**l] * (2 * l + 1) rescale = np.array(rescale) # print(rescale) # return fit[0], rms return fit[0] / rescale, rms
def Pol_Legendre(l, m, x): """ returns an array[m+1,n+1] of the values of the associated Legendre function of all integer degrees l and order m, at point x """ Plm_z, Plm_dz = lpmn(m, l, x) return Plm_z, Plm_dz # use Plm_z[m, l]
def tau_func(n, m, theta): """tau special function in modal decomposition""" if np.sin(theta) == 0: return 0 # Pnm_d = legendre(n,m,theta,1) Pnm_d = -1*np.sin(theta)*special.lpmn(m,n, np.cos(theta))[1][abs(m)][n] return Pnm_d
def testLpmn(self, l_max, num_z): # Points on which the associated Legendre functions areevaluated. z = np.linspace(-0.2, 0.9, num_z) actual_p_vals, actual_p_derivatives = lsp_special.lpmn(m=l_max, n=l_max, z=z) # The expected results are obtained from scipy. expected_p_vals = np.zeros((l_max + 1, l_max + 1, num_z)) expected_p_derivatives = np.zeros((l_max + 1, l_max + 1, num_z)) for i in range(num_z): val, derivative = osp_special.lpmn(l_max, l_max, z[i]) expected_p_vals[:, :, i] = val expected_p_derivatives[:, :, i] = derivative with self.subTest('Test values.'): self.assertAllClose(actual_p_vals, expected_p_vals, rtol=1e-6, atol=3.2e-6) with self.subTest('Test derivatives.'): self.assertAllClose(actual_p_derivatives, expected_p_derivatives, rtol=1e-6, atol=8.4e-4) with self.subTest('Test JIT compatibility'): args_maker = lambda: [z] lsp_special_fn = lambda z: lsp_special.lpmn(l_max, l_max, z) self._CompileAndCheck(lsp_special_fn, args_maker)
def derlpmn_em(l, m, x): """ Computes derivative of associated Legendre function (Plm) of the first kind of order m and degree l with respect to the argument x. Parameters ---------- l: int degree of Plm m: int order of Plm x: Nx1 array evaluation points Returns ------- derlp: Nx1 array dPlm/dx at `x` """ derlp = np.zeros(x.shape) for i in range(x.shape[0]): a, b = lpmn(m, l, x[i]) derlp[i] = b[np.abs(m), l] return derlp
def __normalized_legendre(m, n, x): """ Fully normalized associated legendre polynomials degree n and order m. Cf. https://de.mathworks.com/help/matlab/ref/legendre.html#f89-1002493 :param m: Order :param n: Degree :param x: Evaluation point :return: Function value """ upper_fact = (lambda x: x, n - m) lower_fact = (lambda x: 1 / x, n + m) factor = RBF_QR_3D.__prodprod(upper_fact, lower_fact) factor = (-1)**m * math.sqrt(factor * (n + 0.5)) if not np.isscalar(x): return np.array([lpmn(m, n, x_i)[0][-1, -1] for x_i in x]) return lpmn(m, n, x)[0][-1, -1] * factor
def _compute(self, funcTilde, R, z, phi): """ NAME: _compute PURPOSE: evaluate the NxLxM density or potential INPUT: funcTidle - must be _rhoTilde or _phiTilde R - Cylindrical Galactocentric radius z - vertical height phi - azimuth OUTPUT: An NxLxM density or potential at (R,z, phi) HISTORY: 2016-05-18 - Written - Aladdin """ Acos, Asin = self._Acos, self._Asin N, L, M = Acos.shape r, theta, phi = bovy_coords.cyl_to_spher(R, z, phi) PP = lpmn(M - 1, L - 1, nu.cos(theta))[0].T ##Get the Legendre polynomials func_tilde = funcTilde(r, N, L) ## Tilde of the function of interest func = nu.zeros( (N, L, M), float) ## The function of interest (density or potential) m = nu.arange(0, M)[nu.newaxis, nu.newaxis, :] mcos = nu.cos(m * phi) msin = nu.sin(m * phi) func = func_tilde[:, :, None] * (Acos[:, :, :] * mcos + Asin[:, :, :] * msin) * PP[None, :, :] return func
def radial_sp(self, radial, theta, phi, radius=None, M=2, mu=1, musp=1, small=False): if not small or radius is None: max_it = self.max_it(radial) else: max_it = self.max_it(radius) riccati_terms = riccati_jn(max_it, M * self.wave_number * radial)[0] legendre_terms = lpmn(max_it, max_it, np.cos(theta))[0] nm_func = lambda n, m: n * (n + 1) pre_mul = self.e0 / np.power(radial, 2) / M**2 / self.wave_number mies = mie_cns(max_it, self.wave_number, radius, M, mu, musp) return self.component(radial, theta, phi, riccati_terms, legendre_terms, pre_mul, nm_func, max_it, mies=mies)
def igrf_B(year,ht,lon,lat): base=int((year-1900)/5) # base model shift=year-(5*base+1900) # shift years g=(1-shift/5.)*gdat[base][:][:]+(shift/5.)*gdat[base+1][:][:] h=(1-shift/5.)*hdat[base][:][:]+(shift/5.)*hdat[base+1][:][:] phi=lon*pi/180. # set phi=longitude dependence - co-sinusoids cp=cos(m*phi) sp=sin(m*phi) az=g*cp+h*sp az_phi=m*(-g*sp+h*cp) r=a+ht # set geocentric altitude dependence amp=a*((a/r)**(n+1)) amp_r=-(n+1)*amp/r # r derivative of amp from scipy.special import lpmn theta=(90.-lat)*pi/180. # set theta=colatitude dependence ct=cos(theta) st=sqrt(1.-ct**2.) [lPmn,lPmn_der]=lpmn(10,10,ct) # assoc legendre function and derivative lPmn=lPmn*schmidt # schmidt normalization lPmn_theta=-st*lPmn_der*schmidt # figure() # imshow(schmidt,interpolation='nearest') # colorbar() # title("schmidt_mn") Z=sum(amp_r*lPmn*az) # get field components (nT) Y=-sum(amp*lPmn*az_phi)/(r*st) X=sum(amp*lPmn_theta*az)/r B=sqrt(X**2.+Y**2.+Z**2.) return X,Y,Z,B
def _compute(self, funcTilde, R, z, phi): """ NAME: _compute PURPOSE: evaluate the NxLxM density or potential INPUT: funcTidle - must be _rhoTilde or _phiTilde R - Cylindrical Galactocentric radius z - vertical height phi - azimuth OUTPUT: An NxLxM density or potential at (R,z, phi) HISTORY: 2016-05-18 - Written - Aladdin """ Acos, Asin = self._Acos, self._Asin N, L, M = Acos.shape r, theta, phi = bovy_coords.cyl_to_spher(R,z,phi) PP = lpmn(M-1,L-1,nu.cos(theta))[0].T ##Get the Legendre polynomials func_tilde = funcTilde(r, N, L) ## Tilde of the function of interest func = nu.zeros((N,L,M), float) ## The function of interest (density or potential) m = nu.arange(0, M)[nu.newaxis, nu.newaxis, :] mcos = nu.cos(m*phi) msin = nu.sin(m*phi) func = func_tilde[:,:,None]*(Acos[:,:,:]*mcos + Asin[:,:,:]*msin)*PP[None,:,:] return func
def lpmn_em(l, m, x): """ Computes associated Legendre function (Plm) of the first kind of order m and degree l. Parameters ---------- l: int degree of Plm m: int order of Plm x: Nx1 array evaluation points Returns ------- lp: Nx1 array Plm at `x` """ lp = np.zeros(x.shape) for i in range(x.shape[0]): a, b = lpmn(m, l, x[i]) lp[i] = a[np.abs(m), l] return lp
def igrf_B(year,ht,lon,lat): base=int((year-1900)/5) # base model shift=year-(5*base+1900) # shift years g=(1-shift/5.)*gdat[base][:][:]+(shift/5.)*gdat[base+1][:][:] h=(1-shift/5.)*hdat[base][:][:]+(shift/5.)*hdat[base+1][:][:] phi=lon*pi/180.# set phi=longitude dependence - co-sinusoids cp=cos(m*phi) sp=sin(m*phi) az=g*cp+h*sp az_phi=m*(-g*sp+h*cp) r=a+ht # set geocentric altitude dependence amp=a*((a/r)**(n+1)) amp_r=-(n+1)*amp/r # r derivative of amp from scipy.special import lpmn theta=(90.-lat)*pi/180. # set theta=colatitude dependence ct=cos(theta) st=sqrt(1.-ct**2.) [lPmn,lPmn_der]=lpmn(10,10,ct) # assoc legendre function and derivative lPmn=lPmn*schmidt # schmidt normalization lPmn_theta=-st*lPmn_der*schmidt # figure() # imshow(schmidt,interpolation='nearest') # colorbar() # title("schmidt_mn") Z=sum(amp_r*lPmn*az) # get field components (nT) Y=-sum(amp*lPmn*az_phi)/(r*st) X=sum(amp*lPmn_theta*az)/r B=sqrt(X**2.+Y**2.+Z**2.) return X,Y,Z,B
def pi_func(n, m, theta): """pi special function in modal decomposition""" if np.sin(theta) == 0: return 0 # Pnm = legendre(n,m,theta) Pnm = special.lpmn(m,n, np.cos(theta))[0][abs(m)][n] return m*Pnm/np.sin(theta)
def Mm(x,m,q,aks): "Function M(eta), part of the H2+ solution" maxk=len(aks) #Plm = polyx.Plmc(x,m,maxk) #mm = [aks[il]*Plm[il] for il in range(len(aks))] Plm = special.lpmn(m, maxk-1+m, x)[0][m] mm = [aks[il]*Plm[il+m] for il in range(len(aks))] return sum(mm)*exp(-q*x)
def check_sph_harm(l, m, theta, phi): print(sp.sph_harm(m, l, phi, theta)) Clm = np.sqrt( (2 * l + 1.0) / 4 / np.pi * sp.poch(l + abs(m) + 1, -2 * abs(m))) [Pmlv, Pmlvdiff] = sp.lpmn(abs(m), l, np.cos(theta)) ans = Clm * Pmlv[abs(m), l] * np.exp(1j * m * phi) if (m < 0): ans = (-1)**m * np.conjugate(ans) print(ans)
def legendre(z): x = [] for ii in z: x.append(((1 + sigma_m0 * ii) / (1 - sigma_m0))**.5) r_list = [] for ii in x: #print(lpmn((beta-1)/2, 2,ii)[0][-1][-1]) r_list.append(lpmn((4 * beta - 1) / 2, 2, ii)[0][-1][-1] / (ii**2 - 1)) return r_list
def cyl_mom(L, M, dens, H, R): gamFac = np.sqrt(np.exp(sp.gammaln(L - M + 1) - sp.gammaln(L + M + 1))) fact = np.sqrt((2 * L + 1) / (4 * np.pi)) * gamFac * sp.factorial(L - M) / (2. * np.pi) R22 = np.sqrt(R**2 + H**2) theta22 = H / R22 theta21 = -H / R22 mom = 0 PLM22 = sp.lpmn(L + 2, L + 2, theta22)[0][:, -1] PLM21 = sp.lpmn(L + 2, L + 2, theta21)[0][:, -1] momval = PLM22 - PLM21 ks = np.arange(L - M) fac2 = (ks * 2 + 1 + M) * 2 * M / ((M + 2 * ks) * (M + 2 * ks + 2)) mom = fact * fac2 * R * R22**(L + 2) * momval[-len(ks):] mom = np.sum(mom) if M == 0: mom = fact * R * R22**(L + 2) * momval[1] return mom
def multiplet(x, l, freq, width, splitting, inc): legendre2 = lpmn(l, l, np.cos(inc))[0]**2 y = lorentz((x - freq) / width) * factorial(l) * legendre2[0][l] for m in range(1, l + 1): energy = legendre2[m][l] * factorial(l - m) / factorial(l + m) y = y + lorentz((x - freq - m * splitting) / width) * energy y = y + lorentz((x - freq + m * splitting) / width) * energy return y
def ydot_geopotential(self, y, C, S, n, m): """Returns the time derivative of only the geopotential effect for a given state. !!! Deprecated Method!!! Args: y(1x6 numpy array): the state vector [rx,ry,rz,vx,vy,vz] gravityCoeff (nxm numpy array): the array where you have stored the geopotential coefficients Cnm,Snm n (integer): degree of coeffs you want to use for the calculation m (integer): order of coeffs you want to use for the calculation Returns: 1x6 numpy array: the time derivative of y [vx,vy,vz,ax,ay,az] """ r, phi, l = self.cart2geodetic(y[0], y[1], y[2]) earthR = 6378137 mu = 398600.4405e+09 r = r + earthR legendreP = sp.lpmn(n+1, m+1, mp.sin(phi)) legendreP = legendreP[0] legendreP = np.transpose(legendreP) V = np.zeros((n+1, m+1)) W = np.zeros((n+1, m+1)) for i in range(0, n+1): for j in range(0, i+1): V[i, j] = ((earthR/r) ** (i+1)) * (legendreP[i, j] * mp.cos(j * l)) W[i, j] = ((earthR/r) ** (i+1)) * (legendreP[i, j] * mp.sin(j * l)) ax = 0 ay = 0 az = 0 for i in range(0, n-2): for j in range(0, i+1): if j == 0: ax = ax + (mu / earthR**2) * (-C[i, 0] * V[i+1, 1]) ay = ay + (mu / earthR ** 2) * (-C[i, 0] * W[i + 1, 1]) else: ax = ax + (mu / earthR ** 2) * 0.5 * (-C[i, j] * V[i + 1, j + 1] - S[i, j] * W[i + 1, j + 1]) + \ (mp.factorial(i - j + 2) / mp.factorial(i - j)) * ( C[i, j] * V[i + 1, j - 1] + S[i, j] * W[i + 1, j - 1]) ay = ay + (mu / earthR ** 2) * 0.5 * (-C[i, j] * W[i + 1, j + 1] + S[i, j] * V[i + 1, j + 1]) + \ (mp.factorial(i - j + 2) / mp.factorial(i - j)) * ( -C[i, j] * W[i + 1, j - 1] + S[i, j] * V[i + 1, j - 1]) az = az + (mu / earthR ** 2) * ((i-j+1) * (-C[i, j] * V[i+1, j] - S[i, j] * W[i+1, j])) ax = -ax ay = -ay # print(ax, ay, az) return np.array([ax, ay, az])
def __init__(self, NSIDE, lmax=10, clv=True): """ Args: NSIDE (int) : the healpix NSIDE parameter, must be a power of 2, less than 2**30 npix (int) : number of pixel in the X and Y axis of the final projected map rot_velocity (float) : rotation velocity of the star in the equator in km/s Returns: None """ self.NSIDE = int(NSIDE) self.hp_npix = hp.nside2npix(NSIDE) self.lmax = lmax self.n_coef_max = (1+lmax)**2 self.epsilon = 1e-3 self.l = np.arange(self.lmax+1) self.alpha = np.zeros(self.n_coef_max) self.beta = np.zeros(self.n_coef_max) self.gamma = np.zeros(self.n_coef_max) # self.rot_velocity = rot_velocity self.clv = clv # Generate the indices of all healpix pixels self.indices = np.arange(hp.nside2npix(NSIDE), dtype='int') self.n_healpix_pxl = len(self.indices) self.polar_angle, self.azimuthal_angle = hp.pixelfunc.pix2ang(self.NSIDE, np.arange(self.n_healpix_pxl)) self.pixel_vectors = np.array(hp.pixelfunc.pix2vec(self.NSIDE, self.indices)) # Compute LOS rotation velocity as v=w x r self.rotation_velocity = np.cross(np.array([0.0,0.0,1.0])[:,None], self.pixel_vectors, axisa=0, axisb=0, axisc=0) self.vec_boundaries = np.zeros((3,4,self.n_healpix_pxl)) for i in range(self.n_healpix_pxl): self.vec_boundaries[:,:,i] = hp.boundaries(self.NSIDE, i) self.Plm = np.zeros((self.lmax+2, self.lmax+2, self.n_healpix_pxl)) self.dPlm = np.zeros((self.lmax+2, self.lmax+2, self.n_healpix_pxl)) self.Clm = np.zeros((self.lmax+2, self.lmax+2)) for i in range(self.n_healpix_pxl): self.Plm[:,:,i], self.dPlm[:,:,i] = sp.lpmn(self.lmax+1, self.lmax+1, np.cos(self.polar_angle[i])) self.dPlm[:,:,i] *= -np.sin(self.polar_angle[i]) for l in range(self.lmax+2): for m in range(0, l+1): self.Clm[m,l] = np.sqrt((2.0*l+1) / (4.0*np.pi) * mi.factorial(l-m) / mi.factorial(l+m)) self.lambda0 = 5000.0 self.lande = 1.2 self.constant = -4.6686e-13 * self.lambda0 * self.lande * 3e5
def Pol_Legendre(N, M, X): """ function from scipy directly """ Plm_z, Plm_dz = lpmn(M, N, X) for n in range(0, Plm_z.shape[0]): for m in range(0, n + 1): Plm_z[m, n] = Plm_z[m, n] * Normalize(n, m) return Plm_z.T, Plm_dz.T # use Plm_z[m, l]
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 cmp_LPQL(Nx,xmin,xmax, maxm,maxl, ist, Sol, Ck, Modd): Xx=1-xmin+logspace(log10(xmin),log10(xmax),Nx) # For rombohedral method we need the change of variable to equidistant mesh # We can change the variable Int[f(x),{x,1,Inf}] = Int[ exp(t) f(1-xmin+exp(t)), {t, log(xmin),inf}] # Here t is distributed in linear mesh with spacing dxi, and exp(t)=x-1+xmin, because we # constructued logarithmic mesh by x=1-xmin+exp(t) Expu = Xx-1.+xmin dxi = (log(Expu[-1])-log(Expu[0]))/(len(Expu)-1.) Qlm_all = array([special.lqmn(maxm,maxl,x)[0] for x in Xx]) Plm_all = array([special.lpmn(maxm,maxl,x)[0] for x in Xx]) Qlm_all[0]=0.0 # This diverges, hence we set it to zero LPL = zeros((len(ist),maxl+1,len(Xx)),dtype=float) LQL = zeros((len(ist),maxl+1,len(Xx)),dtype=float) LPxL= zeros((len(ist),maxl+1,len(Xx)),dtype=float) LQxL= zeros((len(ist),maxl+1,len(Xx)),dtype=float) LLP = zeros((len(ist),maxl+1,len(Xx)),dtype=float) LLQ = zeros((len(ist),maxl+1,len(Xx)),dtype=float) LLPx= zeros((len(ist),maxl+1,len(Xx)),dtype=float) LLQx= zeros((len(ist),maxl+1,len(Xx)),dtype=float) for i,(i1,i2) in enumerate(ist): (R1,Ene1,m1,p1,A1) = Sol[i1] (R2,Ene2,m2,p2,A2) = Sol[i2] print 'i1=', i1, 'i2=', i2, 'm1=', m1, 'm2=', m2 m = abs(m1-m2) Qlm = transpose(Qlm_all[:,m]) Plm = transpose(Plm_all[:,m]) LL = array([Lambda(x,m1,p1,Ck[i1]) * Lambda(x,m2,p2,Ck[i2]) for ix,x in enumerate(Xx)]) for il in range(m,maxl+1): odd = (Modd[i1]+Modd[i2]+il+m)%2 if odd: continue LLQ [i,il,:] = LL * Qlm[il,:] LLQx[i,il,:] = LLQ[i,il,:] * Xx**2 LLP [i,il,:] = LL * Plm[il,:] LLPx[i,il,:] = LLP[i,il,:] * Xx**2 for ix in range(len(Xx)): LPL [i,il,ix] = simps(LLP [i,il,:ix+1],Xx[:ix+1]) LPxL[i,il,ix] = simps(LLPx[i,il,:ix+1],Xx[:ix+1]) LQL [i,il,ix] = simps(LLQ [i,il,ix:],Xx[ix:]) LQxL[i,il,ix] = simps(LLQx[i,il,ix:],Xx[ix:]) return (LPL, LQL, LPxL, LQxL, LLP, LLQ, LLPx, LLQx)
def integrand(xi, costheta): l = numpy.arange(0, L)[numpy.newaxis, :] r = _xiToR(xi,a) R = r*numpy.sqrt(1 - costheta**2.) z = r*costheta Legandre = lpmn(0,L-1,costheta)[0].T[numpy.newaxis,:,0] dV = (1. + xi)**2. * numpy.power(1. - xi, -4.) phi_nl = a**3*(1. + xi)**l * (1. - xi)**(l + 1.)*_C(xi, N, L)[:,:] * Legandre param[0] = R param[1] = z return phi_nl*dV * dens(*param)
def integrand(xi, costheta): l = nu.arange(0, L)[nu.newaxis, :] r = _xiToR(xi,a) R = r*nu.sqrt(1 - costheta**2.) z = r*costheta Legandre = lpmn(0,L-1,costheta)[0].T[nu.newaxis,:,0] dV = (1. + xi)**2. * nu.power(1. - xi, -4.) phi_nl = a**3*(1. + xi)**l * (1. - xi)**(l + 1.)*_C(xi, N, L)[:,:] * Legandre param[0] = R param[1] = z return phi_nl*dV * dens(*param)
def test_assocLegendre_renorm(): x = linspace(-1.0, 1.0, 100) ap_it = assocLegendre_renorm_it(x) for l in xrange(0, 100): for m in xrange(0, l+1): print "l = %s, m = %s" % (l,m) Plm = assoc_legendre_p(l, m, x) Plm_scipy = array([lpmn(m,l,xi)[0][-1][-1] for xi in x]) Plm_it = fact2(2*l-1)*ap_it.next() dif = sum(abs(Plm_scipy - Plm_it))/sum(abs(Plm_scipy)) print "dif = %s" % dif assert dif < 1e-10
def N(n, m, theta, phi, r, k): """electric vector spherical function""" # Pnm = legendre(n,m,theta) Pnm = special.lpmn(m,n, np.cos(theta))[0][abs(m)][n] H = spherical_hankel(n, k*r) Hp = spherical_hankel(n, k*r, 1) r_comp = n*(n+1)*Pnm*H/(k*r)*np.exp(1j*m*phi) theta_comp = tau_func(n,m,theta) phi_comp = 1j*pi_func(n,m,theta) const = (H + r*k*Hp)*np.exp(1j*m*phi)/(k*r) theta_comp *= const phi_comp *= const return np.array([r_comp, theta_comp, phi_comp])
def legendre(xv, order): legout=numpy.zeros((order*(order+2),len(xv))) dlegout=legout.copy() m,l=degrees(order, start=1) sch=schmidt(m,l) for i,x in enumerate(xv): leg, dleg = lpmn(order,order,x) legout[:,i]= leg[abs(m),l]*sch dlegout[:,i]= dleg[abs(m),l]*sch return legout, dlegout
def integrand(xi, costheta, phi): l = nu.arange(0, L)[nu.newaxis, :, nu.newaxis] m = nu.arange(0, L)[nu.newaxis,nu.newaxis,:] r = _xiToR(xi, a) R = r*nu.sqrt(1 - costheta**2.) z = r*costheta Legandre = lpmn(L - 1,L-1,costheta)[0].T[nu.newaxis,:,:] dV = (1. + xi)**2. * nu.power(1. - xi, -4.) phi_nl = - a**3*(1. + xi)**l * (1. - xi)**(l + 1.)*_C(xi, N, L)[:,:,nu.newaxis] * Legandre return dens(R,z, phi) * phi_nl[nu.newaxis, :,:,:]*nu.array([nu.cos(m*phi), nu.sin(m*phi)])*dV
def legendrePnm_z(n, m, z): if m > n: return 0.0 elif n < 0 or m < 0: # This should really be replaced with maxima return mat.execute_numerical("LegendreP", n, m, z) else: try: result = lpmn(m, n, z)[0][-1][-1] except ValueError: print n, " ", m raise Exception, "Value Error" return result
def _computeforce(self,R,z,phi=0,t=0): """ NAME: _computeforce PURPOSE: Evaluate the first derivative of Phi with respect to R, z and phi INPUT: R - Cylindrical Galactocentric radius z - vertical height phi - azimuth t - time OUTPUT: dPhi/dr, dPhi/dtheta, dPhi/dphi HISTORY: 2016-06-07 - Written - Aladdin """ Acos, Asin = self._Acos, self._Asin N, L, M = Acos.shape r, theta, phi = bovy_coords.cyl_to_spher(R,z,phi) new_hash= hashlib.md5(nu.array([R, z,phi])).hexdigest() if new_hash == self._force_hash: dPhi_dr = self._cached_dPhi_dr dPhi_dtheta = self._cached_dPhi_dtheta dPhi_dphi = self._cached_dPhi_dphi else: PP, dPP = lpmn(M-1,L-1,nu.cos(theta)) ##Get the Legendre polynomials PP = PP.T[None,:,:] dPP = dPP.T[None,:,:] phi_tilde = self._phiTilde(r, N, L)[:,:,nu.newaxis] dphi_tilde = self._dphiTilde(r,N,L)[:,:,nu.newaxis] m = nu.arange(0, M)[nu.newaxis, nu.newaxis, :] mcos = nu.cos(m*phi) msin = nu.sin(m*phi) dPhi_dr = -nu.sum((Acos*mcos + Asin*msin)*PP*dphi_tilde) dPhi_dtheta = -nu.sum((Acos*mcos + Asin*msin)*phi_tilde*dPP*(-nu.sin(theta))) dPhi_dphi =-nu.sum(m*(Asin*mcos - Acos*msin)*phi_tilde*PP) self._force_hash = new_hash self._cached_dPhi_dr = dPhi_dr self._cached_dPhi_dtheta = dPhi_dtheta self._cached_dPhi_dphi = dPhi_dphi return dPhi_dr,dPhi_dtheta,dPhi_dphi
def legendrePnm_theta(n, m, theta, harmtype="_{n,m}"): """ _{n}^{m} is the P_{n}^{m} type harmonic and _{n,m} is the P_{n,m} type harmonic """ if m > n: result = 0.0 elif n < 0 or m < 0: # This should really be replaced with maxima result = mat.execute_numerical("LegendreP", n, m, cos(theta)) else: result = lpmn(m, n, cos(theta))[0][-1][-1] if harmtype == "_{n,m}": # print "OldResult: ",result result = result * pow(-1.0, float(m)) # print "newresult: ",result return result
def evaluate_V(self, eta_grid, m, mu): """ result = evaluate_V(eta_grid, m, mu) Evaluates V on a grid. V is the basis function for the eta coordinate. V is defined in eq. (8) in Kamta2005. Parameters ---------- eta_grid : 1D float array, the eta values for which one wants to evaluate V. m : integer, the angular momentum projection quantum number. mu : integer, some sort of quantum number associated with V. Returns ------- result : 1D complex array, the result of the evaluation. """ #Eq. (8) in Kamta2005. #Normalization factor, M^m_mu. M = self.find_M(m, mu) #Associated Legendre polynomial of the first kind. #P^{order}_{degree} => lpmn(order, degree) #Initalize array. legendre_factor = zeros(len(eta_grid), dtype=complex) #Function does not allow for array input. for i, eta in enumerate(eta_grid): #Function returns all degrees and orders up to those given. P, dP = lpmn(m, mu, eta) #Selects the correct polynomial. legendre_factor[i] = P[-1,-1] #All together now. result = M * legendre_factor return result
def get_inc(self, n, m, axisymm=False): """Return incident field expansion coefficients""" #if (self.Pna is None) or (len(self.Pna)!=n): self.Pna, self.Pdna = lpmn(n, n, cos(self.alpha))[:] self.sina = sin(self.alpha) sina = self.sina Pna = self.Pna[m, m:] l = arange(m, n + 1) if axisymm: c_inc = 1j ** l * (2 * l + 1.) / (l * (l + 1.)) * Pna else: Pdna = self.Pdna[m, m:] c_inc = zeros(2 * (n - m + 1), dtype=complex) if sina == 0. and m == 1: c_inc[:n - m + 1] = -1j ** (l - 1) * (2 * l + 1) else: c_inc[:n - m + 1] = -1j ** (l - 1) / sina\ * 2 * (2 * l + 1)\ * factorial(l - m) / factorial(l + m)\ * Pna return c_inc
def compute_Ylm(l, theta, phi): Y = np.zeros([np.size(phi), np.size(theta), 2*l+1]) L = np.zeros([l+1, np.size(theta)]) for the in range(0, np.size(theta)): Pmn_z, Pmn_dz = lpmn(l, l, np.cos(theta[0, the])) L[:,the] = Pmn_z[:,-1] for m in range(0, l+1): L[m, :] = L[m, :]*((-1)**m)*sqrt_function(l,m) L = np.sqrt(1/(2*math.pi))*L for m in range(-l,l+1): if (m>0): Y[:,:, l+m] = np.sqrt(2.0)*np.cos(phi*m)*L[m, :] elif (m<0): Y[:,:, l+m] = np.sqrt(2.0)*np.sin(phi*m)*L[-m, :] else: Y[:,:, l+m] = np.ones([M,1])*L[0, :] return Y
def get_approx(theta, phi, l_range, quad_precision, radius, rand_nums): ''' Get the matrix X ''' alpha_vec = get_alpha_vec(l_range, quad_precision, radius) output = np.zeros([np.size(theta), np.size(phi)], dtype = 'float64') coef1 = (0.5/np.sqrt(math.pi))*np.sqrt(alpha_vec[0]) coef2 = np.zeros(l_range, dtype = 'float64') coef3 = np.zeros([l_range, l_range], dtype = 'float64') for t in range(0, np.size(theta)): if np.mod(t,20) == 0: print 'Finished with ', t, 'of ', np.size(theta) th = theta[t] Pmn_z, Pmn_dz = lpmn(l_range, l_range, np.cos(th)) for l in range(1, l_range): coef2[l] = np.sqrt(alpha_vec[l])*Pmn_z[0, l]*np.sqrt((2*l+1)/(4*math.pi)) for m in range(1, l+1): coef3[l,m] = np.sqrt(2*alpha_vec[l])*Pmn_z[m,l]*factorial_function(l,m) for p in range(0, np.size(phi)): count = 0 ph = phi[p] output[t,p] += coef1*rand_nums[count] count += 1 for l in range(1, l_range): output[t,p] += coef2[l]*rand_nums[count] count += 1 for m in range(1, l+1): output[t,p] += (rand_nums[count]*np.cos(m*ph) + \ rand_nums[count+1]*np.sin(m*ph))*coef3[l,m] count += 2 return output/radius
def cmp_MPM(Ny, maxm,maxl, ist, ak, Modd): Xx = linspace(-1,1,Ny) MPM = zeros((len(ist),maxl+1),dtype=float) MPxM = zeros((len(ist),maxl+1),dtype=float) for i,(i1,i2) in enumerate(ist): (R1,Ene1,m1,p1,A1) = Sol[i1] (R2,Ene2,m2,p2,A2) = Sol[i2] print 'i1=', i1, 'i2=', i2, 'm1=', m1, 'm2=', m2 #, MPM,MPxM m = abs(m1-m2) Plm_all = array([special.lpmn(maxm,maxl,x)[0] for x in Xx]) MM = array([Mm(x,m1,p1,ak[i1]) * Mm(x,m2,p2,ak[i2]) for x in Xx]) Plm = transpose(Plm_all[:,m]) for il in range(m,maxl+1): odd = (Modd[i1]+Modd[i2]+il+m)%2 if not odd: # If the function is odd, we do not calculate! MMP = MM*Plm[il,:] MMPx = MMP * Xx**2 MPM [i,il] = integrate.romb(MMP, Xx[1]-Xx[0]) MPxM[i,il] = integrate.romb(MMPx,Xx[1]-Xx[0]) return (MPM,MPxM)
def sphere(self,ka,sosm,soss,sosshear,rhom,rhos,maxang,maxn): '''a function which calculates scattering cross sections for spheres according to Faran's theory; the output is a size of x3 vector giving the scattering length at 180 degrees and entries correspond to different values of ka (step size and max value of ka can be changed by manipulating the initialization of x3); note that the output is the absolute value of the scattering length (i.e. square root of the differential scattering cross section) times the wavenumber in the host medium (output is therefore unitless) ka = an array containing the (wavenumber)*(scatter radius) values over which scattering length will be calculated. sosm = speed of sound in host medium (fluid) soss = speed of sound in sphere sosshear = speed of sound for shear waves in sphere (if poisson's ratio (sigma)is available, sosshear=soss*sqrt((1-2*sigma)/2/(1-sigma))) rhom = host medium density rhos = sphere density maxang = maximum angle (in degrees) for which to calculate a cross section maxn = number of terms to include in the summation (higher number = greater accuracy but more computation time) %UNITS ARE OF NO CONSEQUENCE AS LONG AS THEY ARE CONSISTENT, I.E. %SPEEDS OF SOUND MUST HAVE THE SAME UNITS AND DENSITIES MUST HAVE THE SAME %UNITS %9/20/04 Tony Gerig %Hairong Shi added comments: % for glass beads we used in lab, Poisson's ratio sigma=0.21, %sosm=1540m/s %soss=5570m/s %so sosshear=3374.7m/s %rhom=1020 kg/m^3 %rhos=2540 kg/m^3 % %so an example to run this code is: % k3absscatlength = sphere(1540,5570,3374.7,1020,2540,180,100); ''' import numpy from scipy.special import lpmn #initialization theta= 180 x3=ka x2=x3*sosm/sosshear #ka value for shear waves in sphere x1=x3*sosm/soss #ka value for compressional waves in sphere #main loop over order n coeff = numpy.zeros((maxn + 1, len(x3)) ) + 1j*numpy.zeros((maxn + 1, len(x3))) for n in range(0,maxn + 1): #spherical bessel functions jx1=self.sphbess(n,x1) jx2=self.sphbess(n,x2) jx3=self.sphbess(n,x3) #spherical neumann functions nx3=self.sphneumm(n,x3) #derivatives of spherical bessel and neumann functions jpx3=n/(2*n+1.)*self.sphbess(n-1,x3)-(n+1)/(2*n+1.)*self.sphbess(n+1,x3) npx3=n/(2*n+1.)*self.sphneumm(n-1,x3)-(n+1)/(2*n+1.)*self.sphneumm(n+1,x3) jpx1=n/(2*n+1.)*self.sphbess(n-1,x1)-(n+1)/(2*n+1.)*self.sphbess(n+1,x1) jpx2=n/(2*n+1.)*self.sphbess(n-1,x2)-(n+1)/(2*n+1.)*self.sphbess(n+1,x2) #calculation of tandelta, tanalpha, tanbeta tandeltax3=-jx3/nx3 tanalphax3=-x3*jpx3/jx3 tanbetax3=-x3*npx3/nx3 tanalphax1=-x1*jpx1/jx1 tanalphax2=-x2*jpx2/jx2 #calculation of tanxsi [eq. 30] term1=tanalphax1/(tanalphax1+1) term2=(n**2+n)/(n**2+n-1-0.5*x2**2+tanalphax2) term3=(n**2+n-0.5*x2**2+2*tanalphax1)/(tanalphax1+1) term4=((n**2+n)*(tanalphax2+1))/(n**2+n-1-0.5*x2**2+tanalphax2) tanxsi=-x2**2/2*(term1-term2)/(term3-term4) #calculation of tanphi [eq. 29] tanPhi = -rhom/rhos*tanxsi #calculation of coefficient (2n+1)*sin(eta)*cos(eta) part of [eqn. 31] taneta=tandeltax3*(tanPhi+tanalphax3)/(tanPhi+tanbetax3) coeff[n,:]=(2*n+1)*taneta/(1+taneta**2)+1j*(2*n+1)*taneta**2/(1+taneta**2) #legendre polynomials temp, deriv=lpmn(n,n,numpy.cos(numpy.pi/180*theta)) #taking the first row is effectively taking m = 0 legend=temp[0,:].reshape((1,maxn + 1)) #matrix mult completes summation over n [eqn. 31] k3absscatlength=abs(numpy.dot(legend,coeff)) output = k3absscatlength.reshape( len(x3) ) output[numpy.isnan(output)] = 0 return output
def legendre_p_via_lpmn(n, x): return lpmn(0, n, x)[0][0,-1]
r=i*2*dr+(2*rmin-1) else: r=1+(i-rNum+1)*2.0/rNum for j in range(thNum): th=j*dth XAvalues[i][j]=r*math.sin(th) YAvalues[i][j]=r*math.cos(th) #Create array for multipole coefficients multipoles=zeros((lNum)); #store P_l^1(cos(theta)) at the surface, used to solve multipoles. I have an array evaluated in midpoints to perform #the integrations, and another one solve on mesh points to perform alpha evaluation plone=zeros((lNum,thNum)); plone2=zeros((lNum,thNum)); for j in range(thNum): alp=special.lpmn(1, lNum+1, math.cos((j+0.5)*dth)) alp2=special.lpmn(1, lNum+1, math.cos(j*dth)) for l in range(lNum): plone[l][j]=alp[0][1][l+1] plone2[l][j]=alp2[0][1][l+1] #Create gray-scale printable colormap, cdict taken from user Damon McDougall-2 who posted it in the matplotlib mailing list cdict = {'red':((0.000, 0.00, 0.00), (0.125, 0.15, 0.15), (0.250, 0.30, 0.30), (0.375, 0.60, 0.60), (0.500, 1.00, 1.00), (0.625, 0.90, 0.90), (0.750, 0.90, 0.90), (0.875, 0.90, 0.90), (1.000, 1.00, 1.00)),
def legendre(n,m,theta, deriv=0): Pnm = special.lpmn(m,n, np.cos(theta))[deriv][abs(m)][n] return Pnm
def __init__(self, NSIDE, npix, lmax=10, clv=True): """ Args: NSIDE (int) : the healpix NSIDE parameter, must be a power of 2, less than 2**30 npix (int) : number of pixel in the X and Y axis of the final projected map rot_velocity (float) : rotation velocity of the star in the equator in km/s Returns: None """ self.NSIDE = int(NSIDE) self.npix = int(npix) self.hp_npix = hp.nside2npix(NSIDE) self.lmax = lmax self.n_coef_max = (1+lmax)**2 # self.rot_velocity = rot_velocity self.clv = clv # Generate the indices of all healpix pixels self.indices = np.arange(hp.nside2npix(NSIDE), dtype='int') self.n_healpix_pxl = len(self.indices) # Define the orthographic projector that generates the maps of the star on the plane of the sky self.projector = hp.projector.OrthographicProj(xsize=int(self.npix)) # This function returns the pixel associated with a vector (x,y,z). This is needed by the projector self.f_vec2pix = lambda x, y, z: hp.pixelfunc.vec2pix(int(self.NSIDE), x, y, z) self.polar_angle, self.azimuthal_angle = hp.pixelfunc.pix2ang(self.NSIDE, np.arange(self.n_healpix_pxl)) # Generate a mesh grid of X and Y points in the plane of the sky that covers only the observed hemisphere of the star x = np.linspace(-2.0,0.0,int(self.npix/2)) y = np.linspace(-1.0,1.0,int(self.npix/2)) X, Y = np.meshgrid(x,y) # Rotational velocity vector (pointing in the z direction and unit vector) omega = np.array([0,0,1]) # Compute the radial vector at each position in the map and the projected velocity on the plane of the sky radial_vector = np.array(self.projector.xy2vec(X.flatten(), Y.flatten())).reshape((3,int(self.npix/2),int(self.npix/2))) self.vel_projection = np.cross(omega[:,None,None], radial_vector, axisa=0, axisb=0)[:,:,0] # Compute the mu angle (astrocentric angle) self.mu_angle = radial_vector[0,:,:] # Generate a fake temperature map in the star using spherical harmonics # self.temperature_map = 5000 * np.ones(self.npix) # self.temperature_map = 5000 + 250 * hp.sphtfunc.alm2map(np.ones(10,dtype='complex'),self.NSIDE) #np.random.rand(self.n_healpix_pxl) * 2000 + 5000 # self.temperature_map = 5000 * np.ones(self.hp_npix) self.coeffs = hp.sphtfunc.map2alm(self.temperature_map) self.nlambda = 500 self.v = np.linspace(-100.0, 100.0, self.nlambda) self.d = 0.5 self.delta = 5.0 self.Plm = np.zeros((self.lmax+2, self.lmax+2, self.n_healpix_pxl)) self.dPlm = np.zeros((self.lmax+2, self.lmax+2, self.n_healpix_pxl)) self.Clm = np.zeros((self.lmax+2, self.lmax+2)) for i in range(self.n_healpix_pxl): self.Plm[:,:,i], self.dPlm[:,:,i] = sp.lpmn(self.lmax+1, self.lmax+1, np.cos(self.polar_angle[i])) self.dPlm[:,:,i] *= -np.sin(self.polar_angle[i]) for l in range(self.lmax+2): for m in range(0, l+1): self.Clm[m,l] = np.sqrt((2.0*l+1) / (4.0*np.pi) * mi.factorial(l-m) / mi.factorial(l+m)) self.lambda0 = 5000.0 self.lande = 1.2 self.constant = -4.6686e-13 * self.lambda0 * self.lande * 3e5
def lpn_normalized(n, z): vals, _ = lpmn(0, n, z) return vals[0][n] * np.sqrt(n+0.5)
def get_Pmn(m, n, x): return array([lpmn(m, n, xl) for xl in x])
def set_funcs_ang(self): P = array([special.lpmn(self.n, self.n, ct) for ct in self.cost]) self.data_Ang, self.data_Angd = P[:, 0, :, :], P[:, 1, :, :]
def lpnm(n, m, z): if m > n: return 0.0 return sc.lpmn(m, n, z)[0][-1,-1]