Kx, Ky = km.K_matrix_cubic_2D(beta_x, beta_y, ax, ay, P, Q)

    #from here, we can actually dtermine omega from our specification of kx and ky
    # omega = c0*np.sqrt(beta_x**2+beta_y**2)/L0;
    #
    # ## we can do a determination of a dispersive medium from here
    # #drude for example
    #eps_drude = 1-omega_p**2/(omega**2-cmath.sqrt(-1)*gamma*omega);
    #print(eps_drude); eps_tracker.append(eps_drude);

    epsilon = np.ones((Nx, Ny))
    halfy = int(Ny / 2)
    epsilon[halfy - 100:halfy + 100, :] = 12

    ## =============== Convolution Matrices ==============
    E_r = cm.convmat2D(epsilon, P, Q)
    ## ===========================================================

    eigenvalues, eigenvectors, A_matrix = eg.PWEM2D_TE(Kx, Ky, E_r)
    #what are the eigenvalue units
    omega_eig_store.append(np.sqrt(abs(np.real(eigenvalues))))
    plt.plot(beta_x * np.ones((PQ, )),
             np.sort(np.sqrt(abs(np.real(eigenvalues)))), '.b')
    plt.plot(beta_x * np.ones((PQ, )),
             np.sort(np.sqrt(abs(np.imag(eigenvalues)))), '.r')

## plot the light line

plt.plot(kx_scan, abs(kx_scan))

plt.show()
Example #2
0
    #print(str(nx1)+', '+str(nx2))
    ER[nx1:nx2+1, int(ny_ind), 0] = er1;

# plt.imshow(ER[:,:,0])
# plt.colorbar()
# plt.show()
# Af = np.fft.fftshift(np.fft.fft2(ER[:,:,0]));
# plt.figure();
# plt.subplot(121)
# plt.imshow(np.log(abs(Af))); #note that the fft HAS A HUGE RANGE OF VALUES, which can become a source of inaccuracy
# plt.colorbar()
# plt.subplot(122)
# plt.imshow(np.abs(ER[:,:,0]))
# plt.show();
## conv matrices of the 1st
E_conv = (cm.convmat2D(ER[:, :, 0], PQ[0], PQ[1]));
np.set_printoptions(precision = 4)
print(E_conv)
mu_conv = (np.identity(NH));

## Build the second layer (uniform)
URC2 =  (np.identity(NH))
ERC2= erd*(np.identity(NH));


## BUILD THE K_MATRIX
kx_inc = n_i * np.sin(theta) * np.cos(phi);
ky_inc = n_i * np.sin(theta) * np.sin(phi);  # constant in ALL LAYERS; ky = 0 for normal incidence
kz_inc = cmath.sqrt(n_i**2 - kx_inc ** 2 - ky_inc ** 2);

Kx, Ky = km.K_matrix_cubic_2D(kx_inc, ky_inc, k0, Lx, Ly,  PQ[0], PQ[1]);
# ============== build high resolution circle ==================
Nx = 512; Ny = 512;
A = np.ones((Nx,Ny));
ci = int(Nx/2); cj= int(Ny/2);
cr = (radius/a)*Nx;
I,J=np.meshgrid(np.arange(A.shape[0]),np.arange(A.shape[1]));

dist = np.sqrt((I-ci)**2 + (J-cj)**2);
A[np.where(dist<cr)] = e_r;

#visualize structure
plt.imshow(A);
plt.show()

## =============== Convolution Matrices ==============
E_r = cm.convmat2D(A, P,Q)
print(E_r.shape)
print(type(E_r))
plt.figure();
plt.imshow(abs(E_r), cmap = 'jet');
plt.colorbar()
plt.show()

## =============== K Matrices =========================
beta_x = beta_y = 0;
plt.figure();

