def solve(self, init, x): A = np.zeros((2, 2)) A[0][0] = special.sph_jn(self.l, self.function(x[0]))[0][self.l] A[0][1] = special.sph_yn(self.l, self.function(x[0]))[0][self.l] A[1][0] = self.function.deriv(1)(x[0]) * special.sph_jn( self.l, self.function(x[0]))[1][self.l] A[1][1] = self.function.deriv(1)(x[0]) * special.sph_yn( self.l, self.function(x[0]))[1][self.l] c = np.linalg.solve(A, init) 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.sph_jn(self.l,self.function(x[i]))[j][self.l] + \ c[1]*special.sph_yn(self.l,self.function(x[i]))[j][self.l] elif j == 1: y[i][j] = \ c[0]*self.function.deriv(1)(x[i])*special.sph_jn(self.l,self.function(x[i]))[j][self.l] + \ c[1]*self.function.deriv(1)(x[i])*special.sph_yn(self.l,self.function(x[i]))[j][self.l] self.x = x self.y = y return y
def test_mie_internal_coeffs(): m = 1.5 + 0.1j x = 50. n_stop = miescatlib.nstop(x) al, bl = miescatlib.scatcoeffs(m, x, n_stop) cl, dl = miescatlib.internal_coeffs(m, x, n_stop) jlx = sph_jn(n_stop, x)[0][1:] jlmx = sph_jn(n_stop, m * x)[0][1:] hlx = jlx + 1.j * sph_yn(n_stop, x)[0][1:] assert_allclose(cl, (jlx - hlx * bl) / jlmx, rtol=1e-6, atol=1e-6) assert_allclose(dl, (jlx - hlx * al) / (m * jlmx), rtol=1e-6, atol=1e-6)
def test_mie_internal_coeffs(): m = 1.5 + 0.1j x = 50. n_stop = miescatlib.nstop(x) al, bl = miescatlib.scatcoeffs(m, x, n_stop) cl, dl = miescatlib.internal_coeffs(m, x, n_stop) jlx = sph_jn(n_stop, x)[0][1:] jlmx = sph_jn(n_stop, m * x)[0][1:] hlx = jlx + 1.j * sph_yn(n_stop, x)[0][1:] assert_allclose(cl, (jlx - hlx * bl) / jlmx, rtol = 1e-6, atol = 1e-6) assert_allclose(dl, (jlx - hlx * al)/ (m * jlmx), rtol = 1e-6, atol = 1e-6)
def bessel(l, q): """ Parameters: q : product of k.del(r) l : order of the spherical bessel function; ToDo: Instead of closed form (form Mathematica), think about just using special.sph_jn(l,q) from python """ if l == 0: if q == 0: return 1 return np.sin(q) / q elif l == 2: if q == 0: return 0 return (-3 * np.cos(q)) / q**2 + ((3 - q**2) * np.sin(q)) / q**3 elif l == 4: if q == 0: return 0 return (5 * (-21 + 2 * q**2) * np.cos(q)) / q**4 + ( (105 - 45 * q**2 + q**4) * np.sin(q)) / q**5 else: jn = special.sph_jn(l, q)[0][ 2] #this routine in python computes the spehrical bessel function and its first #derivates. I only want one value. See documentation return jn
def jn_zeros(n, k, method="sympy", dps=15): """ Zeros of the spherical Bessel function of the first kind. This returns an array of zeros of jn up to the k-th zero. * method = "sympy": uses mpmath besseljzero * method = "scipy": uses the SciPy's sph_jn and newton to find all roots, which is faster than computing the zeros using a general numerical solver, but it requires SciPy and only works with low precision floating point numbers. [the function used with method="sympy" is a recent addition to mpmath, before that a general solver was used] Examples ======== >>> from sympy import jn_zeros >>> jn_zeros(2, 4, dps=5) [5.7635, 9.095, 12.323, 15.515] See Also ======== jn, yn, besselj, besselk, bessely """ from math import pi if method == "sympy": from sympy.mpmath import besseljzero from sympy.mpmath.libmp.libmpf import dps_to_prec from sympy import Expr prec = dps_to_prec(dps) return [Expr._from_mpmath(besseljzero(S(n + 0.5)._to_mpmath(prec), int(k)), prec) for k in xrange(1, k + 1)] elif method == "scipy": from scipy.special import sph_jn from scipy.optimize import newton f = lambda x: sph_jn(n, x)[0][-1] else: raise NotImplementedError("Unknown method.") def solver(f, x): if method == "scipy": root = newton(f, x) else: raise NotImplementedError("Unknown method.") return root # we need to approximate the position of the first root: root = n + pi # determine the first root exactly: root = solver(f, root) roots = [root] for i in range(k - 1): # estimate the position of the next root using the last root + pi: root = solver(f, root + pi) roots.append(root) return roots
def jpseudize(self, a_g, gc, l=0, points=4): """Construct spherical Bessel function continuation of a_g for g<gc. Returns (b_g, b(0)/r^l) such that b_g=a_g for g >= gc and:: P-2 b = Sum c_p j (q r ) g p=0 l p g for g < gc+P, where. """ from scipy.special import sph_jn from scipy.optimize import brentq if a_g[gc] == 0: return self.zeros(), 0.0 assert isinstance(gc, int) and gc > 10 zeros_l = [[1, 2, 3, 4, 5, 6], [1.430, 2.459, 3.471, 4.477, 5.482, 6.484], [1.835, 2.895, 3.923, 4.938, 5.949, 6.956], [2.224, 3.316, 4.360, 5.387, 6.405, 7.418]] # Logarithmic derivative: ld = np.dot([-1 / 60, 3 / 20, -3 / 4, 0, 3 / 4, -3 / 20, 1 / 60], a_g[gc - 3:gc + 4]) / a_g[gc] / self.dr_g[gc] rc = self.r_g[gc] def f(q): j, dj = (y[-1] for y in sph_jn(l, q * rc)) return dj * q - j * ld j_pg = self.empty(points - 1) q_p = np.empty(points - 1) zeros = zeros_l[l] if rc * ld > l: z1 = zeros[0] zeros = zeros[1:] else: z1 = 0 x = 0.01 for p, z2 in enumerate(zeros[:points - 1]): q = brentq(f, z1 * pi / rc + x, z2 * pi / rc - x) j_pg[p] = [sph_jn(l, q * r)[0][-1] for r in self.r_g] q_p[p] = q z1 = z2 C_dg = [[0, 0, 0, 1, 0, 0, 0], [1 / 90, -3 / 20, 3 / 2, -49 / 18, 3 / 2, -3 / 20, 1 / 90], [1 / 8, -1, 13 / 8, 0, -13 / 8, 1, -1 / 8], [-1 / 6, 2, -13 / 2, 28 / 3, -13 / 2, 2, -1 / 6]][:points - 1] c_p = np.linalg.solve(np.dot(C_dg, j_pg[:, gc - 3:gc + 4].T), np.dot(C_dg, a_g[gc - 3:gc + 4])) b_g = a_g.copy() b_g[:gc + 2] = np.dot(c_p, j_pg[:, :gc + 2]) return b_g, np.dot(c_p, q_p**l) * 2**l * fac[l] / fac[2 * l + 1]
def jpseudize(self, a_g, gc, l=0, points=4): """Construct spherical Bessel function continuation of a_g for g<gc. Returns (b_g, b(0)/r^l) such that b_g=a_g for g >= gc and:: P-2 b = Sum c_p j (q r ) g p=0 l p g for g < gc+P, where. """ from scipy.special import sph_jn from scipy.optimize import brentq if a_g[gc] == 0: return self.zeros(), 0.0 assert isinstance(gc, int) and gc > 10 zeros_l = [[1, 2, 3, 4, 5, 6], [1.430, 2.459, 3.471, 4.477, 5.482, 6.484], [1.835, 2.895, 3.923, 4.938, 5.949, 6.956], [2.224, 3.316, 4.360, 5.387, 6.405, 7.418]] # Logarithmic derivative: ld = np.dot([-1 / 60, 3 / 20, -3 / 4, 0, 3 / 4, -3 / 20, 1 / 60], a_g[gc - 3:gc + 4]) / a_g[gc] / self.dr_g[gc] rc = self.r_g[gc] def f(q): j, dj = (y[-1] for y in sph_jn(l, q * rc)) return dj * q - j * ld j_pg = self.empty(points - 1) q_p = np.empty(points - 1) zeros = zeros_l[l] if rc * ld > l: z1 = zeros[0] zeros = zeros[1:] else: z1 = 0 x = 0.01 for p, z2 in enumerate(zeros[:points - 1]): q = brentq(f, z1 * pi / rc + x, z2 * pi / rc - x) j_pg[p] = [sph_jn(l, q * r)[0][-1] for r in self.r_g] q_p[p] = q z1 = z2 C_dg = [[0, 0, 0, 1, 0, 0, 0], [1 / 90, -3 / 20, 3 / 2, -49 / 18, 3 / 2, -3 / 20, 1 / 90], [1 / 8, -1, 13 / 8, 0, -13 / 8, 1, -1 / 8], [-1 / 6, 2, -13 / 2, 28 / 3, -13 / 2, 2, -1 / 6]][:points - 1] c_p = np.linalg.solve(np.dot(C_dg, j_pg[:, gc - 3:gc + 4].T), np.dot(C_dg, a_g[gc - 3:gc + 4])) b_g = a_g.copy() b_g[:gc + 2] = np.dot(c_p, j_pg[:, :gc + 2]) return b_g, np.dot(c_p, q_p**l) * 2**l * fac(l) / fac(2 * l + 1)
def translator (r, s, phi, theta, l): ''' Compute the diagonal translator for a translation distance r, a translation direction s, azimuthal samples specified in the array phi, polar samples specified in the array theta, and a truncation point l. ''' # The radial argument kr = 2. * math.pi * r # Compute the radial component hl = spec.sph_jn(l, kr)[0] + 1j * spec.sph_yn(l, kr)[0] # Multiply the radial component by scale factors in the translator m = numpy.arange(l + 1) hl *= (1j / 4. / math.pi) * (1j)**m * (2. * m + 1.) # Compute Legendre angle argument dot(s,sd) for sample directions sd stheta = numpy.sin(theta)[:,numpy.newaxis] sds = (s[0] * stheta * numpy.cos(phi)[numpy.newaxis,:] + s[1] * stheta * numpy.sin(phi)[numpy.newaxis,:] + s[2] * numpy.cos(theta)[:,numpy.newaxis]) # Initialize the translator tr = 0 # Sum the terms of the translator for hv, pv in zip(hl, poly.legpoly(sds, l)): tr += hv * pv return tr
def uExactDirichletTrace(self, point): x, y, z = point r = np.sqrt(x**2 + y**2 + z**2) hD, dhD = sph_jn(self.l_max, self.kExt) + 1j * sph_yn(self.l_max, self.kExt * r) Y, dY = lpn(self.l_max, x / r) return (self.cDir * hD * Y).sum()
def bessel(l, q): """ Parameters: q : product of k.del(r) l : order of the spherical bessel function; sensible values = 0,2,4 """ """ if l == 0: if q == 0: return 1 return np.sin(q)/q elif l == 2: if q == 0: return 0 return (-3*np.cos(q))/q**2 + ((3 - q**2)*np.sin(q))/q**3 elif l == 4: if q == 0: return 0 return (5*(-21 + 2*q**2)*np.cos(q))/q**4 + ((105 - 45*q**2 + q**4)*np.sin(q))/q**5 else: print("L must be 0, 2 or 4") """ sphbessel = special.sph_jn(l, q)[0][l] return sphbessel
def jn_zeros(n, k, method="sympy", dps=15): """ Zeros of the spherical Bessel function of the first kind. This returns an array of zeros of jn up to the k-th zero. * method = "sympy": uses mpmath besseljzero * method = "scipy": uses the SciPy's sph_jn and newton to find all roots, which is faster than computing the zeros using a general numerical solver, but it requires SciPy and only works with low precision floating point numbers. [the function used with method="sympy" is a recent addition to mpmath, before that a general solver was used] Examples ======== >>> from sympy import jn_zeros >>> jn_zeros(2, 4, dps=5) [5.7635, 9.095, 12.323, 15.515] See Also ======== jn, yn, besselj, besselk, bessely """ from math import pi if method == "sympy": from sympy.mpmath import besseljzero from sympy.mpmath.libmp.libmpf import dps_to_prec from sympy import Expr prec = dps_to_prec(dps) return [Expr._from_mpmath(besseljzero(S(n + 0.5)._to_mpmath(prec), int(k)), prec) \ for k in xrange(1, k + 1)] elif method == "scipy": from scipy.special import sph_jn from scipy.optimize import newton f = lambda x: sph_jn(n, x)[0][-1] else: raise NotImplementedError("Unknown method.") def solver(f, x): if method == "scipy": root = newton(f, x) else: raise NotImplementedError("Unknown method.") return root # we need to approximate the position of the first root: root = n + pi # determine the first root exactly: root = solver(f, root) roots = [root] for i in range(k - 1): # estimate the position of the next root using the last root + pi: root = solver(f, root + pi) roots.append(root) return roots
def __init__(self, k): self.k = k self.kExt = k l_max = 200 l = np.arange(0, l_max + 1) jExt, djExt = sph_jn(l_max, self.kExt) yExt, dyExt = sph_yn(l_max, self.kExt) hExt = jExt + 1j * yExt aInc = (2 * l + 1) * 1j**l np.seterr(divide='ignore', invalid='ignore') cBound = 1 / (1j * self.kExt) / hExt cDir = jExt / hExt for l in range(l_max + 1): if abs(cBound[l]) < 1e-16: # neglect all further terms l_max = l - 1 aInc = aInc[:l] cBound = cBound[:l] cDir = cDir[:l] break self.cDir = cDir self.aInc = aInc self.cBound = cBound self.l_max = l_max
def __init__(self, k): self.k = k kExt = k l_max = 200 l = np.arange(0, l_max + 1) jExt, djExt = sph_jn(l_max, kExt) yExt, dyExt = sph_yn(l_max, kExt) hExt = jExt + 1j * yExt aInc = (2 * l + 1) * 1j ** l np.seterr(divide='ignore', invalid='ignore') cBound = 1/(1j * kExt) / hExt cDir = jExt / hExt cBoundSq = (2l + 1) * 1j ** (l-2) / (hExt**2) / (kExt**2) / jExt for l in range(l_max + 1): if abs(cBound[l]) < 1e-16: # neglect all further terms l_max = l - 1 aInc = aInc[:l] cBound = cBound[:l] cBoundSq = cBoundSq[:l] cDir = cDir[:l] break self.cDir = cDir self.aInc = aInc self.cBound = cBound self.l_max = l_max self.cBoundSq = cBoundSq
def jl(l,k): q = k if l == 0: if q == 0: return 1 return np.sin(q)/q elif l == 2: if q == 0: return 0 return (-3*np.cos(q))/q**2 + ((3 - q**2)*np.sin(q))/q**3 elif l ==3: if q ==0: return 0 return ( ((-15+q**2) * np.cos(q))/q**3 - (3* (-5+2*q**2) * np.sin(q) )/q**4 ) elif l == 4: if q == 0: return 0 return (5*(-21 + 2*q**2)*np.cos(q))/q**4 + ((105 - 45*q**2 + q**4)*np.sin(q))/q**5 else: #print("L must be 0, 2 or 4") sphbessel = special.sph_jn(l,k)[0][l] return sphbessel
def jn_zeros(n, k, method="sympy"): """ Zeros of the spherical Bessel function of the first kind. This returns an array of zeros of jn up to the k-th zero. method = "sympy": uses the SymPy's jn and findroot to find all roots method = "scipy": uses the SciPy's sph_jn and newton to find all roots, which if faster than method="sympy", but it requires SciPy and only works with low precision floating point numbers Examples: >>> from sympy.mpmath import nprint >>> from sympy import jn_zeros >>> nprint(jn_zeros(2, 4)) [5.76345919689, 9.09501133048, 12.3229409706, 15.5146030109] """ if method == "sympy": from sympy.mpmath import findroot f = lambda x: jn(n, x).n() elif method == "scipy": from scipy.special import sph_jn from scipy.optimize import newton f = lambda x: sph_jn(n, x)[0][-1] elif method == 'mpmath': # this needs a recent version of mpmath, newer than in sympy from mpmath import besseljzero return [besseljzero(n + 0.5, k) for k in xrange(1, k + 1)] else: raise NotImplementedError("Unknown method.") def solver(f, x): if method == "sympy": # findroot(solver="newton") or findroot(solver="secant") can't find # the root within the given tolerance. So we use solver="muller", # which converges towards complex roots (even for real starting # points), and so we need to chop all complex parts (that are small # anyway). Also we need to set the tolerance, as it sometimes fail # without it. def f_real(x): return f(complex(x).real) root = findroot(f_real, x, solver="muller", tol=1e-9) root = complex(root).real elif method == "scipy": root = newton(f, x) else: raise NotImplementedError("Unknown method.") return root # we need to approximate the position of the first root: root = n+pi # determine the first root exactly: root = solver(f, root) roots = [root] for i in range(k-1): # estimate the position of the next root using the last root + pi: root = solver(f, root+pi) roots.append(root) return roots
def ASq(self, L): integrand = lambda kl: np.power(sph_jn(L, self.Lbox*kl)[0][-1], 2.0)*np.power(kl, self.ns-2.0) const = 64.*np.pi*self.A/(np.power(self.k0, self.ns-1.0)) klmax = np.pi/self.Lbox intresult = integrate.quad(integrand, self.klmin, klmax) self.asq0=const*intresult[0] self.L=L return self.asq0
def uExactBoundaryDirichletTrace(self, point, normal, domain_index, result): x, y, z = point r = np.sqrt(x**2 + y**2 + z**2) hD, dhD = sph_jn(self.l_max, self.kExt) + 1j * sph_yn(self.l_max, self.kExt * r) Y, dY = lpn(self.l_max, x / r) result[0] = (self.cDir * hD * Y).sum()
def bessel(l, q): """ Parameters: q : product of k.del(r) l : order of the spherical bessel function; L=l, l-1, l+2 """ sphbessel = special.sph_jn(l, q)[0][l] return sphbessel
def _sph_jn(n, x, derivative=False): sph_jn, deriv_sph_jn = special.sph_jn(n, x) if derivative: return deriv_sph_jn else: return sph_jn
def ASq(self, L): integrand = lambda kl: np.power(sph_jn(L, self.Lbox * kl)[0][-1], 2.0 ) * np.power(kl, self.ns - 2.0) const = 64. * np.pi * self.A / (np.power(self.k0, self.ns - 1.0)) klmax = np.pi / self.Lbox intresult = integrate.quad(integrand, self.klmin, klmax) self.asq0 = const * intresult[0] self.L = L return self.asq0
def solve(self, E=0.5): e = 5.9 s = 1. # 3.57 A, but we normalized to s r0 = .5 mh = 6.12 # find the position of the initial value for the numerov algorithm r0_pos = bisect_left(self._r, r0) # .... and initialize the solution up to that point using the solution for small r self._u[:r0_pos+1] = map(lambda r: exp(-sqrt(6.12*e/25.)/r**5), self._r[:r0_pos+1]) def solve4l(l): def CombinedPotential(r): return LennardJonesPotential(e, s, r) + l*(l+1)/(mh*r**2) # initialize the (combined) potential self._V = array(map(lambda r: CombinedPotential(r), self._r)) # initialize the k's, based on the potential self._k = mh*(E-self._V) for i in xrange(r0_pos, len(self._r)-1): self._u[i+1] = numerov(self._dr, self._k[i], self._u[i], self._k[i-1], self._u[i-1], self._k[i+1]) l_max = 10 s_tot = 0. for l in range(0, l_max+1): solve4l(l) r1 = self._r[-4] u1 = self._u[-4] r2 = self._r[-1] u2 = self._u[-1] K = r1*u2/(r2*u1) k = sqrt(E*mh) delta = arctan2( K*sph_jn(l, k*r1)[0][l] - sph_jn(l, k*r2)[0][l] , K*sph_yn(l, k*r1)[0][l] - sph_yn(l, k*r2)[0][l] ) s_tot += (2*l + 1)*sin(delta)**2 * 4*pi/k**2 print s_tot return s_tot
def Get_g_legendre(): ll = np.genfromtxt('Job_output_0/green_legendre_0.txt').transpose()[0] NL = len(ll) tnl = np.zeros([N_OMEGA,NL], np.complex_) l= np.arange(NL) # recover g(iw) from the legendre polynomial measurements, see for i in range(N_OMEGA): tnl[i]=(-1)**i*(1j)**(l+1)*np.sqrt(2*l+1)*sph_jn(NL-1,(2*i+1)*pi/2)[0] g = tnl.dot(ll) return(np.hstack([-g[::-1],g]))
def riccati_1(nmax, x): """Riccati bessel function of the 1st kind returns (r1, r1'), n=0,1,...,nmax""" jn, jnp = special.sph_jn(nmax, x) r0 = x * jn r1 = jn + x * jnp return np.array([r0, r1])
def amplitude(wf, R, edash, mu): # Mies F ~ JA + NB J ~ sin(kR)/kR # normalization sqrt(2 mu/pu hbar^2) = zz zz = np.sqrt(2*mu/const.pi)/const.hbar oo, n, nopen = wf.shape # two asymptotic points on wavefunction wf[:, j] i1 = oo-5 i2 = i1-1 x1 = R[i1]*1.0e-10 x2 = R[i2]*1.0e-10 A = np.zeros((nopen, nopen)) B = np.zeros((nopen, nopen)) oc = 0 for j in range(n): if edash[j] < 0: continue # open channel ke = np.sqrt(2*mu*edash[j]*const.e)/const.hbar rtk = np.sqrt(ke) kex1 = ke*x1 kex2 = ke*x2 j1 = sph_jn(0, kex1)[0]*x1*rtk*zz y1 = sph_yn(0, kex1)[0]*x1*rtk*zz j2 = sph_jn(0, kex2)[0]*x2*rtk*zz y2 = sph_yn(0, kex2)[0]*x2*rtk*zz det = j1*y2 - j2*y1 for k in range(nopen): A[oc, k] = (y2*wf[i1, j, k] - y1*wf[i2, j, k])/det B[oc, k] = (j1*wf[i2, j, k] - j2*wf[i1, j, k])/det oc += 1 AI = linalg.inv(A) K = B @ AI return K, AI, B
def SpherePlaneWave(k,x): """Find acoustic potential from planewave [1,0,0] scattered by sphere of radius 1. Potentials are solved for a points p = r*cos(x) and so r must be the same for all points.""" ka=k kr=k x=np.asarray(x,np.float).reshape(-1,) theta = np.arccos(x) N=0 badcells=False,False while any(badcells)==False: N += 100 n = np.arange(N+1) djnka = sph_jn(N,ka)[1] dynka = sph_yn(N,ka)[1] dhnka = djnka + 1j*dynka jnkr = sph_jn(N,kr)[0] ynkr = sph_yn(N,kr)[0] hnkr = jnkr + 1j*ynkr simplefilter("ignore") pscat= - (1j**n) * (2*n+1) * djnka * hnkr / dhnka simplefilter("default") badcells = np.isnan(pscat)+np.isinf(pscat) pscat = np.repeat([pscat],x.size,axis=0) * Pn(N,np.cos(theta)) pscat = pscat.compress(np.logical_not(badcells),axis=1) pinc = np.exp(1j*k*x) return np.sum(pscat,axis=1) + pinc
def Get_g_legendre(): ll = np.genfromtxt('Job_output_0/green_legendre_0.txt').transpose()[0] NL = len(ll) tnl = np.zeros([N_OMEGA, NL], np.complex_) l = np.arange(NL) # recover g(iw) from the legendre polynomial measurements, see for i in range(N_OMEGA): tnl[i] = (-1)**i * (1j)**(l + 1) * np.sqrt(2 * l + 1) * sph_jn( NL - 1, (2 * i + 1) * pi / 2)[0] g = tnl.dot(ll) return (np.hstack([-g[::-1], g]))
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 sh2fld (k, clm, r, t, p, reg = True): ''' Expand spherical harmonic coefficients clm for a wave number k over the grid range specified by spherical coordinates (r,t,p). Each coordinate should be a single-dimension array. If reg is False, use a singular expansion. Otherwise, use a regular one. ''' # Pull out the maximum degree and the required matrix leading dimension deg, lda = clm.shape[1], 2 * clm.shape[1] - 1 # If there are not enough harmonic orders, raise an exception if clm.shape[0] < lda: raise IndexError('Not enough harmonic coefficients.') # Otherwise, compress the coefficient matrix to eliminate excess values if clm.shape[0] > lda: clm = np.array([[clm[i,j] for j in range(deg)] for i in harmorder(deg-1)]) # Compute the radial term if reg: # Perform a regular expansion jlr = np.array([spec.sph_jn(deg-1, k*rx)[0] for rx in r]) else: # Perform a singular expansion jlr = np.array([spec.sph_jn(deg-1, k*rx)[0] + 1j * spec.sph_yn(deg-1, k*rx)[0] for rx in r]) # Compute the azimuthal term epm = np.array([[np.exp(1j * m * px) for px in p] for m in harmorder(deg-1)]) shxp = lambda c, y: np.array([[c[m,l] * y[abs(m),l] for l in range(deg)] for m in harmorder(deg-1)]) # Compute the polar term and multiply by harmonic coefficients ytlm = np.array([shxp(clm,poly.legassoc(deg-1,deg-1,tx)) for tx in t]) # Return the product on the specified grid fld = np.tensordot(jlr, np.tensordot(ytlm, epm, axes=(1,0)), axes=(1,1)) return fld.squeeze()
def SpherePlaneWave(k, x): """Find acoustic potential from planewave [1,0,0] scattered by sphere of radius 1. Potentials are solved for a points p = r*cos(x) and so r must be the same for all points.""" ka = k kr = k x = np.asarray(x, np.float).reshape(-1, ) theta = np.arccos(x) N = 0 badcells = False, False while any(badcells) == False: N += 100 n = np.arange(N + 1) djnka = sph_jn(N, ka)[1] dynka = sph_yn(N, ka)[1] dhnka = djnka + 1j * dynka jnkr = sph_jn(N, kr)[0] ynkr = sph_yn(N, kr)[0] hnkr = jnkr + 1j * ynkr simplefilter("ignore") pscat = -(1j**n) * (2 * n + 1) * djnka * hnkr / dhnka simplefilter("default") badcells = np.isnan(pscat) + np.isinf(pscat) pscat = np.repeat([pscat], x.size, axis=0) * Pn(N, np.cos(theta)) pscat = pscat.compress(np.logical_not(badcells), axis=1) pinc = np.exp(1j * k * x) return np.sum(pscat, axis=1) + pinc
def bf_coeff(l, km, k0, etam, eta0, r): """Ratios between (b1lm,f1lm) and a1lm. See the single_spherical_wave_scatter.nb file""" sph_j_kmr = sph_jn(l, km*r) sph_j_k0r = sph_jn(l, k0*r) sph_y_k0r = sph_yn(l, k0*r) jm = sph_j_kmr[0][l] h01 = sph_j_k0r[0][l] + 1j * sph_y_k0r[0][l] h02 = sph_j_k0r[0][l] - 1j * sph_y_k0r[0][l] Jm = jm + km * r * sph_j_kmr[1][l] H01 = h01 + k0 * r * (sph_j_k0r[1][l] + 1j * sph_y_k0r[1][l]) H02 = h02 + k0 * r * (sph_j_k0r[1][l] - 1j * sph_y_k0r[1][l]) denom1 = h01*Jm*k0*eta0 - H01*jm*km*etam b1_a1 = - (h02*Jm*k0*eta0 - H02*jm*km*etam) / denom1 f1_a1 = - k0 * sqrt(eta0*etam) * (H01*h02 - h01*H02) / denom1 denom2 = (H01*jm*km*eta0 - h01*Jm*k0*etam) b2_a2 = - (H02*jm*km*eta0 - h02*Jm*k0*etam) / denom2 f2_a2 = - k0 * sqrt(eta0*etam) * (-H01*h02 + h01*H02) / denom2 return (b1_a1, f1_a1, b2_a2, f2_a2)
def jn_sphere(n, x): """Spherical bessel function of first order with vector input, j1(k). Keyword arguments: n -- order x -- array of input values Return values: y -- output value for jn(x) """ out1, out2 = sph_jn(n, x) return out1[-1]
def populate_response_matrix(self): """ Populate the R matrix for the default range of l and n, or or over the range specified above """ truncated_nmax = Universe.truncated_nmax truncated_nmin = Universe.truncated_nmin truncated_lmax = Universe.truncated_lmax truncated_lmin = Universe.truncated_lmin lms = Universe.lms kfilter = Universe.kfilter # 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(Universe.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) k, theta, phi = Universe.k[ind], np.arctan2( Universe.ky[ind], Universe.kx[ind]), np.arccos(Universe.kz[ind] / Universe.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 Universe.R = np.zeros([NY, len(ind[1])], dtype=np.complex128) Universe.R = np.append(R_long[:, 0:len(ind[1]) / 2], R_long[:, len(ind[1]):3 * len(ind[1]) / 2], axis=1) return
def SpherePlaneWave2(k, a, r, theta, just_scattered=False): """Find acoustic potential from planewave [1,0,0] scattered by sphere of radius 1.""" ka = k * a x = r * np.cos(theta) N = 0 badcells = False, False while np.any(badcells) == False: N += 100 n = np.arange(N + 1) djnka = sph_jn(N, ka)[1] dynka = sph_yn(N, ka)[1] dhnka = djnka + 1j * dynka djnka = np.repeat([djnka], r.size, axis=0).reshape(r.size, N + 1) dhnka = np.repeat([dhnka], r.size, axis=0).reshape(r.size, N + 1) jnkr = np.vstack([sph_jn(N, kr)[0] for kr in k * r]) ynkr = np.vstack([sph_yn(N, kr)[0] for kr in k * r]) hnkr = jnkr + 1j * ynkr simplefilter("ignore") pscat = -(1j**n) * (2 * n + 1) * djnka * hnkr / dhnka simplefilter("default") badcells = np.isnan(pscat) + np.isinf(pscat) pscat *= Pn(N, np.cos(theta)) pscat = pscat.compress(np.all(np.logical_not(badcells) == True, axis=0), axis=1) if just_scattered: return np.sum(pscat, axis=1) else: return np.sum(pscat, axis=1) + np.exp(1j * k * x)
def ComputeInterstitialOverlap(Km, RMuffinTin, Vol): """ Overlap in the interstitials can be calculated outside the k-loop Please see Eq.46 on page 26 for the quantity O_{K'K}^I """ Olap_I = zeros((len(Km), len(Km)), dtype=float) for i in range(len(Km)): #Olap_I[i,i] = 1 - 4*pi*RMuffinTin**3/(3.*Vol) Olap_I[i, i] = 1 - 4 * pi * pow(RMuffinTin, 3) / (3. * Vol) for j in range(i + 1, len(Km)): KKl = sqrt(dot(Km[i] - Km[j], Km[i] - Km[j])) fbessel = special.sph_jn(1, KKl * RMuffinTin)[0][1] #Olap_I[i,j] = -4*pi*RMuffinTin**2*fbessel/(KKl*Vol) Olap_I[i, j] = -4 * pi * pow(RMuffinTin, 2) * fbessel / (KKl * Vol) Olap_I[j, i] = Olap_I[i, j] return Olap_I
def SpherePlaneWave2(k,a,r,theta,just_scattered=False): """Find acoustic potential from planewave [1,0,0] scattered by sphere of radius 1.""" ka=k*a x = r*np.cos(theta) N=0 badcells=False,False while np.any(badcells)==False: N += 100 n = np.arange(N+1) djnka = sph_jn(N,ka)[1] dynka = sph_yn(N,ka)[1] dhnka = djnka + 1j*dynka djnka = np.repeat([djnka],r.size,axis=0).reshape(r.size,N+1) dhnka = np.repeat([dhnka],r.size,axis=0).reshape(r.size,N+1) jnkr = np.vstack([sph_jn(N,kr)[0] for kr in k*r]) ynkr = np.vstack([sph_yn(N,kr)[0] for kr in k*r]) hnkr = jnkr + 1j*ynkr simplefilter("ignore") pscat= - (1j**n) * (2*n+1) * djnka * hnkr / dhnka simplefilter("default") badcells = np.isnan(pscat)+np.isinf(pscat) pscat *= Pn(N,np.cos(theta)) pscat = pscat.compress(np.all(np.logical_not(badcells)==True,axis=0),axis=1) if just_scattered: return np.sum(pscat,axis=1) else: return np.sum(pscat,axis=1) + np.exp(1j*k*x)
def calc_phase_shift(self, l, points): """Finds the phase shift of the wavelength using the method described in Gianozzi. Arguments: l: angular momentum number points: the array holding the solution to the Schrodinger equation Returns: delta: the phase shift """ #set up r1 and r2 using a r2 = self.rgrid[-1] wavelength = 2 * np.pi / self.ki r1_index = -int(2 * wavelength / self.stepsize) r1 = self.rgrid[r1_index] #pick out X(r1) and X(r2) chi2 = points[-1] chi1 = points[r1_index] #find K K = (r2 * chi1) / (r1 * chi2) #Get correct Bessel functions jl and nl and plug in r values #special.sph_jn(l,k*r) #special.sph_yn(l,k*r) # These functions actually return a list of two arrays: # - an array containing all jn up to l # - an array containing all jn' up to l #tan^-1 of 3.19 jn1 = special.sph_jn(l, self.ki * r1)[0][-1] yn1 = special.sph_yn(l, self.ki * r1)[0][-1] jn2 = special.sph_jn(l, self.ki * r2)[0][-1] yn2 = special.sph_yn(l, self.ki * r2)[0][-1] delta = np.arctan((K * jn2 - jn1) / (K * yn2 - yn1)) return delta
def calc_phase_shift(self, l, points): """Finds the phase shift of the wavelength using the method described in Gianozzi. Arguments: l: angular momentum number points: the array holding the solution to the Schrodinger equation Returns: delta: the phase shift """ #set up r1 and r2 using a r2 = self.rgrid[-1] wavelength = 2*np.pi/self.ki r1_index = -int(2*wavelength/self.stepsize) r1 = self.rgrid[r1_index] #pick out X(r1) and X(r2) chi2 = points[-1] chi1 = points[r1_index] #find K K = (r2*chi1)/(r1*chi2) #Get correct Bessel functions jl and nl and plug in r values #special.sph_jn(l,k*r) #special.sph_yn(l,k*r) # These functions actually return a list of two arrays: # - an array containing all jn up to l # - an array containing all jn' up to l #tan^-1 of 3.19 jn1 = special.sph_jn(l,self.ki*r1)[0][-1] yn1 = special.sph_yn(l,self.ki*r1)[0][-1] jn2 = special.sph_jn(l,self.ki*r2)[0][-1] yn2 = special.sph_yn(l,self.ki*r2)[0][-1] delta = np.arctan((K*jn2-jn1) / (K*yn2-yn1)) return delta
def SIGMA_TOT( E, U, lmax, h, a ): k = math.sqrt(2*E) JJ = scsp.sph_jn((lmax+2),k*2*a) NN = scsp.sph_yn((lmax+2),k*2*a) sig_l = [] sig_tot = 0. for l in range( 0 , lmax + 1): sig_l.append( SIGMA_L(l, E, U, h, a, JJ[0][l], NN[0][l], JJ[1][l], NN[1][l] ) ) sig_tot += sig_l[l] return [sig_tot , sig_l]
def SIGMA_TOT(E, U, lmax, h, a): k = math.sqrt(2 * E) N_max = 2 * int(a / h) - 5 JJ = scsp.sph_jn((lmax + 2), k * 2 * a) NN = scsp.sph_yn((lmax + 2), k * 2 * a) sig_l = [] sig_tot = 0. for l in range(0, lmax + 1): sig_l.append( SIGMA_L(l, E, U, h, a, JJ[0][l], NN[0][l], JJ[1][l], NN[1][l])) sig_tot += sig_l[l] return [sig_tot, sig_l]
def dlog_bessel_j(lmax, x): """Calculates logarithmic derivative of the spherical bessel functions It returns three quantities: (x*d/dx log(j_l(x)), j_l(x), the product of the first two) for l up to lmax The last entry is important for singular cases: when x is zero of bessel function. In this case the logarithmic derivative is diverging while j*dlog(j(x))/dx is not """ if (fabs(x) < 1e-5): #return [(l, x**l/misc.factorial2(2*l+1), l*x**l/misc.factorial2(2*l+1)) for l in range(lmax+1)] return [(l, pow(x, l) / misc.factorial2(2 * l + 1), l * pow(x, l) / misc.factorial2(2 * l + 1)) for l in range(lmax + 1)] else: (jls, djls) = special.sph_jn( lmax, x) # all jl's and derivatives for l=[0,...lmax] return [(x * djls[l] / jls[l], jls[l], x * djls[l]) for l in range(lmax + 1)]
def sigmatot( E ): k = math.sqrt(2*E) siT = 0. lmin = 0 lmax = 7 siI = [] JJ = scsp.sph_jn((lmax+2),k) NN = scsp.sph_yn((lmax+2),k) chi = CHI(E, lmax) for l in range(lmin, lmax+1): siI.append( sigmal( E, l, chi[l] , JJ[0][l], NN[0][l], JJ[1][l], NN[1][l] )) siT += siI[l] return (siT,siI,chi)
def populate_response_matrix(self): """ Populate the R matrix for the default range of l and n, or or over the range specified above """ truncated_nmax = Universe.truncated_nmax truncated_nmin = Universe.truncated_nmin truncated_lmax = Universe.truncated_lmax truncated_lmin = Universe.truncated_lmin lms = Universe.lms kfilter = Universe.kfilter # 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(Universe.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) k, theta, phi = Universe.k[ind], np.arctan2(Universe.ky[ind],Universe.kx[ind]), np.arccos(Universe.kz[ind]/Universe.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 Universe.R = np.zeros([NY,len(ind[1])], dtype=np.complex128) Universe.R = np.append(R_long[:,0:len(ind[1])/2], R_long[:,len(ind[1]):3*len(ind[1])/2], axis=1) return
def _mie_abcd(m, x): '''Computes a matrix of Mie coefficients, a_n, b_n, c_n, d_n, of orders n=1 to nmax, complex refractive index m=m'+im", and size parameter x=k0*a, where k0= wave number in the ambient medium, a=sphere radius; p. 100, 477 in Bohren and Huffman (1983) BEWI:TDD122 C. Matzler, June 2002''' nmax = np.round(2+x+4*x**(1.0/3.0)) mx = m * x # Get the spherical bessel functions of the first (j) and second (y) kind, # and their derivatives evaluated at x at order up to nmax j_x,jd_x,y_x,yd_x = ss.sph_jnyn(nmax, x) # The above function includes the 0 order bessel functions, which aren't used j_x = j_x[1:] jd_x = jd_x[1:] y_x = y_x[1:] yd_x = yd_x[1:] # Get the spherical Hankel function of the first type (and it's derivative) # from the combination of the bessel functions h1_x = j_x + 1.0j*y_x h1d_x = jd_x + 1.0j*yd_x # Get the spherical bessel function of the first kind and it's derivative # evaluated at mx j_mx,jd_mx = ss.sph_jn(nmax, mx) j_mx = j_mx[1:] jd_mx = jd_mx[1:] # Get primes (d/dx [x*f(x)]) using derivative product rule j_xp = j_x + x*jd_x j_mxp = j_mx + mx*jd_mx h1_xp = h1_x + x*h1d_x m2 = m * m an = (m2 * j_mx * j_xp - j_x * j_mxp)/(m2 * j_mx * h1_xp - h1_x * j_mxp) bn = (j_mx * j_xp - j_x * j_mxp)/(j_mx * h1_xp - h1_x * j_mxp) ## cn = (j_x * h1_xp - h1_x * j_xp)/(j_mx * h1_xp - h1_x * j_mxp) ## dn = m * (j_x * h1_xp - h1_x * j_xp)/(m2 * j_mx * h1_xp -h1_x * j_mxp) return an, bn
def Woods_SaxonFormFactor(q, A): """Calculates Wood-Saxong's nuclcear form factor. Ref : SUPERSYMMETRIC DARK MATTER, G. JUNGMAN. Ec. 7.31 p. 271. @type q : float @param q : transfer momentum [eV] @type A : float @param A : mass number @rtype : float @return : Woods-Saxon's form factor """ s = 1.0 * pc.fermi R = 1.2 * A**(1 / 3) * pc.fermi r = np.sqrt(R**2 - 5.0 * s**2) return (3.0 * spe.sph_jn(q * r) / (q * r)) * np.exp(-((q * r)**2))
def ScatteringCoeff(incidentDirection): global a, kappa, numTerms Al = np.zeros((numTerms, 2 * numTerms + 1), dtype=np.complex) AA = np.zeros((2, 2), dtype=np.complex) j, jp = special.sph_jn(numTerms - 1, kappa * a) # array of Bessel 1st kind and its derivatives h, hp = special.sph_yn(numTerms - 1, a) # arrays of Bessel 2nd kind and its derivatives theta, phi = thetaphi(incidentDirection) for l in range(numTerms): Y = complexY(l, theta, phi) AA[0, 0], AA[0, 1] = j[l], -h[l] AA[1, 0], AA[1, 1] = kappa * jp[l], -hp[l] for m in np.arange(-l, l + 1): a0lm = pi4 * (1j ** l) * np.conjugate(Y[m + l]) RHS = [a0lm * j[l], a0lm * jp[l]] x = sci.linalg.solve(AA, RHS) # x, info = sci.sparse.linalg.gmres(ScatAmplitude,RHS) Al[l, m + l] = x[1] return Al
def bessel(l, q): """ Parameters: q : product of k.del(r) l : order of the spherical bessel function; sensible values = 0,2,4 """ """ if l == 0: if q == 0: return 1 return np.sin(q)/q elif l == 2: if q == 0: return 0 return (-3*np.cos(q))/q**2 + ((3 - q**2)*np.sin(q))/q**3 else: sphbessel = special.sph_jn(l,q)[0][l] return sphbessel """ sphbessel = special.sph_jn(l, q)[0][l] return sphbessel
def sph_jn_(n, x): return sph_jn(n.astype('l'), x)[0][-1]
def spherical_hankel(n, val, deriv = 0): """spherical hankel function""" a = special.sph_jn(n,val)[deriv][n] b = special.sph_yn(n,val)[deriv][n] return a + 1j*b
def j1d(z): return sph_jn(1, z)[1][1] from mantid.api import IFunction1D, FunctionFactory
def j1(z): return sph_jn(1, z)[0][1] def j1d(z): return sph_jn(1, z)[1][1]
def spherical_jn(n, x): return sph_jn(n, x)[0][-1]
def jl(l,x): return sps.sph_jn(l,x)[0][-1]
def get_Jn(n, x): return array([special.sph_jn(n, xl) for xl in x])
def f(r): # Sch eqn in Numerov form return 2*(E - V(r)) - L*(L+1)/(r*r) def wf(M, xm): # find w.f. and deriv at xm c = (h*h)/6. wfup, nup = ode.numerov(f, [0,.1], M, xL, h) # 1 step past xm dup = ((1+c*f(xm+h))*wfup[-1] - (1+c*f(xm-h))*wfup[-3])/(h+h) return wfup, dup/wfup[-2] xL, a, M = 0., 10., 200 # limits, matching point h, Lmax, E =(a-xL)/M, 15, 2. # step size, max L, energy k, ps = np.sqrt(2*E), np.zeros(Lmax+1) # wave vector, phase shift if scipy.__version__[0] < '1': jl, dj = sph_jn(Lmax, k*a) # (j_l, j_l') tuple nl, dn = sph_yn(Lmax, k*a) # (n_l, n_l') else: Lrange = range(Lmax + 1) jl, dj = sph_jn(Lrange, k*a, False), sph_jn(Lrange, k*a, True) # (j_l, j_l') nl, dn = sph_yn(Lrange, k*a, False), sph_yn(Lrange, k*a, True) # (n_l, n_l') for L in range(Lmax+1): u, g = wf(M, a) # g= u'/u x = np.arctan(((g*a-1)*jl[L] - k*a*dj[L])/ # phase shift ((g*a-1)*nl[L] - k*a*dn[L])) while (x < 0.0): x += np.pi # handle jumps by pi ps[L] = x theta, sigma = np.linspace(0., np.pi, 100), [] cos, La = np.cos(theta), np.arange(1,2*Lmax+2,2)
def f(q): j, dj = (y[-1] for y in sph_jn(l, q * rc)) return dj * q - j * ld
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 phase_eq(self,phase,r,l): ph = -2*self.m*self.k0*r**2*self.V(r) ph *= (cos(phase)*sph_jn(l,self.k0*r)[0][l]-sin(phase)*sph_yn(l,self.k0*r)[0][l])**2.0 return (ph)
def test_jn(self): n = 1234 x = 2300. right_ans = special.sph_jn(n, x)[0][-1] j = sph_bessel.jn(n, x) self.assertTrue(np.allclose(j, right_ans))
def mie_abcd(m, x): """Computes a matrix of Mie coefficients, a_n, b_n, c_n, d_n, of orders n=1 to nmax, complex refractive index m=m'+im", and size parameter x=k0*a, where k0= wave number in the ambient medium, a=sphere radius; p. 100, 477 in Bohren and Huffman (1983) BEWI:TDD122 C. Matzler, June 2002 Inputs: - m - scalar, refractive-index; - x - 1D array, size parameter; Outputs: - an - 1D array, Mie coefficient; - bn - 1D array, Mie coefficient. Example: >>> import scipy.special as ss >>> m = 5.62 + 2.78j # refractive index of water at 20 [Celsius] >>> d = 0.003 # drop diameter - 3 [mm] --> 0.003 [m] >>> lam = 0.01 # wavelength - 10 [mm] --> 0.01 [m] >>> x = np.pi * d / lam >>> an, bn = mie_abcd(m, x) >>> an array([ 3.28284411e-01 -3.36266733e-01j, 3.55370117e-03 -2.36426920e-02j, 3.90046294e-05 -5.15173202e-04j, 3.89223349e-07 -6.78235070e-06j, 2.94035836e-09 -5.85429913e-08j, 1.66462864e-11 -3.54797147e-10j, 7.17772878e-14 -1.58903782e-12j]) >>> bn array([ 7.69466132e-02 +1.28116779e-01j, 6.75408598e-03 +6.94984812e-03j, 1.99953419e-04 +8.05215919e-05j, 2.23969208e-06 +8.10161445e-08j, 1.39633882e-08 -2.58644268e-09j, 6.06975879e-11 -1.97461249e-11j, 2.01460986e-13 -8.42856046e-14j]) """ nmax = np.round(2 + x + 4 * x ** (1.0 / 3.0)) mx = m * x # Get the spherical bessel functions of the first (j) and second (y) kind, # and their derivatives evaluated at x at order up to nmax j_x, jd_x, y_x, yd_x = ss.sph_jnyn(nmax, x) # The above function includes the 0 order bessel functions, which aren't used j_x = j_x[1:] jd_x = jd_x[1:] y_x = y_x[1:] yd_x = yd_x[1:] # Get the spherical Hankel function of the first type (and it's derivative) # from the combination of the bessel functions h1_x = j_x + 1.0j * y_x h1d_x = jd_x + 1.0j * yd_x # Get the spherical bessel function of the first kind and it's derivative # evaluated at mx j_mx, jd_mx = ss.sph_jn(nmax, mx) j_mx = j_mx[1:] jd_mx = jd_mx[1:] # Get primes (d/dx [x*f(x)]) using derivative product rule j_xp = j_x + x * jd_x j_mxp = j_mx + mx * jd_mx h1_xp = h1_x + x * h1d_x m2 = m * m an = (m2 * j_mx * j_xp - j_x * j_mxp) / (m2 * j_mx * h1_xp - h1_x * j_mxp) bn = (j_mx * j_xp - j_x * j_mxp) / (j_mx * h1_xp - h1_x * j_mxp) return an, bn