def mode_jonesmat2x2(shape, k, jmat, epsv=(1., 1., 1.), epsa=(0., 0., 0.), mode=+1, betamax=BETAMAX): """Returns a mode polarizer for fft of the field data in the laboratory frame. This is the most general set of jones matrices for E-field data. It is meant to be used in FFT space. Parameters ---------- shape : (int,int) Shape of the 2D crossection of the field data. k : float or array of floats Wavenumber at which to compute the mode matrices. jmat : (2,2) array A 2x2 jones matrix that needs to be converted to 4x4 mode matrices. epsv : array Medium epsilon eigenvalues epsa : array Medium epsilon euler angles mode : int PRopagatin mode, either +1 or -1 betamax : float The betamax parameter Returns ------- pmat : (:,:,2,2) array Output matrix. Shape of the matirx is shape + (2,2) or len(ks) + shape + (2,2) if k is an array. See Also -------- ray_jonesmat2x2 : for applying the jones matrix in the real space. """ ks = np.asarray(k, FDTYPE) ks = abs(ks) epsv = np.asarray(epsv, CDTYPE) epsa = np.asarray(epsa, FDTYPE) beta, phi = betaphi(shape, ks) alpha, f = diffraction_alphaf(shape, ks, epsv=epsv, epsa=epsa, betamax=betamax) beta, phi = betaphi(shape, ks) #matrix viewed in the eigenframe jmat = rotated_matrix(jmat, phi) pmat = jonesmat4x4(jmat, f) return as2x2(pmat, f, mode)
def test_betaphi(self): b, p = wave.betaphi(self.shape, self.ks) self.allclose(self.beta, b) self.allclose(self.phi, p) out = np.empty_like(b), np.empty_like(p) wave.betaphi(self.shape, self.ks, out=out) self.allclose(self.beta, out[0]) self.allclose(self.phi, out[1]) b, p = wave.betaphi(self.shape, self.ks[0]) self.allclose(self.beta[0], b) self.allclose(self.phi, p) self.isfloat(b) self.isfloat(p)
def diffraction_alphaffi(shape, ks, epsv=(1., 1., 1.), epsa=(0., 0., 0.), betamax=BETAMAX, out=None): ks = np.asarray(ks) ks = abs(ks) beta, phi = betaphi(shape, ks) alpha, f, fi = alphaffi(beta, phi, epsv, epsa, out=out) out = (alpha, f, fi) # try: # b1,betamax = betamax # a = (betamax-b1)/(betamax) # m = tukey(beta,a,betamax) # np.multiply(f,m[...,None,None],f) # except: # pass mask0 = (beta >= betamax) #betamax) fi[mask0] = 0. f[mask0] = 0. alpha[mask0] = 0. #return mask, alpha,f,fi return out
def propagate_4x4_full(field, wavenumbers, layer, nsteps=1, betamax=BETAMAX, out=None): shape = field.shape[-2:] d, epsv, epsa = layer kd = wavenumbers * d / nsteps if out is None: out = np.empty_like(field) out_af = None pm = None ii, jj = np.meshgrid(range(shape[0]), range(shape[1]), copy=False, indexing="ij") for step in range(nsteps): for i in range(len(wavenumbers)): ffield = fft2(field[..., i, :, :, :]) ofield = np.zeros_like(out[..., i, :, :, :]) b, p = betaphi(shape, wavenumbers[i]) mask = b < betamax amplitude = ffield[..., mask] betas = b[mask] phis = p[mask] iind = ii[mask] jind = jj[mask] for bp in sorted(zip(range(len(betas)), betas, phis, iind, jind), key=lambda el: el[1], reverse=False): #for j,bp in enumerate(zip(betas,phis,iind,jind)): j, beta, phi, ieig, jeig = bp out_af = alphaffi(beta, phi, epsv, epsa, out=out_af) alpha, f, fi = out_af pm = phasem(alpha, kd[i], out=pm) w = eigenwave(amplitude.shape[:-1] + shape, ieig, jeig, amplitude=amplitude[..., j]) w = dotmdmf(f, pm, fi, w, out=w) np.add(ofield, w, ofield) out[..., i, :, :, :] = ofield field = out return out
def filter_eps(eps, k, betamax=1): eps = np.moveaxis(eps, -1, -3) feps = fft2(eps) beta, phi = betaphi(feps.shape[-2:], k) mask = beta > betamax feps[..., mask] = 0. eps = ifft2(feps) eps = np.moveaxis(eps, -3, -1) return eps
def test_planewave_k(self): shape = (13, 11) for k in (0.1, 1., 10): b, p = wave.betaphi(shape, k) for i in range(shape[0]): for j in range(shape[1]): w1 = wave.planewave(shape, k, b[i, j], p[i, j]) w2 = wave.eigenwave(shape, i, j) self.allclose(w1, w2)
def denoise_fftfield(ffield, wavenumbers, beta, smooth = 1, filter_func = exp_notch_filter, out = None): """Denoises fourier transformed field by attenuating modes around the selected beta parameter. """ shape = ffield.shape[-2:] b, p = betaphi(shape,wavenumbers) f = filter_func(b, beta, smooth) f = f[...,None,:,:] ffield = np.multiply(ffield, f, out = out) return ffield
def test_planewave_shapes(self): shapes = ((16, 16), (15, 15), (12, 13), (7, 6)) k = 1 for shape in shapes: b, p = wave.betaphi(shape, k) for i in range(shape[0]): for j in range(shape[1]): w1 = wave.planewave(shape, k, b[i, j], p[i, j]) w2 = wave.eigenwave(shape, i, j) self.allclose(w1, w2)
def mode_polarizer(shape, ks, jones=(1, 0), epsv=(1., 1., 1.), epsa=(0., 0., 0.), betamax=BETAMAX): """Returns a mode polarizer that should be applied in fft space. This is the most general polarizer that does not introduce any reflections for any kind of nonhomogeneous or homogeneous field.""" ks = np.asarray(ks, FDTYPE) ks = abs(ks) epsv = np.asarray(epsv, CDTYPE) epsa = np.asarray(epsa, FDTYPE) beta, phi = betaphi(shape, ks) alpha, f = diffraction_alphaf(shape, ks, epsv=epsv, epsa=epsa, betamax=betamax) beta, phi = betaphi(shape, ks) jones = jonesvec(jones, phi) pmat = polarizer4x4(jones, f) return pmat
def illumination_eigenrays(shape, k0, NA=0.2, scale=(1, 1)): scale = np.asarray(scale, dtype=int) if scale.ndim == 0: scale = (scale, scale) elif scale.ndim != 1 or len(scale) != 2: raise ValueError("Unknown scale parameter!") b, p = betaphi(shape, k0) bs = b[..., ::scale[0], ::scale[1]] ps = p[..., ::scale[0], ::scale[1]] mask = bs <= NA if bs.ndim == 3: bs = tuple((b[m] for b, m in zip(bs, mask))) ps = tuple((ps[m] for m in mask)) intensity = tuple((1. / m.sum() for m in mask)) return bs, ps, intensity else: return bs[mask], ps[mask], 1. / mask.sum()
def E_diffraction_alphaE(shape, ks, epsv=(1, 1, 1), epsa=(0., 0., 0.), mode=+1, betamax=BETAMAX, out=None): ks = np.asarray(ks) ks = abs(ks) beta, phi = betaphi(shape, ks) mask0 = (beta >= betamax) #betamax) alpha, j = alphaE(beta, phi, epsv, epsa, mode=mode, out=out) j[mask0] = 0. alpha[mask0] = 0. out = (alpha, j) return out
def diffraction_alphaf(shape, ks, epsv=(1., 1., 1.), epsa=(0., 0., 0.), betamax=BETAMAX, out=None): ks = np.asarray(ks) ks = abs(ks) beta, phi = betaphi(shape, ks) epsv = np.asarray(epsv, CDTYPE) epsa = np.asarray(epsa, FDTYPE) alpha, f = alphaf(beta, phi, epsv, epsa, out=out) out = (alpha, f) mask0 = (beta >= betamax) f[mask0] = 0. alpha[mask0] = 0. return out
def propagate_2x2_full(field, wavenumbers, layer, input_layer=None, nsteps=1, mode=+1, reflection=True, betamax=BETAMAX, refl=None, bulk=None, out=None): shape = field.shape[-2:] d, epsv, epsa = layer if input_layer is not None: d_in, epsv_in, epsa_in = input_layer kd = wavenumbers * d / nsteps if out is None: out = np.empty_like(field) ii, jj = np.meshgrid(range(shape[0]), range(shape[1]), copy=False, indexing="ij") for step in range(nsteps): for i in range(len(wavenumbers)): ffield = fft2(field[..., i, :, :, :]) ofield = np.zeros_like(out[..., i, :, :, :]) b, p = betaphi(shape, wavenumbers[i]) mask = b < betamax amplitude = ffield[..., mask] betas = b[mask] phis = p[mask] iind = ii[mask] jind = jj[mask] if bulk is not None: obulk = bulk[..., i, :, :, :] if refl is not None: tampl = fft2(refl[..., i, :, :, :])[..., mask] orefl = refl[..., i, :, :, :] orefl[...] = 0. for bp in sorted(zip(range(len(betas)), betas, phis, iind, jind), key=lambda el: el[1], reverse=False): #for j,bp in enumerate(zip(betas,phis,iind,jind)): j, beta, phi, ieig, jeig = bp out_af = alphaf(beta, phi, epsv, epsa) alpha, fmat_out = out_af e = E_mat(fmat_out, mode=mode) ei0 = inv(e) ei = ei0 pm = phase_mat(alpha, kd[i, None, None], mode=mode) w = eigenwave(amplitude.shape[:-1] + shape, ieig, jeig, amplitude=amplitude[..., j]) if step == 0 and reflection != False: alphain, fmat_in = alphaf(beta, phi, epsv_in, epsa_in) if refl is not None: ei, eri = Etri_mat(fmat_in, fmat_out, mode=mode) ein = E_mat(fmat_in, mode=-1 * mode) t = eigenwave(amplitude.shape[:-1] + shape, ieig, jeig, amplitude=tampl[..., j]) r = dotmf(eri, w) r = dotmf(ein, r, out=r) np.add(orefl, r, orefl) w = dotmf(ei, w, out=w) t = dotmf(ei0, t, out=t) w = np.add(t, w, out=w) else: ei = Eti_mat(fmat_in, fmat_out, mode=mode) w = dotmf(ei, w, out=w) w = dotmf(dotmd(e, pm), w, out=w) np.add(ofield, w, ofield) else: w = dotmdmf(e, pm, ei, w, out=w) np.add(ofield, w, ofield) if bulk is not None: e2h = E2H_mat(fmat_out, mode=mode) obulk[..., 1::2, :, :] += dotmf(e2h, w) obulk[..., ::2, :, :] += w out[..., i, :, :, :] = ofield field = out return out, refl
def setUp(self): self.shape = (64, 64) self.ks = [1, 2] self.beta, self.phi = wave.betaphi(self.shape, self.ks)