## check K-matrices for normal icnidence
Kx, Ky = km.K_matrix_cubic_2D(0,0, a, a, P, Q);
np.set_printoptions(precision = 3)
    Nx = 512
    Ny = 512
    A = e_r * np.ones((Nx, Ny))
    A = A.astype('complex')
    x1 = int(Nx / 2) - 50
    x2 = int(Nx / 2) + 50
    y1 = int(Ny / 2) - 50
    y2 = int(Ny / 2) + 50

    A[:, y1:y2] = eps_drude
    ## A METALLIC HOLE...the fact that we have to recalculate the convolution

    # plt.imshow(np.abs(A));
    # plt.show();
    ## =============== Convolution Matrices ==============
    E_r = cm.convmat2D(A, N, M)

    NM = (2 * N + 1) * (2 * M + 1)

    ## ================== GEOMETRY OF THE LAYERS AND CONVOLUTIONS ==================##
    thickness_slab = 0.2
    # in units of L0;
    ER = [E_r]
    UR = [np.identity(NM)]
    layer_thicknesses = [thickness_slab]
    # this retains SI unit convention

    #source parameters
    theta = 0 * degrees
    #%elevation angle
    phi = 0 * degrees
    #print(str(nx1)+', '+str(nx2))
    ER[nx1:nx2+1, int(ny_ind), 0] = er1;

# plt.imshow(ER[:,:,0])
# plt.colorbar()
# plt.show()
Af = np.fft.fftshift(np.fft.fft2(ER[:,:,0]));
plt.figure();
plt.subplot(121)
plt.imshow(np.log(abs(Af))); #note that the fft HAS A HUGE RANGE OF VALUES, which can become a source of inaccuracy
plt.colorbar()
plt.subplot(122)
plt.imshow(np.abs(ER[:,:,0]))
plt.show();
## conv matrices of the 1st
E_conv = np.matrix(cm.convmat2D(ER[:, :, 0], PQ[0], PQ[1]));
np.set_printoptions(precision = 4)
print(E_conv)
mu_conv = np.matrix(np.identity(NH));

## Build the second layer (uniform)
URC2 = np.matrix(np.identity(NH))
ERC2= erd*np.matrix(np.identity(NH));
ER = [E_conv, ERC2];
UR = [mu_conv, URC2];

wavelengths = np.linspace(0.5, 5, 501)*centimeters
ref = list(); trans = list();

for i in range(len(wavelengths)): #in SI units
## Specify number of fourier orders to use:
#sometimes can get orders which make the system singular

N = 2
M = 2
NM = (2 * N + 1) * (2 * M + 1)

# ============== build high resolution circle ==================

E_r = e_layer * np.matrix(np.identity(NM))
U_r = np.matrix(np.identity(NM))

#check that the convmat returns an identity matrix
eps_grid = np.ones((512, 512))
er_check = e_layer * cm.convmat2D(eps_grid, N, M)
er_fft = np.fft.fftshift(np.fft.fft(np.ones((3, 3)))) / (9)

## ================== GEOMETRY OF THE LAYERS AND CONVOLUTIONS ==================##
thickness_slab = 0.76 * L0
#100 nm;
ER = [E_r]
UR = [U_r]
layer_thicknesses = [thickness_slab]
#this retains SI unit convention

## =============== Simulation Parameters =========================
## set wavelength scanning range
wavelengths = L0 * np.linspace(0.25, 1, 1000)
#500 nm to 1000 nm #LHI fails for small wavelengths?
kmagnitude_scan = 2 * np.pi / wavelengths
Example #7
0
    A = e_r * np.ones((Nx, Ny))
    A = A.astype('complex')
    A2 = e_r * np.ones((Nx, Ny))
    A2 = A2.astype('complex')
    x1 = int(Nx / 2) - 50
    x2 = int(Nx / 2) + 50
    y1 = int(Ny / 2) - 50
    y2 = int(Ny / 2) + 50

    A[:, y1:y2] = eps_drude
    ## A METALLIC HOLE...the fact that we have to recalculate the convolution
    A2[x1:x2, :] = eps_drude
    # plt.imshow(np.abs(A));
    # plt.show();
    ## =============== Convolution Matrices ==============
    E_r = cm.convmat2D(A, N, M)
    E_r2 = cm.convmat2D(A2, N, M)
    NM = (2 * N + 1) * (2 * M + 1)

    ## ================== GEOMETRY OF THE LAYERS AND CONVOLUTIONS ==================##
    thickness_slab = 0.2
    # in units of L0;
    ER = [E_r, e_r * np.identity(NM), E_r2]
    UR = [np.identity(NM), np.identity(NM),
          np.identity(NM)]
    layer_thicknesses = [thickness_slab, thickness_slab, thickness_slab]
    # this retains SI unit convention

    #source parameters
    theta = 0 * degrees
    #%elevation angle
