def sphere_extinction_analytical(freqs, r): """Analytical expressions for a PEC sphere's extinction for plane wave with E = 1V/m Parameters ---------- freqs : ndarray Frequencies at which to calculate r : real Radius of sphere """ from scipy.special import sph_jnyn N = 40 k0r = freqs*2*np.pi/c*r #scs = np.zeros(len(k0r)) #scs_modal = np.zeros((len(k0r), N)) ecs_kerker = np.zeros(len(k0r)) for count, x in enumerate(k0r): jn, jnp, yn, ynp = sph_jnyn(N, x) h2n = jn - 1j*yn h2np = jnp - 1j*ynp a_n = ((x*jnp + jn)/(x*h2np + h2n))[1:] b_n = (jn/h2n)[1:] #scs[count] = 2*np.pi*sum((2*np.arange(1, N+1)+1)*(abs(a_n)**2 + abs(b_n)**2))/x**2 # #scs_modal[count] = 2*np.pi*(2*np.arange(1, N+1)+1)*(abs(a_n)**2 + abs(b_n)**2)/x**2 # ecs_kerker[count] = 2*np.pi*np.real(np.sum((2*np.arange(1, N+1)+1)*(a_n + b_n)))/x**2 return ecs_kerker*r**2/eta_0
def bessy(self, n, z): """Given order (n) and argument (z), computes mad bessel related junk. Argument can be a scalar or vector numeric. """ #http://docs.scipy.org/doc/scipy/reference/special.html # Returns all orders of N for a single argument (ie if order is 5, # returns n=0,1,2,3,4 for arg z. Pain in the ass actually... # sph_jnyn computes jn, derivjn, yn, derivyn in one pass jn, djn, yn, dyn = special.sph_jnyn(n,z) #Compute sph j/y in one pass i = 1j # Choose only the nth's bessel function jn=complex(jn[n]) yn=complex(yn[n]) djn=complex(djn[n]) dyn=complex(dyn[n]) hn=jn + i*yn #VERIFIED!!! dhn=djn + i*dyn #Derivative (d/dp (j + iy)) = (dj + idy) Psi=z*jn dPsi=z*djn + jn #Psi = p(jn) DPsi= jn + p j'n Chain rollin Zi=z*hn dZi=z*dhn + hn Xi=-z*yn #Xi=-i*(Zi + Psi) Verified WORKING either way! dXi=-(z*dyn + yn) #dXi=-i*(dZi + dPsi) return(Psi, dPsi, Zi, dZi, Xi, dXi)
def set_all_layers(self, lab): self.data_layers = [0] for bnd in lab.boundaries(): r, rd, rdd = bnd.shape.R(self.knots) rdr = rd / r r2rd2 = r**2 + rd**2 Rad = [0, {}, {}] Radd = [0, {}, {}] kis = [0, bnd.k1, bnd.k2] for i in [1, 2]: krs = kis[i] * r JY = array([special.sph_jnyn(self.n, kr) for kr in krs])[:, :, :] Rad[i] = { 'j': JY[:, 0, :], 'h': JY[:, 0, :] + 1j * JY[:, 2, :] } Radd[i] = { 'j': JY[:, 1, :], 'h': JY[:, 1, :] + 1j * JY[:, 3, :] } self.data_layers.append({'ki': kis,\ 'r': r,\ 'rd': rd,\ 'rdd': rdd,\ 'rdr': rdr,\ 'r2rd2': r2rd2,\ 'Rad': Rad,\ 'Radd': Radd})
def bessy(self, n, z): """Given order (n) and argument (z), computes mad bessel related junk. Argument can be a scalar or vector numeric. """ #http://docs.scipy.org/doc/scipy/reference/special.html # Returns all orders of N for a single argument (ie if order is 5, # returns n=0,1,2,3,4 for arg z. Pain in the ass actually... # sph_jnyn computes jn, derivjn, yn, derivyn in one pass jn, djn, yn, dyn = special.sph_jnyn(n, z) #Compute sph j/y in one pass i = 1j # Choose only the nth's bessel function jn = complex(jn[n]) yn = complex(yn[n]) djn = complex(djn[n]) dyn = complex(dyn[n]) hn = jn + i * yn #VERIFIED!!! dhn = djn + i * dyn #Derivative (d/dp (j + iy)) = (dj + idy) Psi = z * jn dPsi = z * djn + jn #Psi = p(jn) DPsi= jn + p j'n Chain rollin Zi = z * hn dZi = z * dhn + hn Xi = -z * yn #Xi=-i*(Zi + Psi) Verified WORKING either way! dXi = -(z * dyn + yn) #dXi=-i*(dZi + dPsi) return (Psi, dPsi, Zi, dZi, Xi, dXi)
def get_phase_shift_from_logder(self,logder,E,r): k = np.sqrt(2*self.mass*E) kr = k*r jl, jlp, yl, ylp = sph_jnyn(0,kr) iyl = 1j*yl iylp = 1j*ylp sl = -(jl-iyl)/(jl+iyl) * (logder-kr*(jlp-iylp)/(jl-iyl))/(logder-kr*(jlp+iylp)/(jl+iyl)) return np.angle(sl)/2.
def get_phase_shift_from_logder(self, logder, E, r): k = np.sqrt(2 * self.mass * E) kr = k * r jl, jlp, yl, ylp = sph_jnyn(0, kr) iyl = 1j * yl iylp = 1j * ylp sl = -(jl - iyl) / (jl + iyl) * (logder - kr * (jlp - iylp) / (jl - iyl)) / (logder - kr * (jlp + iylp) / (jl + iyl)) return np.angle(sl) / 2.
def jnyn( n, resolution ): delta = numpy.pi / resolution zTable = numpy.mgrid[delta:max( maxz_j( n ), maxz_y( n ) ):delta] jTable = numpy.zeros( ( len( zTable ), n + 1 ) ) yTable = numpy.zeros( ( len( zTable ), n + 1 ) ) for i, z in enumerate( zTable ): jTable[i], _, yTable[i], _ = special.sph_jnyn( n, z ) jTable = jTable.transpose() yTable = yTable.transpose() return zTable, jTable, yTable
def riccati_2(nmax, x): """Riccati bessel function of the 2nd kind returns (r2, r2'), n=0,1,...,nmax""" jn, jnp, yn, ynp = special.sph_jnyn(nmax, x) hn = jn + 1j * yn hnp = jnp + 1j * ynp r0 = x * hn r1 = hn + x * hnp return np.array([r0, r1])
def calculate_mie_coefficients(n_max, x, m): """ Calculates the Mie coefficients. :rtype : object :param n_max: :param x: size parameter :param m: """ # calculate spherical bessels # jn, djn, yn, dyn = sph_jnyn(n_max, x) # j(n, x), y(n, x) jm, djm, ym, dym = sph_jnyn(n_max, m * x) # j(n, mx), y(n, mx) # calculate spherical hankel # hn, dhn = sph_hn(n_max, x) # h(n, x) # calculate riccati bessel functions # dpsi_n = [x * jn[n - 1] - n * jn[n] for n in range(0, len(jn))] dpsi_m = [m * x * jm[n - 1] - n * jm[n] for n in range(0, len(jm))] dzeta_n = [x * hn[n - 1] - n * hn[n] for n in range(0, len(hn))] a_n = (m**2 * jm * dpsi_n - jn * dpsi_m) / (m**2 * jm * dzeta_n - hn * dpsi_m) b_n = (jm * dpsi_n - jn * dpsi_m) / (jm * dzeta_n - hn * dpsi_m) return a_n, b_n
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 jnyn(n, resolution): delta = numpy.pi / resolution z_table = numpy.mgrid[min(minz_j(n),minz_y(n)):max(maxz_j(n), maxz_y(n)):delta] j_table = numpy.zeros((len(z_table), n+1)) jdot_table = numpy.zeros((len(z_table), n+1)) y_table = numpy.zeros((len(z_table), n+1)) ydot_table = numpy.zeros((len(z_table), n+1)) for i, z in enumerate(z_table): j_table[i], jdot_table[i], y_table[i], ydot_table[i] \ = special.sph_jnyn(n, z) j_table = j_table.transpose() jdot_table = jdot_table.transpose() y_table = y_table.transpose() ydot_table = ydot_table.transpose() return z_table, j_table, jdot_table, y_table, ydot_table
def set_all_layers(self, lab): self.data_layers = [0] for bnd in lab.boundaries(): r, rd, rdd = bnd.shape.R(self.knots) rdr = rd / r r2rd2 = r ** 2 + rd ** 2 Rad = [0, {}, {}] Radd = [0, {}, {}] kis = [0, bnd.k1, bnd.k2] for i in [1, 2]: krs = kis[i] * r JY = array([special.sph_jnyn(self.n, kr) for kr in krs])[:, :, :] Rad[i] = {'j': JY[:, 0, :], 'h': JY[:, 0, :] + 1j * JY[:, 2, :]} Radd[i] = {'j': JY[:, 1, :], 'h': JY[:, 1, :] + 1j * JY[:, 3, :]} self.data_layers.append({'ki': kis,\ 'r': r,\ 'rd': rd,\ 'rdd': rdd,\ 'rdr': rdr,\ 'r2rd2': r2rd2,\ 'Rad': Rad,\ 'Radd': Radd})
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
def sph_hn(n, x): # calculate spherical hankel, h(n,x) = j(n,x) + iy(n,x) # jn, djn, yn, dyn = sph_jnyn(n, x) hn = jn + 1j * yn dhn = djn + 1j * dyn return hn, dhn
def get_JnHn(n, x): JnYn = array([special.sph_jnyn(n, xl) for xl in x]) return JnYn[:, :2, :], JnYn[:, :2, :] + 1j * JnYn[:, 2:, :]