def fi_iso2d(shape, k0, n=1., betay=0, betamax=BETAMAX): fmat = f_iso2d(shape, k0, n, betay, betamax) if isinstance(fmat, tuple): out = (inv(f) for f in fmat) return tuple(out) else: return inv(fmat)
def _reflect2d(fvec_in, fmat_in, rmat, fmat_out, fvec_out=None): """Transmits/reflects field vector using 4x4 method. This functions takes a field vector that describes the input field and computes the output transmited field and also updates the input field with the reflected waves. """ fmat_ini = inv(fmat_in) avec = dotmv(fmat_ini, fvec_in) a = np.zeros(avec.shape, avec.dtype) a[..., 0::2] = avec[..., 0::2] if fvec_out is not None: fmat_outi = inv(fmat_out) bvec = dotmv(fmat_outi, fvec_out) a[..., 1::2] = bvec[..., 1::2] else: bvec = np.zeros_like(avec) av = a.reshape(a.shape[:-2] + (a.shape[-2] * a.shape[-1], )) out = dotmv(rmat, av).reshape(a.shape) avec[..., 1::2] = out[..., 1::2] bvec[..., ::2] = out[..., ::2] dotmv(fmat_in, avec, out=fvec_in) return dotmv(fmat_out, bvec, out=out)
def alphaEEi(beta, phi, epsv, epsa, mode=+1, out=None): if out is None: alpha, E = alphaE(beta, phi, epsv, epsa, mode=mode) return alpha, E, inv(E) else: alpha, E, Ei = out alpha, E = alphaE(beta, phi, epsv, epsa, mode=mode, out=(alpha, E)) Ei = inv(E, out=Ei) return alpha, E, Ei
def Eti_mat(fin, fout, fini=None, overwrite_fin=False, mode=+1, out=None): A = E_mat(fin, mode=mode, copy=False) Ai = inv(A, out=out) St, Sr = S_mat(fin, fout, fini=fini, overwrite_fin=overwrite_fin, mode=mode) Sti = inv(St, out=St) return dotmm(Sti, Ai, out=Ai)
def Etri_mat(fin, fout, fini=None, overwrite_fin=False, mode=+1, out=None): out1, out2 = out if out is not None else (None, None) A = E_mat(fin, mode=mode, copy=False) Ai = inv(A, out=out1) St, Sr = S_mat(fin, fout, fini=fini, overwrite_fin=overwrite_fin, mode=mode) Sti = inv(St, out=St) ei = dotmm(Sti, Ai, out=Ai) return ei, dotmm(Sr, ei, out=out2)
def transmission_mat(fin, fout, fini=None, mode=+1, out=None): A, B = S_mat(fin, fout, fini=fini, mode=mode) if mode == +1: A1 = fin[..., ::2, ::2] A2 = fout[..., ::2, ::2] elif mode == -1: A1 = fin[..., 1::2, 1::2] A2 = fout[..., 1::2, 1::2] else: raise ValueError("Unknown propagation mode.") Ai = inv(A, out=out) A1i = inv(A1) return dotmm(dotmm(A2, Ai, out=Ai), A1i, out=Ai)
def transmit(fvec_in, cmat, fmatin=None, fmatout=None, fmatini=None, fmatouti=None, fvec_out=None): """Transmits field vector using 4x4 method. This functions takes a field vector that describes the input field and computes the output transmited field and also updates the input field with the reflected waves. """ b = np.broadcast(fvec_in[..., None], cmat, fmatin, fmatout) if fmatini is None: if fmatin is None: fmatin = f_iso(1, 0, 0) fmatini = inv(fmatin) if fmatin is None: fmatin = inv(fmatini) if fmatouti is None: if fmatout is None: fmatout = fmatin fmatouti = fmatini else: fmatouti = inv(fmatout) if fmatout is None: fmatout = inv(fmatouti) smat = system_mat(cmat, fmatini=fmatini, fmatout=fmatout) avec = dotmv(fmatini, fvec_in) a = np.zeros(b.shape[:-1], avec.dtype) a[..., 0::2] = avec[..., 0::2] avec = a.copy() #so that it broadcasts if fvec_out is not None: bvec = dotmv(fmatouti, fvec_out) a[..., 1::2] = bvec[..., 1::2] else: bvec = np.zeros_like(avec) r = reflection_mat(smat) out = dotmv(r, a, out=fvec_out) avec[..., 1::2] = out[..., 1::2] bvec[..., ::2] = out[..., ::2] dotmv(fmatin, avec, out=fvec_in) return dotmv(fmatout, bvec, out=out)
def _transfer_ray_4x4_1_windows(windows, field, wavenumbers, layer, dmat1, dmat2, betas, phis, nsteps = 1, out = None, betamax = BETAMAX): d, epsv, epsa = layer kd = wavenumbers*d if out is None: out = np.zeros_like(field) for j in range(nsteps): field = dotmf(dmat1,field) for window, beta, phi in zip(windows, betas, phis): alpha, f = alphaf(beta,phi,epsv,epsa) p = phasem(alpha,kd[...,None,None]) e = E_mat(f, mode = None) ei = inv(e) f = field * window f = ifft2(f, out = f) f = dotmdmf(e,p,ei,f, out = f) f = fft2(field, out = f) out += f out = dotmf(dmat2,out, out = out) return out
def jonesmat4x4(jmat, fmat, out=None): """Returns a 4x4 jones matrix for applying in eigenframe. Numpy broadcasting rules apply. Parameters ---------- jmat : (...,2,2) array A 2x2 jones matrix in the eigenframe. Any of matrices in :mod:`dtmm.jones` can be used. fmat : (...,4,4) array A field matrix array of the isotropic medium. out : ndarray, optional Output array Returns ------- jmat : (...,4,4) array A 4x4 matrix for field vector manipulation in the eigenframe. See Also -------- ray_jonesmat4x4 : for applying the jones matrix in the laboratory frame. """ fmat = normalize_f(fmat) fmati = inv(fmat) pmat = as4x4(jmat) m = dotmm(fmat, dotmm(pmat, fmati, out=out), out=out) return m
def _transfer_ray_4x4_1(field, wavenumbers, layer, dmat1, dmat2, beta=0, phi=0, nsteps=1, betamax=BETAMAX, out=None): d, epsv, epsa = layer kd = wavenumbers * d alpha, f = alphaf(beta, phi, epsv, epsa) p = phasem(alpha, kd[..., None, None]) e = E_mat(f, mode=None) ei = inv(e) for j in range(nsteps): field = dotmf(dmat1, field, out=out) field = ifft2(field, out=field) field = dotmdmf(e, p, ei, field, out=field) field = fft2(field, out=field) field = dotmf(dmat2, field, out=out) return field
def polarizer4x4(jones, fmat, out=None): """Returns a polarizer matrix from a given jones vector and field matrix. Numpy broadcasting rules apply. Parameters ---------- jones : array_like A length two array describing the jones vector. Jones vector should be normalized. fmat : array_like A field matrix array of the medium. out : ndarray, optional Output array Examples -------- >>> f = f_iso(n = 1.) >>> jvec = dtmm.jones.jonesvec((1,0)) >>> pol_mat = polarizer4x4(jvec, f) #x polarizer matrix """ jonesmat = polarizer2x2(jones) fmat = normalize_f(fmat) fmati = inv(fmat) pmat = as4x4(jonesmat) m = dotmm(fmat, dotmm(pmat, fmati, out=out), out=out) return m
def system_mat(cmat, fmatin=None, fmatout=None, fmatini=None, out=None): """Computes a system matrix from a characteristic matrix Fin-1.C.Fout""" if fmatini is None: if fmatin is None: fmatin = f_iso(1, 0, 0) fmatini = inv(fmatin) if fmatout is None: fmatout = fmatin out = dotmm(fmatini, cmat, out=out) return dotmm(out, fmatout, out=out)
def projection_mat(fmat, fmati=None, mode=+1): if fmati is None: fmati = inv(fmat) diag = np.zeros(fmat.shape[:-1], fmat.dtype) if mode == 1: diag[..., 0::2] = 1. elif mode == -1: diag[..., 1::2] = 1. else: raise ValueError("Unknown propagation mode.") return dotmdm(fmat, diag, fmati)
def E2H_mat(fmat, mode=+1, out=None): if mode == +1: A = fmat[..., ::2, ::2] B = fmat[..., 1::2, ::2] elif mode == -1: A = fmat[..., ::2, 1::2] B = fmat[..., 1::2, 1::2] else: raise ValueError("Unknown propagation mode.") Ai = inv(A, out=out) return dotmm(B, Ai, out=Ai)
def Epn_correction_matrix(beta, phi, ks, d=1., epsv=(1, 1, 1), epsa=(0, 0, 0.), out=None): alpha, f = alphaf(beta, phi, epsv, epsa) kd = -np.asarray(ks) * d pmat = phase_mat(alpha, kd[..., None, None]) e = E_mat(f, mode=None) ei = inv(e) return dotmdm(e, pmat, ei, out=out)
def S_mat(fin, fout, fini=None, overwrite_fin=False, mode=+1): if overwrite_fin == True: out = fin else: out = None if fini is None: fini = inv(fin, out=out) S = dotmm(fini, fout, out=out) if mode == +1: return S[..., ::2, ::2], S[..., 1::2, 0::2] elif mode == -1: return S[..., 1::2, 1::2], S[..., 0::2, 1::2] else: raise ValueError("Unknown propagation mode.")
def alphaffi(beta, phi, epsv, epsa, out=None): """Computes alpha and field arrays (eigen values and eigen vectors arrays) and inverse of the field array. See :func:`alphaf` for details Broadcasting rules apply. Returns ------- alpha, field, ifield : (ndarray, ndarray, ndarray) Eigen values and eigen vectors arrays and its inverse This is equivalent to >>> alpha,field = alphaf(0,0, [2,2,2], [0.,0.,0.]) >>> ifield = inv(field) """ if out is not None: a, f, fi = out _alphaf(beta, phi, epsv, epsa, out=(a, f)) inv(f, fi) else: a, f = _alphaf(beta, phi, epsv, epsa) fi = inv(f) return a, f, fi
def reflection_mat(smat, out=None): """Computes a 4x4 reflection matrix. """ m1 = np.zeros_like(smat) m2 = np.zeros_like(smat) m1[..., 1, 1] = 1. m1[..., 3, 3] = 1. m1[..., :, 0] = -smat[..., :, 0] m1[..., :, 2] = -smat[..., :, 2] m2[..., 0, 0] = -1. m2[..., 2, 2] = -1. m2[..., :, 1] = smat[..., :, 1] m2[..., :, 3] = smat[..., :, 3] m1 = inv(m1) return dotmm(m1, m2, out=out)
def _layer_mat3d(k0, d, epsv, epsa, mask, betas, phis, indices, method): n = len(betas) kd = k0 * d #/2. shape = epsv.shape[-3], epsv.shape[-2] if method.startswith("2x2"): out = np.empty(shape=(n, n, 2, 2), dtype=CDTYPE) else: out = np.empty(shape=(n, n, 4, 4), dtype=CDTYPE) for j, (beta, phi) in enumerate(zip(betas, phis)): if method.startswith("2x2"): alpha, fmat = alphaf(beta, phi, epsv, epsa) f = tmm.E_mat(fmat, mode=+1, copy=False) fi = inv(f) pmat = phase_mat(alpha[..., ::2], kd) else: alpha, f, fi = alphaffi(beta, phi, epsv, epsa) pmat = phase_mat(alpha, -kd) if method == "4x4_1": pmat[..., 1::2] = 0. if method != "4x4": raise ValueError("Unsupported method.") wave = eigenwave(shape, indices[j, 0], indices[j, 1], amplitude=1.) m = dotmdm(f, pmat, fi) mw = m * wave[..., None, None] mf = mfft2(mw, overwrite_x=True) #dd = np.linspace(0,1.,10)*d # dmat = 0. # for dm in dd: # dmat = dmat + second_field_diffraction_matrix(shape, -k0, beta, phi,dm, # epsv = (1.5,1.5,1.5), # epsa = (0.,0.,0.), betamax = 1.4) /len(dd) # mf = dotmm(dmat,mf) mf = mf[mask, ...] out[:, j, :, :] = mf return out
def _transfer_ray_4x4_2(field, wavenumbers, layer, beta=0, phi=0, nsteps=1, dmatpn=None, out=None, tmpdata=None): _out = {} if tmpdata is None else tmpdata d, epsv, epsa = layer if dmatpn is None: kd = wavenumbers * d else: dmatp, dmatn = dmatpn kd = wavenumbers * d / 2 alpha, f, fi = alphaffi(beta, phi, epsv, epsa, out=_out.get("affi")) p = phasem(alpha, kd[..., None, None], out=_out.get("p")) if tmpdata is not None: tmpdata["affi"] = (alpha, f, fi) tmpdata["p"] = p if dmatpn is not None: e = E_mat(f, mode=None) ei = inv(e, out=_out.get("ei")) if tmpdata is not None: tmpdata["ei"] = ei for j in range(nsteps): if dmatpn is None: field = dotmdmf(f, p, fi, field, out=out) else: field = dotmdmf(e, p, fi, field, out=out) diffract(field[..., 0::2, :, :], dmatp, out=field[..., 0::2, :, :]) diffract(field[..., 1::2, :, :], dmatn, out=field[..., 1::2, :, :]) field = dotmdmf(f, p, ei, field, out=field) return field
def second_Epn_diffraction_matrix(shape, ks, d=1., epsv=(1, 1, 1), epsa=(0, 0, 0.), betamax=BETAMAX, out=None): ks = np.asarray(ks, dtype=FDTYPE) epsv = np.asarray(epsv, dtype=CDTYPE) epsa = np.asarray(epsa, dtype=FDTYPE) alpha, f = diffraction_alphaf(shape, ks, epsv=epsv, epsa=epsa, betamax=betamax) kd = ks * d e = E_mat(f, mode=None) ei = inv(e) pmat = phase_mat(alpha, kd[..., None, None]) return dotmdm(f, pmat, ei, out=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 _transfer_ray_2x2_1(fft_field, wavenumbers, layer, effective_layer_in, effective_layer_out, dmat1, dmat2, beta=0, phi=0, nsteps=1, mode=+1, reflection=True, betamax=BETAMAX, refl=None, bulk=None, out=None, tmpdata=None): _out = {} if tmpdata is None else tmpdata #fft_field = fft2(fft_field, out = out) shape = fft_field.shape[-2:] d_in, epsv_in, epsa_in = effective_layer_in d_out, epsv_out, epsa_out = effective_layer_out if reflection: tmat, rmat = E_tr_matrix(shape, wavenumbers, epsv_in=epsv_in, epsa_in=epsa_in, epsv_out=epsv_out, epsa_out=epsa_out, mode=mode, betamax=betamax) d, epsv, epsa = layer alpha, fmat = alphaf(beta, phi, epsv, epsa, out=_out.get("alphaf")) e = E_mat(fmat, mode=mode, copy=False) #2x2 E-only view of fmat ei = inv(e, out=_out.get("ei")) # kd = wavenumbers * d p = phase_mat(alpha, kd[..., None, None], mode=mode, out=_out.get("p")) if tmpdata is not None: _out["alphaf"] = alpha, fmat _out["ei"] = ei _out["p"] = p for j in range(nsteps): if j == 0 and reflection: #reflect only at the beginning if refl is not None: trans = refl.copy() refl = dotmf(rmat, fft_field, out=refl) fft_field = dotmf(tmat, fft_field, out=out) fft_field = np.add(fft_field, trans, out=fft_field) if mode == -1 and bulk is not None: field = ifft2(fft_field) e2h = E2H_mat(fmat, mode=mode) bulk[..., ::2, :, :] += field bulk[..., 1::2, :, :] += dotmf(e2h, field, out=field) fft_field = dotmf(dmat1, fft_field, out=fft_field) out = fft_field else: fft_field = dotmf(tmat, fft_field, out=out) fft_field = dotmf(dmat1, fft_field, out=fft_field) out = fft_field else: if dmat1 is not None: fft_field = dotmf(dmat1, fft_field, out=out) out = fft_field field = ifft2(fft_field, out=out) field = dotmdmf(e, p, ei, field, out=field) fft_field = fft2(field, out=field) if dmat2 is not None: fft_field = dotmf(dmat2, fft_field, out=fft_field) #return fft_field, refl #out = ifft2(fft_field, out = out) if mode == +1 and bulk is not None: field = ifft2(fft_field) e2h = E2H_mat(fmat, mode=mode) bulk[..., 1::2, :, :] += dotmf(e2h, field) bulk[..., ::2, :, :] += field return fft_field, refl
def _transfer_ray_2x2_2(field, wavenumbers, in_layer, out_layer, dmat=None, beta=0, phi=0, nsteps=1, mode=+1, reflection=True, betamax=BETAMAX, refl=None, bulk=None, out=None, tmpdata=None): _out = {} if tmpdata is None else tmpdata if in_layer is not None: d, epsv, epsa = in_layer alpha, fmat_in = alphaf(beta, phi, epsv, epsa, out=_out.get("afin")) if tmpdata is not None: _out["afin"] = alpha, fmat_in d, epsv, epsa = out_layer alpha, fmat = alphaf(beta, phi, epsv, epsa, out=_out.get("afout")) e = E_mat(fmat, mode=mode, copy=False) #2x2 E-only view of fmat # if refl is not None: # ein = E_mat(fmat_in, mode = mode * (-1)) #reverse direction # # if reflection == 0: # kd = wavenumbers * d # else: kd = wavenumbers * d / 2 p = phase_mat(alpha, kd[..., None, None], mode=mode, out=_out.get("p")) ei0 = inv(e, out=_out.get("ei0")) ei = ei0 if tmpdata is not None: _out["afout"] = alpha, fmat _out["ei0"] = ei _out["p"] = p for j in range(nsteps): #reflect only at the beginning if j == 0 and reflection != 0: #if we need to track reflections (multipass) if refl is not None: #ei,eri = Etri_mat(fmat_in, fmat, mode = mode, out = _out.get("eieri")) tmat, rmat = tr_mat(fmat_in, fmat, mode=mode, out=_out.get("eieri")) if tmpdata is not None: #_out["eieri"] = ei,eri _out["eieri"] = tmat, rmat trans = refl.copy() #refl = dotmf(eri, field, out = refl) refl = dotmf(rmat, field, out=refl) #field = dotmf(ei,field, out = out) field = dotmf(tmat, field, out=out) field = np.add(field, trans, out=field) if mode == -1 and bulk is not None: #tmp_field = dotmf(e,field) tmp_field = field e2h = E2H_mat(fmat, mode=mode) bulk[..., ::2, :, :] += tmp_field bulk[..., 1::2, :, :] += dotmf(e2h, tmp_field) field = dotmf(ei, field, out=field) if d != 0.: field = dotmf(dotmd(e, p), field, out=field) else: field = dotmf(e, field, out=field) out = field # rmat = dotmm(ein, eri, out = eri) # trans = refl.copy() # refl = dotmf(rmat, field, out = refl) # ei0 = inv(e) # field = dotmf(ei,field, out = out) # field = dotmf(e,field) + trans # if d != 0.: # field = dotmdmf(e,p,ei0,field, out = out) ei = ei0 else: ei = Eti_mat(fmat_in, fmat, mode=mode, out=_out.get("eti")) field = dotmdmf(e, p, ei, field, out=out) out = field if tmpdata is not None: _out["eti"] = ei ei = ei0 else: #no need to compute if d == 0!.. identity if d != 0.: field = dotmdmf(e, p, ei, field, out=out) out = field if dmat is not None: field = diffract(field, dmat, out=out) out = field #no need to compute if d == 0!.. identity if d != 0.: field = dotmdmf(e, p, ei, field, out=out) if mode == +1 and bulk is not None: e2h = E2H_mat(fmat, mode=mode) bulk[..., 1::2, :, :] += dotmf(e2h, field) bulk[..., ::2, :, :] += field return field, refl
#: in 4x4 we are propagating backward--- minus sign must be taken in the phase p = tmm.phase_mat(a,-kd) # uncoment this to test that setting backward propagating waves to zero, # you have single reflections only... -same result as 2x2 with reflection. #p[...,1::2] = 0. #4x4 characteristic matrix m = dotmdm(f,p,fi) #we could have built layer matrices directly, note the there is no negative value in front of kd: #m = tmm.layer_mat(kd,eps_values, eps_angles, beta = beta, phi = phi) #e field 2x22 matrix.. skip the first layer (air) e = tmm.E_mat(f[1:], mode = +1) # the inverse, no reflections ei = linalg.inv(e) # the inverse, with reflections eti = tmm.Eti_mat(f[:-1], f[1:], mode = +1) p2 = tmm.phase_mat(a,kd, mode = +1)[:,1:] #2x2 characteristic matrix m2 = dotmdm(e,p2,ei) #no reflections m2t = dotmdm(e,p2,eti) #with reflections # multiply matrices together over second axis (first axis is wavelenght, second are layers) cmat = linalg.multi_dot(m, axis = 1) #the 2x2 matrices must be multiplied in reverse order... because we propagate forward cmat2 = linalg.multi_dot(m2, axis = 1, reverse = True) cmat2t = linalg.multi_dot(m2t, axis = 1, reverse = True)
def _system_mat2d(fmatin, cmat, fmatout): """Computes a system matrix from a characteristic matrix Fin-1.C.Fout""" fmatini = inv(fmatin) out = bdotdm(fmatini, cmat) return bdotmd(out, fmatout)