def fun():
    '''
    run the RCWA simulation...do not use this code...
    :return:
    '''
    meters = 1
    centimeters = 1e-2 * meters
    degrees = np.pi / 180

    # Source parameters
    lam0 = 2 * centimeters
    theta = 0
    phi = 0
    pte = 1
    # te polarized
    ptm = 0
    normal_vector = np.array([0, 0, -1])  # positive z points down;
    ate_vector = np.array([0, 1, 0])
    # vector for the out of plane E-field
    k0 = 2 * np.pi / lam0
    print('k0: ' + str(k0))
    # structure parameters
    # reflection 1 and transmission 2
    ur1 = 1
    er1 = 2
    n_i = np.sqrt(ur1 * er1)
    ur2 = 1
    er2 = 9

    ## second layer
    urd = 1
    erd = 6

    # dimensions of the unit cell
    Lx = 1.75 * centimeters
    Ly = 1.5 * centimeters

    # thickness of layers
    d1 = 0.5 * centimeters
    d2 = 0.3 * centimeters
    w = 0.8 * Ly

    # RCWA parameters
    Nx = 512
    Ny = round(Nx * Ly / Lx)
    PQ = [1, 1]
    # number of spatial harmonics
    NH = (2 * (PQ[0]) + 1) * (2 * (PQ[1]) + 1)

    ## =========================== BUILD DEVICE ON GRID ==================================##
    dx = Lx / Nx
    dy = Ly / Ny
    xa = np.linspace(0, Lx, Nx)
    xa = xa - np.mean(xa)
    ya = np.linspace(0, Ly, Ny)
    ya = ya - np.mean(ya)

    # initialize layers

    UR = np.ones((Nx, Ny, 2))
    # interestin
    ER = erd * np.ones((Nx, Ny, 2))

    L = [d1, d2]

    # Build the triangle
    h = 0.5 * np.sqrt(3) * w
    ny = int(np.round(h / dy))
    # discrete height
    ny1 = np.round((Ny - ny) / 2)
    ny2 = ny1 + ny - 1
    print(str(ny1) + ', ' + str(ny2))

    for ny_ind in np.arange(ny1, ny2 + 1):
        # build the triangle slice wise
        f = (ny_ind - ny1) / (ny2 - ny1)
        # fractional occupation;

        nx = int(round(f * (w / Lx) * Nx))
        # x width
        nx1 = 1 + int(np.floor((Nx - nx) / 2))
        nx2 = int(nx1 + nx)
        # print(str(nx1)+', '+str(nx2))
        ER[nx1:nx2 + 1, int(ny_ind), 0] = er1

    E_conv = (cm.convmat2D(ER[:, :, 0], PQ[0], PQ[1]))
    np.set_printoptions(precision=4)
    print(E_conv)
    mu_conv = (np.identity(NH))

    ## Build the second layer (uniform)
    URC2 = (np.identity(NH))
    ERC2 = erd * (np.identity(NH))

    ## BUILD THE K_MATRIX
    kx_inc = n_i * np.sin(theta) * np.cos(phi)
    ky_inc = n_i * np.sin(theta) * np.sin(phi)
    # constant in ALL LAYERS; ky = 0 for normal incidence
    kz_inc = cmath.sqrt(n_i**2 - kx_inc**2 - ky_inc**2)

    Kx, Ky = km.K_matrix_cubic_2D(kx_inc, ky_inc, k0, Lx, Ly, PQ[0], PQ[1])

    # gap media
    Wg, Vg, Kzg = hl.homogeneous_module(Kx, Ky, 2)

    ## Get Kzr and Kztrans
    Wr, Vr, Kzr = hl.homogeneous_module(Kx, Ky, er1)
    Ar, Br = sm.A_B_matrices_half_space(Wr, Wg, Vr, Vg)
    # make sure this order is right
    Sr, Sr_dict = sm.S_R(Ar, Br)
    Sg = Sr_dict

    ## =================================================================##
    ##               First LAYER (homogeneous)
    ## =======================================================================##
    P, Q, Kzl = pq.P_Q_kz(Kx, Ky, E_conv, mu_conv)
    omega_sq = P @ Q
    ## no gaurantees this is hermitian or symmetric
    W1, lambda_matrix = em.eigen_W(omega_sq)
    V1 = em.eigen_V(Q, W1, lambda_matrix)
    A1, B1 = sm.A_B_matrices(W1, Wg, V1, Vg)
    S1, S1_dict = sm.S_layer(A1, B1, d1, k0, lambda_matrix)
    Sg_matrix, Sg = rs.RedhefferStar(Sg, S1_dict)

    ## =================================================================##
    ##               SECOND LAYER (homogeneous)
    ## =======================================================================##

    ##check with PQ formalism, which is unnecessary
    P2, Q2, Kz2_check = pq.P_Q_kz(Kx, Ky, ERC2, URC2)
    omega_sq_2 = P2 @ Q2
    W2, lambda_matrix_2 = em.eigen_W(
        omega_sq_2)  # somehow lambda_matrix is fine but W is full of errors
    V2 = em.eigen_V(Q2, W2, lambda_matrix_2)
    A2, B2 = sm.A_B_matrices(W2, Wg, V2, Vg)
    S2, S2_dict = sm.S_layer(A2, B2, d2, k0, lambda_matrix_2)
    Sg_matrix, Sg = rs.RedhefferStar(Sg, S2_dict)

    ## TRANSMISSION LAYER
    # #create ST
    Wt, Vt, Kzt = hl.homogeneous_module(Kx, Ky, er2)
    At, Bt = sm.A_B_matrices_half_space(Wt, Wg, Vt, Vg)
    # make sure this order is right
    St, St_dict = sm.S_T(At, Bt)
    ### FUCKKKKKKKKKKKKKKKK
    Sg_matrix, Sg = rs.RedhefferStar(Sg, St_dict)

    print('final Sg')
    print(Sg['S11'])

    ## ================START THE SSCATTERING CALCULATION ==========================##

    K_inc_vector = n_i * np.array([np.sin(theta) * np.cos(phi), \
                                   np.sin(theta) * np.sin(phi), np.cos(theta)])
    E_inc, cinc, Polarization = ic.initial_conditions(K_inc_vector, theta,
                                                      normal_vector, pte, ptm,
                                                      PQ[0], PQ[1])

    ## COMPUTE FIELDS: similar idea but more complex for RCWA since you have individual modes each contributing
    reflected = Wr @ Sg['S11'] @ cinc
    # reflection coefficients for every mode...
    transmitted = Wt @ Sg['S21'] @ cinc

    ## these include only (rx, ry), (tx, ty), which is okay as these are the only components for normal incidence in LHI
    rx = reflected[0:NH, :]
    ry = reflected[NH:, :]
    tx = transmitted[0:NH, :]
    ty = transmitted[NH:, :]

    # longitudinal components; should be 0
    rz = np.linalg.inv(Kzr) @ (Kx @ rx + Ky @ ry)
    tz = np.linalg.inv(Kzt) @ (Kx @ tx + Ky @ ty)

    print('rx')
    print(rx)
    print('ry')
    print(ry)
    print('rz')
    print(rz)

    ## apparently we're not done...now we need to compute 'diffraction efficiency'
    r_sq = np.square(np.abs(rx)) + np.square(np.abs(ry)) + np.square(
        np.abs(rz))
    t_sq = np.square(np.abs(tx)) + np.square(np.abs(ty)) + np.square(
        np.abs(tz))
    R = np.real(Kzr) @ r_sq / np.real(kz_inc)
    T = np.real(Kzt) @ t_sq / (np.real(kz_inc))

    print('final R vector-> matrix')
    print(np.reshape(R, (3, 3)))
    # should be 3x3
    print('final T vector/matrix')
    print(np.reshape(T, (3, 3)))
    print('final reflection: ' + str(np.sum(R)))
    print('final transmission: ' + str(np.sum(T)))
    print('sum of R and T: ' + str(np.sum(R) + np.sum(T)))

    ## if the sum isn't 1, that's a PROBLEM
    t1 = time.time()
    return np.sum(R), np.sum(T)