def polarizability_CM(d, m): """Calculates Clausius-Mossoti polarizability of dipoles. Calcualtes Clausius-Mossoti Polarizability of dipole array according to their refractive indexes `m` and lattice spacing `d`. Parameters ---------- d : float Dipole lattice spacing m : array_like List of dipole refractive indexes Returns ------- alph: list List of dipole polarizabilities Notes ----- Currently only supports isotropic polarizabilities, extending to anisotropic polarizabilities should be trivial, References ---------- .. [1] Purcell, Edward M., and Carlton R. Pennypacker. "Scattering and absorption of light by nonspherical dielectric grains." The Astrophysical Journal 186 (1973): 705-714. """ pow2 = misc.power_function(2) pow3 = misc.power_function(3) N = m.size msqr = pow2(m) dcube = pow3(d) alpha_CM = numpy.divide( numpy.multiply(msqr - 1, 3 * dcube / (4 * numpy.pi)), (msqr + 2)) # Clausius-Mossotti alph = numpy.zeros([3 * N], dtype=numpy.complex128) # assuming same polarizability in x, y & z directions for j in range(N): alph[3 * (j - 1) + 0] = alpha_CM[j] alph[3 * (j - 1) + 1] = alpha_CM[j] alph[3 * (j - 1) + 2] = alpha_CM[j] return alph
def objective_collection(k, dipoles, P, NA, dist, samples=15): pow2 = misc.power_function(2) weights, r, theta = disk_quadrature.disk_quadrature_rule(samples, samples) alpha = numpy.arcsin(NA) maxradius = numpy.tan(alpha)*dist r *= maxradius rE = numpy.zeros([pow2(samples), 3]) for n in range(samples): for m in range(samples): rE[n*samples + m, 0] = numpy.sqrt(pow2(dist) + pow2(r[n])) rE[n*samples + m, 1] = theta[m] rE[n*samples + m, 2] = numpy.arctan(r[n]/dist) # calculate scattered field as a function of angles Esca = numpy.zeros([pow2(samples), 3], dtype=numpy.complex128) for ix, r_e in enumerate(rE): r_E = numpy.zeros(3) r_E[0], r_E[1], r_E[2] = misc.rtp2xyz(r_e[0], r_e[1], r_e[2]) Esca[ix, 0], Esca[ix, 1], Esca[ix, 2] = dda_funcs.E_sca_FF(k, dipoles, P, r_E) weights /= numpy.pi * pow2(maxradius) I = 0 for n in range(samples): for m in range(samples): I += pow2(k) * (rE[n*samples + m, 0]).T * numpy.dot(Esca[n*samples + m].conj(), Esca[n*samples + m])*weights[n] return I
def evanescent_E(E1s, E1p, theta_1, n1, n2): # E1p : TM E-field amplitude # E1s : TE E-field amplitude # theta_1 : incident angle # n1 : substrate reflective index # n2 : reflective index of the medium above the substrate, e.g., air # k2 : wave vector above the substrate # E2p : TM E-field vector # E2s : TE E-field vector pow2 = misc.power_function(2) k2, ep, es = evanescent_k_e(theta_1, n1, n2) T2s = (2 * n1 * numpy.cos(theta_1)) / ( n1 * numpy.cos(theta_1) + numpy.sqrt(pow2(n2) - pow2(n1 * numpy.sin(theta_1)) + 0j)) * E1s T2p = (2 * n1 * numpy.cos(theta_1)) / ( n2 * numpy.cos(theta_1) + (n1 / n2) * numpy.sqrt(pow2(n2) - pow2(n1 * numpy.sin(theta_1)) + 0j)) * E1p E2s = es * T2s E2p = ep * T2p return k2, E2s, E2p
def objective_collection_si(k, dipoles, P, n1, NA, dist, samples=15): pow2 = misc.power_function(2) weights, r, theta = disk_quadrature.disk_quadrature_rule(samples, samples) alpha = numpy.arcsin(NA) maxradius = numpy.tan(alpha)*dist r *= maxradius rE = numpy.zeros([samples*samples, 3]) for n in range(samples): for m in range(samples): rE[n*samples + m, 0] = numpy.sqrt(pow2(dist) + pow2(r[n])) rE[n*samples + m, 1] = theta[m] rE[n*samples + m, 2] = numpy.arctan(r[n]/dist) # calculate scattered field as a function of angles # parallel to incident plane #Esca = numpy.zeros([pow2(samples), 3]) Esca = dda_si_funcs.E_sca_SI(k, dipoles, P, rE[:, 0], rE[:, 1], rE[:, 2], n1) weights /= numpy.pi * pow2(maxradius) I = 0 for n in range(samples): for m in range(samples): I += pow2(k) * (rE[n*samples + m, 0]).T * numpy.dot(Esca[n*samples + m].conj(), Esca[n*samples + m])*weights[n] return I
def legendre_ek_compute(n): """ Gauss-Legendre, Elhay-Kautsky method. :param n: number of samples :return: x, points :return: w, weights """ pow2 = misc.power_function(2) zemu = 2.0 bj = numpy.zeros(n) for i in numpy.arange(n): ip1 = i + 1. bj[i] = numpy.sqrt(pow2(ip1) / (4. * pow2(ip1) - 1.)) x = numpy.zeros(n) w = numpy.zeros(n) w[0] = numpy.sqrt(zemu) x_r, w_r = imtqlx(x, bj, w) w_r = pow2(w_r) return x_r, w_r
def precalc_Somm(r, k1, k2, use_mex=False): # r: dipole coordinates # k1: wave number in substrate # k2: wave number in upper medium, e.g., air, water etc. pow2 = misc.power_function(2) # global use_mex N = r.shape[0] zr = numpy.zeros([N * N, 2]) ix = 0 for j in numpy.arange(N): # sprintf('precalc zph rho. %d of %d',j,N) for k in numpy.arange(N): r_j = r[j, :] r_k = r[k, :] zph = r_j[2] + r_k[2] rho = numpy.sqrt(pow2(r_j[0] - r_k[0]) + pow2(r_j[1] - r_k[1])) # round to 4 decimal places # zph = round2(zph,.0001); # rho = round2(rho,.0001); zr[ix, :] = numpy.asarray([zph, rho]) # TODO: Get rid of asarray ix += 1 zr0 = zr #zr, m, n = numpy.unique(zr, return_index=True, return_inverse=True) zr, m, n = misc.unique_rows(zr, return_index=True, return_inverse=True) L = zr.shape[0] S = numpy.zeros([L, 4], dtype=numpy.complex128) for j in numpy.arange(L): # sprintf('precalc S. %d of %d',j,L) if use_mex: raise Exception("Some unknown function") # I = somm(numpy.real(k1), numpy.imag(k1),k2,zr[j,1],zr[j,2]) # IV_rho = I[1] + 1j*I[2] # IV_z = I[3] + 1j*I[4] # IH_rho = I[5] + 1j*I[6] # IH_phi = I[7] + 1j*I[8] else: IV_rho, IV_z, IH_rho, IH_phi = evlua(zph, rho, k1, k2) S[j, :] = [IV_rho, IV_z, IH_rho, IH_phi] return S, n
def Fresnel_coeff_n(n_r, theta): # n_r : relative refractive index bottom substrate medium # theta : incident angle (from surface normal) pow2 = misc.power_function(2) R_TM = (numpy.sqrt(1 - pow2(numpy.sin(theta) / n_r)) - n_r * numpy.cos(theta)) / (numpy.sqrt(1 - pow2( (numpy.sin(theta) / n_r))) + n_r * numpy.cos(theta)) R_TE = ( numpy.cos(theta) - n_r * numpy.sqrt(1 - pow2(numpy.sin(theta) / n_r)) ) / (numpy.cos(theta) + n_r * numpy.sqrt(1 - pow2(numpy.sin(theta) / n_r))) return R_TE, R_TM # R_s, R_p
def scatter_spectrum(diameter, diameter_2, n_dipoles, refractive_index, lambda_range): pow1d3 = misc.power_function(1./3.) pow3 = misc.power_function(3) k = 2 * numpy.pi # wave number # r, N, d_old = scatterer.dipole_sphere(10, diameter) r, N, d_old = scatterer.dipole_spheroid(n_dipoles, diameter, diameter_2, testsphere=False) I_scat_p = numpy.zeros(lambda_range.size) I_scat_s = numpy.zeros(lambda_range.size) # Incident plane wave # Incident field wave vector angle gamma_deg = 22.5 gamma = gamma_deg / 180 * numpy.pi kvec = k * numpy.asarray([0, numpy.sin(gamma), -numpy.cos(gamma)]) # wave vector [x y z] n = refractive_index * numpy.ones([N]) # refractive index of sphere for i, lam in enumerate(lambda_range): d_new = pow1d3((4 / 3) * (numpy.pi / N) * (diameter/2 * diameter/2 * diameter_2/2 / pow3(lam))) r = (d_new/d_old) * r d_old = d_new # # p # E0 = numpy.asarray([1, 0, 0]) # E-field [x y z] # s-pol I_scat_p[i] = scatter_intensity(r, n, d_new, E0, kvec, k) # # s # E0 = numpy.asarray([0, numpy.cos(gamma), numpy.sin(gamma)]) # p-pol I_scat_s[i] = scatter_intensity(r, n, d_new, E0, kvec, k) return I_scat_s, I_scat_p
def evanescent_k_e(theta_1, n1, n2): # theta_1 : incident angle # n1 : substrate reflective index # n2 : reflective index of the medium above the substrate, e.g., air # k2 : wave vector above the substrate # ep : TM polarisation vector # es : TE polarisation vector pow2 = misc.power_function(2) k0 = 2 * numpy.pi # wave number in vacuum theta_c = numpy.arcsin(n2 / n1 + 0j) # critical angle sin_theta_2 = (n1 / n2) * numpy.sin(theta_1) theta_2 = numpy.arcsin(sin_theta_2 + 0j) # This is correct regardless of incident angle. Has round-off error. # Use this for the general case # k2 = [0 n2*k0*sin_theta_2 n2*k0*cos(theta_2)]; # This is only correct beyond the critical angle; # the sign for k_z is opposite otherwise. However, no round-off error. if numpy.isreal(theta_2): k2 = numpy.asarray([ 0, n1 * k0 * numpy.sin(theta_1), 1j * k0 * numpy.sqrt(pow2(n1 * numpy.sin(theta_1)) - pow2(n2)) ], dtype=numpy.complex128) else: k2 = numpy.asarray([ 0, n1 * k0 * numpy.sin(theta_1), -1j * k0 * numpy.sqrt(pow2(n1 * numpy.sin(theta_1)) - pow2(n2)) ], dtype=numpy.complex128) ep = numpy.asarray([ 0, 1j * numpy.sqrt(pow2(n1 / n2 * numpy.sin(theta_1)) - 1), n1 / n2 * numpy.sin(theta_1) ], dtype=numpy.complex128) es = numpy.asarray([1, 0, 0], dtype=numpy.complex128) return k2, ep, es
def polarizability_LDR(d, m, kvec, E0=None): """Calculates Lattice Dispersion Relation polarizability of dipoles. Calcualtes Lattice Dispersion Relation polarizability of dipole array according to their refractive indexes `m` and lattice spacing `d`. Parameters ---------- d : float Dipole lattice spacing m : array_like List of dipole refractive indexes kvec : (3, 1) array_like Wave vector [kx ky kz] e.g. [0 0 1] z-direction E0 : (3, 1) array_like E-field polarization [Ex Ey Ez] e.g. [1 0 0] x-polarized, [1 i 0] left-handed circ pol. Returns ------- alph: list List of dipole polarizabilities Notes ----- Currently only supports isotropic polarizabilities, extending to anisotropic polarizabilities should be trivial, References ---------- .. [1] Draine, Bruce T., and Jeremy Goodman. "Beyond Clausius-Mossotti-Wave propagation on a polarizable point lattice and the discrete dipole approximation." The Astrophysical Journal 405 (1993): 685-697. """ pow2 = misc.power_function(2) pow3 = misc.power_function(3) k0 = 2 * numpy.pi N = m.size # number of dipoles b1 = -1.8915316 b2 = 0.1648469 b3 = -1.7700004 msqr = pow2(m) dcube = pow3(d) if E0 is not None: # we have polarization info a_hat = kvec / numpy.linalg.norm(kvec) e_hat = E0 / numpy.linalg.norm(E0) S = 0 for j in range(3): S += (a_hat[j] * e_hat[j])**2 else: # use randomly-oriented value; also for non-plane wave S = .2 alpha_CM = numpy.divide(3 * dcube / (4 * numpy.pi) * (msqr - 1), (msqr + 2)) # Clausius-Mossotti alpha_LDR = numpy.divide(alpha_CM, (1 + numpy.multiply( (alpha_CM / dcube), ((b1 + msqr * b2 + msqr * b3 * S) * (k0 * d)**2 - 2 / 3 * 1j * k0**3 * dcube)))) alph = numpy.zeros([3 * N], dtype=numpy.complex128) # assuming same polarizability in x, y & z directions for j in range(N): alph[3 * (j - 1) + 0] = alpha_LDR[j] alph[3 * (j - 1) + 1] = alpha_LDR[j] alph[3 * (j - 1) + 2] = alpha_LDR[j] return alph
def evlua(zph, rho, k1, k2): # radiating dipole, k # receiving dipole, j # zph = z_j + z_k # rho = radial coordinate for cylindrical system # k1 = wave number in slab medium # k2 = wave number in top medium # int i, jump; # static double del, slope, rmis; # static complex double cp1, cp2, cp3, bk, delta, delta2, sum[6], ans[6]; pow2 = misc.power_function(2) conj_e = 1 bk = 0 # suminc = zeros(6,1); answer = numpy.zeros([6]) tkmag = 100 * numpy.abs(k1) delt = zph if rho > delt: delt = rho if zph >= 2 * rho: # bessel function form of sommerfeld integrals jh = 0 a = 0 delt = 1 / delt if delt > tkmag: b = .1 * (1 - 1j) * tkmag # b=cmplx(.1*tkmag,-.1*tkmag); suminc = rom1(6, 2, zph, rho, k1, k2, a, b, jh) a = b b = delt * (1 - 1j) answer = rom1(6, 2, zph, rho, k1, k2, a, b, jh) # for i = 0; i < 6; i++ ) # sum[i] += ans[i]; # end suminc = suminc + answer else: b = delt * (1 - 1j) suminc = rom1(6, 2, zph, rho, k1, k2, a, b, jh) delta = .2 * numpy.pi * delt answer = gshank(b, delta, answer, 6, suminc, 0, b, b, zph, rho, k1, k2, jh) # gshank(b,delta,ans,6,sum,0,b,b); answer[5] = answer[5] * k1 # ans[5] *= k1; if conj_e: # conjugate since nec uses exp(+jwt) erv = numpy.conj(pow2(k1) * answer[2]) # *erv=conj(ck1sq*ans[2]); ezv = numpy.conj(pow2(k1) * (answer[1] + pow2(k2) * answer[4]) ) # *ezv=conj(ck1sq*(ans[1]+ck2sq*ans[4])); erh = numpy.conj( pow2(k2) * (answer[0] + answer[5])) # *erh=conj(ck2sq*(ans[0]+ans[5])); eph = -numpy.conj( pow2(k2) * (answer[3] + answer[5])) # *eph=-conj(ck2sq*(ans[3]+ans[5])); else: # unconjugated erv = pow2(k1) * answer[2] # *erv=conj(ck1sq*ans[2]); ezv = pow2(k1) * (answer[1] + pow2(k2) * answer[3] ) # *ezv=conj(ck1sq*(ans[1]+ck2sq*ans[4])); erh = pow2(k2) * (answer[0] + answer[5] ) # *erh=conj(ck2sq*(ans[0]+ans[5])); eph = -pow2(k2) * (answer[3] + answer[5] ) # *eph=-conj(ck2sq*(ans[3]+ans[5])); return erv, ezv, erh, eph # # } /* if(zph >= 2.*rho) */ else: # hankel function form of sommerfeld integrals jh = 1 cp1 = .4 * k2 * 1j # cp1=cmplx(0.0,.4*ck2); cp2 = .6 * k2 - .2 * k2 * 1j # cp2=cmplx(.6*ck2,-.2*ck2); cp3 = 1.02 * k2 - .2 * k2 * 1j # cp3=cmplx(1.02*ck2,-.2*ck2); a = cp1 b = cp2 suminc = rom1(6, 2, zph, rho, k1, k2, a, b, jh) a = cp2 b = cp3 answer = rom1(6, 2, zph, rho, k1, k2, a, b, jh) # for( i = 0; i < 6; i++ ) # sum[i]=-(sum[i]+ans[i]); suminc = -(suminc + answer) # path from imaginary axis to -infinity if zph > .001 * rho: slope = rho / zph else: slope = 1000 delt = .2 * numpy.pi / delt delta = (-1 + slope * 1j) * delt / numpy.sqrt(1 + pow2(slope)) delta2 = -numpy.conj(delta) answer = gshank(cp1, delta, answer, 6, suminc, 0, bk, bk, zph, rho, k1, k2, jh) # gshank(cp1,delta,ans,6,sum,0,bk,bk); rmis = rho * (numpy.real(k1) - k2) jump = 0 # jump = FALSE; if (rmis >= 2 * k2) and (rho >= 1E-10): if (zph >= 1E-10): bk = (-zph + rho * 1j) * (k1 - cp3 ) # bk=cmplx(-zph,rho)*(ck1-cp3); rmis = -numpy.real(bk) / numpy.abs( numpy.imag(bk)) # rmis=-creal(bk)/fabs(cimag(bk)); if (rmis > 4 * rho / zph): jump = 1 # jump = TRUE; if not jump: # if( ! jump ) # integrate up between branch cuts, then to + infinity cp1 = k1 - (.1 + .2 * 1j) # cp1=ck1-(.1+.2fj); cp2 = cp1 + .2 bk = delt * 1j # bk=cmplx(0.,del); suminc = gshank(cp1, bk, suminc, 6, answer, 0, bk, bk, zph, rho, k1, k2, jh) # gshank(cp1,bk,sum,6,ans,0,bk,bk); a = cp1 b = cp2 answer = rom1(6, 1, zph, rho, k1, k2, a, b, jh) # for( i = 0; i < 6; i++ ) # ans[i] -= sum[i]; answer = answer - suminc suminc = gshank(cp3, bk, suminc, 6, answer, 0, bk, bk, zph, rho, k1, k2, jh) # gshank(cp3,bk,sum,6,ans,0,bk,bk); answer = gshank(cp2, delta2, answer, 6, suminc, 0, bk, bk, zph, rho, k1, k2, jh) # gshank(cp2,delta2,ans,6,sum,0,bk,bk); jump = 1 # jump = TRUE; # /* if( (rmis >= 2.*ck2) || (rho >= 1.e-10) ) */ else: jump = 0 # jump = FALSE; if not jump: # ( ! jump ) ##{ # integrate below branch points, then to + infinity # for( i = 0; i < 6; i++ ) # sum[i]=-ans[i]; suminc = -answer rmis = numpy.real(k1) * 1.01 # rmis=creal(ck1)*1.01; # if( (ck2+1.) > rmis ) # rmis=ck2+1.; if (k2 + 1) > rmis: rmis = k2 + 1 bk = rmis + .99 * numpy.imag( k1) * 1j # bk=cmplx(rmis,.99*cimag(ck1)); delta = bk - cp3 delta = delta * delt / numpy.abs( delta) # delta *= del/cabs(delta); answer = gshank(cp3, delta, answer, 6, suminc, 1, bk, delta2, zph, rho, k1, k2, jh) # gshank(cp3,delta,ans,6,sum,1,bk,delta2); # /* if( ! jump ) */ answer[5] = answer[5] * k1 # ans[5] *= ck1; if conj_e: # conjugate since nec uses exp(+jwt) erv = numpy.conj(pow2(k1) * answer[2]) # *erv=conj(ck1sq*ans[2]); ezv = numpy.conj(pow2(k1) * (answer[1] + pow2(k2) * answer[4]) ) # *ezv=conj(ck1sq*(ans[1]+ck2sq*ans[4])); erh = numpy.conj( pow2(k2) * (answer[0] + answer[5])) # *erh=conj(ck2sq*(ans[0]+ans[5])); eph = -numpy.conj( pow2(k2) * (answer[3] + answer[5])) # *eph=-conj(ck2sq*(ans[3]+ans[5])); else: # unconjugated erv = pow2(k1) * answer[2] ezv = pow2(k1) * (answer[1] + pow2(k2) * answer[4]) erh = pow2(k2) * (answer[0] + answer[5]) eph = -pow2(k2) * (answer[3] + answer[5]) return erv, ezv, erh, eph
def saoa(t, zph, rho, k1, k2, a, b, jh): # % double xlr, sign; # % static complex double xl, dxl, cgam1, cgam2, b0, b0p, com, dgam, den1, den2; pow2 = misc.power_function(2) pow4 = misc.power_function(4) pow6 = misc.power_function(6) tsmag = 100 * k1 * numpy.conj(k1) cksm = pow2(k2) / (pow2(k1) + pow2(k2)) # cksm=ck2sq/(ck1sq+ck2sq); ct1 = .5 * (pow2(k1) - pow2(k2)) # ct1=.5*(ck1sq-ck2sq) # % erv=ck1sq*ck1sq; # % ezv=ck2sq*ck2sq; # % ct2=.125*(erv-ezv); ct2 = .125 * (pow4(k1) - pow4(k2)) # % erv *= ck1sq; # % ezv *= ck2sq; # % ct3=.0625*(erv-ezv); ct3 = .0625 * (pow6(k1) - pow6(k2)) xl, dxl = lambd(t, a, b) # lambda(t, &xl, &dxl); if jh == 0: # bessel function form b0, b0p = ott_funcs.bessel0(xl * rho) # bessel(xl*rho, &b0, &b0p); b0 *= 2. # b0 *=2. b0p *= 2. # b0p *=2. cgam1 = numpy.sqrt(pow2(xl) - pow2(k1)) # cgam1=csqrt(xl*xl-ck1sq) cgam2 = numpy.sqrt(pow2(xl) - pow2(k2)) # cgam2=csqrt(xl*xl-ck2sq) if numpy.real(cgam1) == 0: # if(creal(cgam1) == 0.): cgam1 = numpy.abs( numpy.imag(cgam1)) * 1j # cgam1=cmplx(0.,-fabs(cimag(cgam1))) if numpy.real(cgam2) == 0: # if(creal(cgam2) == 0.): cgam2 = numpy.abs( numpy.imag(cgam2)) * 1j # cgam2=cmplx(0.,-fabs(cimag(cgam2))) else: # hankel function form b0, b0p = ott_funcs.hankel0(xl * rho) # hankel(xl*rho, &b0, &b0p); com = xl - k1 # com=xl-ck1; cgam1 = numpy.sqrt(xl + k1) * numpy.sqrt( com) # cgam1=csqrt(xl+ck1)*csqrt(com); if (numpy.real(com) < 0) and (numpy.imag(com) >= 0): # if(creal(com) < 0. && cimag(com) >= 0.) cgam1 = -cgam1 com = xl - k2 # com=xl-ck2; cgam2 = numpy.sqrt(xl + k2) * numpy.sqrt( com) # cgam2=csqrt(xl+ck2)*csqrt(com); if (numpy.real(com) < 0) and (numpy.imag(com) >= 0): # if(creal(com) < 0. && cimag(com) >= 0.) cgam2 = -cgam2 xlr = xl * numpy.conj(xl) if xlr >= tsmag: if numpy.imag(xl) >= 0: xlr = numpy.real(xl) if xlr >= k2: if (xlr <= numpy.realk1): # if(xlr <= ck1r): dgam = cgam2 - cgam1 else: sign = 1 dgam = 1 / (pow2(xl)) # dgam=1./(xl*xl) dgam = sign * ((ct3 * dgam + ct2) * dgam + ct1) / xl else: sign = -1 dgam = 1 / pow2(xl) # dgam=1./(xl*xl) dgam = sign * ((ct3 * dgam + ct2) * dgam + ct1) / xl # /* if(xlr >= ck2) */ # /* if(cimag(xl) >= 0.) */ else: sign = 1 dgam = 1 / pow2(xl) # dgam=1./(xl*xl) dgam = sign * ((ct3 * dgam + ct2) * dgam + ct1) / xl # % /* if(xlr < tsmag) */ else: dgam = cgam2 - cgam1 den2 = cksm * dgam / (cgam2 * (pow2(k1) * cgam2 + pow2(k2) * cgam1) ) # den2=cksm*dgam/(cgam2*(ck1sq*cgam2+ck2sq*cgam1)) den1 = 1 / (cgam1 + cgam2) - cksm / cgam2 com = dxl * xl * numpy.exp(-cgam2 * zph) answer = numpy.zeros([6], dtype=numpy.complex128) answer[5] = com * b0 * den1 / k1 # ans[5] = com*b0*den1/ck1 com = com * den2 # com *= den2 if rho != 0: # if(rho != 0.) b0p /= rho answer[0] = -com * xl * (b0p + b0 * xl) # ans[0]=-com*xl*(b0p+b0*xl) answer[3] = com * xl * b0p # ans[3]=com*xl*b0p else: answer[0] = -com * xl * xl * .5 # ans[0]=-com*xl*xl*.5 answer[3] = answer[0] # ans[3]=ans[0] answer[1] = com * cgam2 * cgam2 * b0 # ans[1]=com*cgam2*cgam2*b0 answer[2] = -answer[3] * cgam2 * rho # ans[2]=-ans[3]*cgam2*rho answer[4] = com * b0 # ans[4]=com*b0 return answer
def interaction_AR(k1, k2, r, alph): # % AR is 3N x 3N matrix # % k1 = wave number in bottom medium (substrate) # % k2 = wave number in top medium (could be air/vacuum) # % r: N x 3 matrix, for x_j, y_j, z_j coordinates # % N: number of dipoles # % j = 1..N # % AR means A + R # % A is as per Eqn(6) plus the inverse polarizability dagonal in # % Draine & Flatau, # % Discrete-dipole approximation for scattering calculations # % pgs 1491-1499, Vol. 11, No. 4 (1994), J. Opt. Soc. Am. A # # % the Rjk component represents radiating and receiving dipole interactions # % via substrate surface reflection; refer to: # % Roland Schmehl, Brent M. Nebeker, and E. Dan Hirleman # % "Discrete-dipole approximation for scattering by features on surfaces # % by means of a two-dimensional fast Fourier transform technique" # % J. Opt. Soc. Am. A 14, 3026-3036 (1997) pow2 = misc.power_function(2) pow_m1 = misc.power_function(-1) pow_m2 = misc.power_function(-2) k0 = 2 * numpy.pi N = r[:, 1].size AR = numpy.zeros([3 * N, 3 * N], dtype=numpy.complex128) I = numpy.eye(3) S, nS = precalc_Somm(r, k1, k2) iS = 0 # dipole combination counter # % nS(iS) determines which set of precalculated Sommmerfeld integrals to use # tic for jj in numpy.arange(N): # sprintf('Interaction matrix, dipole %d of %d',jj,N) for kk in numpy.arange(N): Rjk = reflection_Rjk(k1, k2, r[jj, :], r[kk, :], S[nS[iS], :]) # Schmehl et al. iS += 1 if jj != kk: # off-diagonal rk_to_rj = r[jj, :] - r[kk, :] rjk = numpy.linalg.norm( rk_to_rj) # sqrt(sum((r(jj,:)-r(kk,:)).^2)) rjk_hat = (rk_to_rj) / rjk rjkrjk = numpy.outer(rjk_hat, rjk_hat) Ajk = numpy.exp(1j * k0 * rjk) / rjk * ( pow2(k0) * (rjkrjk - I) + (1j * k0 * rjk - 1) / pow2(rjk) * (3 * rjkrjk - I)) # %Draine & Flatau # % beta, gamma see Schmehl's thesis (1.27) rjk_x = rk_to_rj[0] / rjk rjk_y = rk_to_rj[1] / rjk rjk_z = rk_to_rj[2] / rjk beta = (1 - pow_m2(k0 * rjk) + 1j * pow_m1(k0 * rjk)) gamma = -(1 - 3 * pow_m2(k0 * rjk) + 1j * 3 * pow_m1(k0 * rjk)) Ajk_BG = -numpy.exp(1j * k0 * rjk) / rjk * pow2( k0) * numpy.asarray([[(beta + gamma * pow2(rjk_x)), (gamma * rjk_x * rjk_y), (gamma * rjk_x * rjk_z)], [(gamma * rjk_y * rjk_x), (beta + gamma * pow2(rjk_y)), (gamma * rjk_y * rjk_z)], [(gamma * rjk_z * rjk_x), (gamma * rjk_z * rjk_y), (beta + gamma * pow2(rjk_z))]]) AR[jj * 3 + 0:(jj + 1) * 3, kk * 3 + 0:(kk + 1) * 3] = (Ajk + Rjk) else: AR[jj * 3 + 0, kk * 3 + 0] = 1. / alph[jj * 3 + 0] AR[jj * 3 + 1, kk * 3 + 1] = 1. / alph[jj * 3 + 1] AR[jj * 3 + 2, kk * 3 + 2] = 1. / alph[jj * 3 + 2] AR[jj * 3 + 0:(jj + 1) * 3, kk * 3 + 0:(kk + 1) * 3] += Rjk # + AR[(jj) * 3 + 0:(jj + 1) * 3, kk * 3 + 0:(kk + 1) * 3] return AR
def E_sca_SI(k, r, P, det_r, theta, phi, n1): # % k: wave vector # % r: dipole coordinates (N x 3 matrix) # % P: polarizations (vector of length 3N; Px1,Py1,Pz1 ... PxN,PyN,PzN) # % det_r, theta, phi: evaluation points in spherical coordinates # % n1: refractive index of substrate # # % Note: coordinates are relative to origin # pow2 = misc.power_function(2) N, cols = r.shape # TODO: what does this do? # rows, cols = theta.shape # if cols > rows: # theta = numpy.reshape(theta, [cols, rows]) # rows, cols = phi.shape # if cols > rows: # phi = numpy.reshape(phi, [cols, rows]) # rows, cols = det_r.shape # if cols > rows: # det_r = numpy.reshape(det_r, [cols, rows]) # %pts = length(r_unit); r_sp = numpy.asarray([det_r, theta, phi], dtype=numpy.complex128).T # TODO: Get rid of asarray pts, cols = r_sp.shape r_unit = numpy.ones([pts], dtype=numpy.complex128) # er_sp = numpy.asarray([r_unit, theta, phi]).T # e1_sp = numpy.asarray([r_unit, theta + numpy.sign(theta) * numpy.pi / 2, phi]).T # TODO: Get rid of asarray r_E = numpy.asarray(misc.rtp2xyz(r_unit, theta, phi), dtype=numpy.complex128).T # er_sp r_E1 = numpy.asarray(misc.rtp2xyz(r_unit, theta + numpy.sign(theta) * numpy.pi / 2, phi), dtype=numpy.complex128).T # e1_sp er = numpy.zeros([pts, 3], dtype=numpy.complex128) e1 = numpy.zeros([pts, 3], dtype=numpy.complex128) e2 = numpy.zeros([pts, 3], dtype=numpy.complex128) # % r_E2 = rtp2xyz(er_sp); # % er2 = zeros(pts,3); for j in numpy.arange(pts): er[j, :] = r_E[j, :] / numpy.linalg.norm(r_E[j, :]) e1[j, :] = r_E1[j, :] / numpy.linalg.norm(r_E1[j, :]) e2[j, :] = numpy.cross(er[j, :], e1[j, :]) E = numpy.zeros([pts, 3], dtype=numpy.complex128) for pt in numpy.arange(pts): erp = er[pt, :] # e_r e1p = e1[pt, :] # e_theta e2p = e2[pt, :] # e_phi k_sca = (k * erp).conj() k_Isca = numpy.asarray([k_sca[0], k_sca[1], -k_sca[2]], dtype=numpy.complex128).conj() # % This is the modification was made Mitchell Short, University of Utah, # % to account for the Fresnel coefficient at each angle of dipole # % as opposed to single incident angle. ref_angle = numpy.abs((-numpy.pi / 2) + pt * numpy.pi / theta.size) refl_TE, refl_TM = Fresnel_coeff_n(n1, numpy.abs(ref_angle)) # %rp = norm(r_E(pt,:)); rp = det_r[pt] for j in numpy.arange(N): Pj = P[3 * j + 0:3 * j + 3].conj() rj = r[j, :] rIj = [rj[0], rj[1], -rj[2]] E[pt, :] = E[pt, :] + numpy.exp(-1j * numpy.dot(k_sca, rj)) * ( numpy.dot(Pj, e1p) * e1p + numpy.dot(Pj, e2p) * e2p ) + numpy.exp(-1j * numpy.dot(k_Isca, rj)) * (refl_TM * numpy.dot( Pj, e1p) * e1p + refl_TE * numpy.dot(Pj, e2p) * e2p) # TODO: Inner Outer product? # E(pt,:) = E(pt,:) + ... # exp(-i*k_sca.*rj).*(dot(Pj,e1p)*e1p + dot(Pj,e2p)*e2p) + ... # exp(-i*k_sca.*rIj).*(refl_TM*dot(Pj,e1p)*e1p + refl_TE*dot(Pj,e2p)*e2p); # % dot(k_sca,rIj) and dot(k_Isca,rj) are equal. # % Refer to Schmel's thesis (2.58) E[pt, :] = E[pt, :] * pow2(k) * numpy.exp( 1j * k * rp) / (4 * numpy.pi * rp) return E
def reflection_Rjk(k1, k2, r_j, r_k, S): # % k1 = wave number in bottom medium (e.g. substrate) # % k2 = wave number in top medium (e.g. air/vacuum) # % r_j = receiving dipole coordinate [x y z] # % r_k = radiating dipole coordinate [x y z] # % S = precalculated Sommerfeld essential integrals pow2 = misc.power_function(2) pow_m1 = misc.power_function(-1) pow_m2 = misc.power_function(-2) k0 = 2 * numpy.pi # % (A9d) rI_k2j = [r_j[0] - r_k[0], r_j[1] - r_k[1], r_j[2] + r_k[2]] rIjk = numpy.linalg.norm(rI_k2j) # % x,y,z components vectors (A9a) rhat_x = rI_k2j[0] / rIjk rhat_y = rI_k2j[1] / rIjk rhat_z = rI_k2j[2] / rIjk # % scalars (A9b) & (A9c) beta = (1 - 1 * pow_m2(k0 * rIjk) + 1j * pow_m1(k0 * rIjk)) gamma = -(1 - 3 * pow_m2(k0 * rIjk) + 1j * 3 * pow_m1(k0 * rIjk)) zph = r_j[2] + r_k[2] rho = numpy.sqrt(pow2(r_j[0] - r_k[0]) + pow2(r_j[1] - r_k[1])) # % assign precalculated Sommerfeld essential integrals IV_rho = S[0] IV_z = S[1] IH_rho = S[2] IH_phi = S[3] # S11 = pow2(rhat_x) * IH_rho - pow2(rhat_y) * IH_phi S12 = rhat_x * rhat_y * (IH_rho + IH_phi) S13 = rhat_x * IV_rho S21 = rhat_x * rhat_y * (IH_rho + IH_phi) S22 = pow2(rhat_y) * IH_rho - pow2(rhat_x) * IH_phi S23 = rhat_y * IV_rho S31 = -rhat_x * IV_rho S32 = -rhat_y * IV_rho S33 = IV_z Sjk = numpy.asarray([[S11, S12, S13], [S21, S22, S23], [S31, S32, S33]]) # TODO: Get rid of asarray G11 = -(beta + gamma * pow2(rhat_x)) G12 = -gamma * rhat_x * rhat_y G13 = gamma * rhat_x * rhat_z G21 = -gamma * rhat_y * rhat_x G22 = -(beta + gamma * pow2(rhat_y)) G23 = gamma * rhat_y * rhat_z G31 = -gamma * rhat_z * rhat_x G32 = -gamma * rhat_z * rhat_y G33 = beta + gamma * pow2(rhat_z) Gjk = numpy.asarray([[G11, G12, G13], [G21, G22, G23], [G31, G32, G33]]) # TODO: Get rid of asarray # % to be consistent with the Draine and Flatau interraction matrix # % formulation we omit the (4*pi*ep)^-1 factor # % (A8) Rjk = -(Sjk + pow2(k0) * (pow2(k1) - pow2(k2)) / (pow2(k1) + pow2(k2)) * numpy.exp(1j * k0 * rIjk) / rIjk * Gjk ) # %as per Schmehl's thesis # % The required k0^2 factor was reported by Dr. Andrey Evlyukhin, Laser Zentrum Hannover e.V. # % as per Schmehl's thesis (2.41). In the previous version, # % Rjk = -(Sjk + (k1^2-k2^2)/(k1^2+k2^2)*exp(i*k0*rIjk)/rIjk*Gjk); % as per Schmehl (A8) return Rjk
def imtqlx(diagonal, subdiagonal, vec, abstol=1e-30, maxiterations=30): """ Diagonalize symmetric tridiagonal matrix :param diagonal: matrix diagonal, size N :param subdiagonal: matrix subdiagonal, size N-1 :return: lam: diagonal entries of diagonalized matrix :return: qtz: values of Q' * Z, where Q diagonalizes input matrix M """ n = diagonal.size #assert subdiagonal.size == n-1 assert vec.size == n pow2 = misc.power_function(2) lam = numpy.zeros(n, dtype=numpy.complex128) lam = diagonal qtz = numpy.zeros(n, dtype=numpy.complex128) qtz = vec if n == 1: return lam, qtz subdiagonal[n - 1] = 0 for l in numpy.arange(1, n + 1): j = 0 while True: for m in numpy.arange(l, n + 1): if m == n: break if numpy.abs(subdiagonal[m - 1]) <= abstol * ( numpy.abs(lam[m - 1] + numpy.abs(lam[m]))): break p = lam[l - 1] if m == l: break if j >= maxiterations: raise Exception("Failed to converge in {} iterations".format( maxiterations)) j += 1 g = (lam[l] - p) / (2.0 * subdiagonal[l - 1]) r = numpy.sqrt(pow2(g) + 1.0) if g < 0: t = g - r else: t = g + r g = lam[m - 1] - p + subdiagonal[l - 1] / (g + t) s = 1.0 c = 1.0 p = 0.0 mml = m - l for ii in numpy.arange(1, mml + 1): i = m - ii f = s * subdiagonal[i - 1] b = c * subdiagonal[i - 1] if numpy.abs(g) <= numpy.abs(f): c = g / f r = numpy.sqrt(pow2(c) + 1.0) subdiagonal[i] = f * r s = 1.0 / r c *= s else: s = f / g r = numpy.sqrt(pow2(s) + 1.0) subdiagonal[i] = g * r c = 1.0 / r s *= c g = lam[i] - p r = (lam[i - 1] - g) * s + 2.0 * c * b p = s * r lam[i] = g + p g = c * r - b f = qtz[i] qtz[i] = s * qtz[i - 1] + c * f qtz[i - 1] = c * qtz[i - 1] - s * f lam[l - 1] -= p subdiagonal[l - 1] = g subdiagonal[m - 1] = 0.0 #Sort for ii in numpy.arange(2, n + 1): i = ii - 1 k = i p = lam[i - 1] for j in numpy.arange(ii, n + 1): if lam[j - 1] < p: k = j p = lam[j - 1] if k != i: lam[k - 1] = lam[i - 1] lam[i - 1] = p p = qtz[i - 1] qtz[i - 1] = qtz[k - 1] qtz[k - 1] = p return lam, qtz