Exemplo n.º 1
0
## =======================================================================##

##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...
Exemplo n.º 2
0
def run_RCWA_2D(lam0, theta, phi, ER, UR, layer_thicknesses, lattice_constants,
                pte, ptm, N, M, e_half):
    '''
    :param lam0:
    :param theta: incident angle
    :param phi:   incident angle (azimuthal)
    :param ER: list of convolution matrices for each layer
    :param UR: list of convolution matrices for each layer
    :param layer_thicknesses: list of thicknesses of each layer
    :param lattice_constants: [Lx, Ly] 2 element array containing lattice constants of the 2D unit cell
    :param pte: te mode amplitude
    :param ptm: tm mode amplitude
    :param N:    num orders for x direction
    :param M:    num orders for y direction
    :param e_half: [e_r e_t], dielectric constants of the reflection and transmission spaces
    :return:
    '''
    ## convention specifications
    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
    ## ===========================

    Lx = lattice_constants[0]
    Ly = lattice_constants[1]
    NM = (2 * N + 1) * (2 * M + 1)

    # define vacuum wavevector k0
    k0 = 2 * np.pi / lam0
    ## ============== values to keep track of =======================##
    S_matrices = list()
    kz_storage = list()
    ## ==============================================================##

    m_r = 1
    e_r = e_half[0]
    ## incident wave properties, at this point, everything is in units of k_0
    n_i = np.sqrt(e_r * m_r)

    # actually, in the definitions here, kx = k0*sin(theta)*cos(phi), so kx, ky here are normalized
    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(e_r * 1 - kx_inc**2 - ky_inc**2)

    # remember, these Kx and Ky come out already normalized
    Kx, Ky = km.K_matrix_cubic_2D(kx_inc, ky_inc, k0, Lx, Ly, N, M)
    # Kx and Ky are diagonal but have a 0 on it

    ## =============== K Matrices for gap medium =========================
    ## specify gap media (this is an LHI so no eigenvalue problem should be solved
    e_h = 1
    Wg, Vg, Kzg = hl.homogeneous_module(Kx, Ky, e_h)

    ### ================= Working on the Reflection Side =========== ##
    Wr, Vr, kzr = hl.homogeneous_module(Kx, Ky, e_r)
    kz_storage.append(kzr)

    ## calculating A and B matrices for scattering matrix
    # since gap medium and reflection media are the same, this doesn't affect anything
    Ar, Br = sm.A_B_matrices(Wg, Wr, Vg, Vr)

    ## s_ref is a matrix, Sr_dict is a dictionary
    S_ref, Sr_dict = sm.S_R(Ar, Br)
    # scatter matrix for the reflection region
    S_matrices.append(S_ref)
    Sg = Sr_dict

    ## go through the layers
    for i in range(len(ER)):
        # ith layer material parameters
        e_conv = ER[i]
        mu_conv = UR[i]

        # longitudinal k_vector
        P, Q, kzl = pq.P_Q_kz(Kx, Ky, e_conv, mu_conv)
        kz_storage.append(kzl)
        Gamma_squared = P @ Q

        ## E-field modes that can propagate in the medium, these are well-conditioned
        W_i, lambda_matrix = em.eigen_W(Gamma_squared)
        V_i = em.eigen_V(Q, W_i, lambda_matrix)

        # now defIne A and B, slightly worse conditoined than W and V
        A, B = sm.A_B_matrices(W_i, Wg, V_i, Vg)
        # ORDER HERE MATTERS A LOT because W_i is not diagonal

        # calculate scattering matrix
        Li = layer_thicknesses[i]
        S_layer, Sl_dict = sm.S_layer(A, B, Li, k0, lambda_matrix)
        S_matrices.append(S_layer)

        ## update global scattering matrix using redheffer star
        Sg_matrix, Sg = rs.RedhefferStar(Sg, Sl_dict)

    ##========= Working on the Transmission Side==============##
    m_t = 1
    e_t = e_half[1]
    Wt, Vt, kz_trans = hl.homogeneous_module(Kx, Ky, e_t)

    # get At, Bt
    # since transmission is the same as gap, order does not matter
    At, Bt = sm.A_B_matrices(Wg, Wt, Vg, Vt)

    ST, ST_dict = sm.S_T(At, Bt)
    S_matrices.append(ST)
    # update global scattering matrix
    Sg_matrix, Sg = rs.RedhefferStar(Sg, ST_dict)

    ## finally CONVERT THE GLOBAL SCATTERING MATRIX BACK TO A MATRIX

    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,
                                                      N, M)
    # print(cinc.shape)
    # print(cinc)

    cinc = np.linalg.inv(Wr) @ cinc
    ## COMPUTE FIELDS: similar idea but more complex for RCWA since you have individual modes each contributing
    reflected = Wr @ Sg['S11'] @ cinc
    transmitted = Wt @ Sg['S21'] @ cinc

    rx = reflected[0:NM, :]
    # rx is the Ex component.
    ry = reflected[NM:, :]
    #
    tx = transmitted[0:NM, :]
    ty = transmitted[NM:, :]

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

    ## we need to do some reshaping at some point

    ## 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)
    #division by a scalar
    T = np.real(kz_trans) @ t_sq / (np.real(kz_inc))

    return np.sum(R), np.sum(T)


## need a simulation which can return the field profiles inside the structure
Exemplo n.º 3
0
##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
Exemplo n.º 4
0
        S_layer, Sl_dict = sm.S_layer(A, B, Li, k0, lambda_matrix)
        S_matrices.append(S_layer)

        ## update global scattering matrix using redheffer star
        Sg_matrix, Sg = rs.RedhefferStar(Sg, Sl_dict)

    ##========= Working on the Transmission Side==============##
    m_t = 1
    e_t = 1
    Wt, Vt, kz_trans = hl.homogeneous_module(Kx, Ky, e_t)

    #get At, Bt
    # since transmission is the same as gap, order does not matter
    At, Bt = sm.A_B_matrices(Wg, Wt, Vg, Vt)

    ST, ST_dict = sm.S_T(At, Bt)
    S_matrices.append(ST)
    #update global scattering matrix
    Sg_matrix, Sg = rs.RedhefferStar(Sg, ST_dict)

    ## finally CONVERT THE GLOBAL SCATTERING MATRIX BACK TO A MATRIX

    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,
                                                      N, M)
    # print(cinc.shape)
    # print(cinc)
def run_TMM_simulation(wavelengths, polarization_amplitudes, k_inc, theta, phi, ER, UR, layer_thicknesses,\
                       transmission_medium, incident_medium):
    """
    :param wavelengths:
    :param k_inc: holds kx, ky of the incident wave-vector (which is enough to specify kz since k0 is specified by wavelength
    :param theta:
    :param phi:
    :param ER: relative dielectric constants of each layer
    :param UR: relative permeability of each layer
    :param layer_thicknesses:
    :param transmission_medium:
    :param incident_medium:
    :return:
    """

    assert len(layer_thicknesses) == len(ER) == len(UR); "number of layer parameters not the same"

    ref = [];
    trans = [];
    I = np.matrix(np.eye(2, 2));  # unit 2x2 matrix

    [e_r, m_r] = incident_medium;
    [e_t, m_t] = transmission_medium;
    n_i = np.sqrt(e_r*m_r);
    [kx, ky] = k_inc;

    normal_vector = np.array([0, 0, -1])  # positive z points down;
    ate_vector = np.matrix([0, 1, 0]);  # vector for the out of plane E-field

    ## =================  specify gap media ========================##
    e_h = 1;
    m_h = 1;
    Pg, Qg, kzg = pq.P_Q_kz(kx, ky, e_h, m_h)
    Wg = I;  # Wg should be the eigenmodes of the E field, which paparently is the identity, yes for a homogeneous medium
    sqrt_lambda = cmath.sqrt(-1) * Wg;
    # remember Vg is really Qg*(Omg)^-1; Vg is the eigenmodes of the H fields
    Vg = Qg * Wg * (sqrt_lambda) ** -1;

    ## ========================================== ##

    [pte, ptm] = polarization_amplitudes;

    for i in range(len(wavelengths)):  # in SI units
        ## initialize global scattering matrix: should be a 4x4 identity so when we start the redheffer star, we get I*SR

        Sg11 = np.matrix(np.zeros((2, 2)));
        Sg12 = np.matrix(np.eye(2, 2));
        Sg21 = np.matrix(np.eye(2, 2));
        Sg22 = np.matrix(np.zeros((2, 2)));  # matrices
        Sg = np.block(
            [[Sg11, Sg12], [Sg21, Sg22]]);  # initialization is equivelant as that for S_reflection side matrix

        ### ================= Working on the Reflection Side =========== ##
        Pr, Qr, kzr = pq.P_Q_kz(kx, ky, e_r, m_r)

        ## ============== values to keep track of =======================##
        S_matrices = list();
        kz_storage = [kzr];
        X_storage = list();
        ## ==============================================================##

        # define vacuum wavevector k0
        lam0 = wavelengths[i];  # k0 and lam0 are related by 2*pi/lam0 = k0
        k0 = 2*np.pi/lam0;
        ## modes of the layer
        Om_r = np.matrix(cmath.sqrt(-1) * kzr * I);
        X_storage.append(Om_r);
        W_ref = I;
        V_ref = Qr * Om_r.I;  # can't play games with V like with W because matrices for V are complex

        ## calculating A and B matrices for scattering matrix
        Ar, Br = sm.A_B_matrices(Wg, W_ref, Vg, V_ref);

        S_ref, Sr_dict = sm.S_R(Ar, Br);  # scatter matrix for the reflection region
        S_matrices.append(S_ref);
        Sg, D_r, F_r = rs.RedhefferStar(Sg, S_ref);

        ## go through the layers
        for i in range(len(ER)):
            # ith layer material parameters
            e = ER[i];
            m = UR[i];

            # longitudinal k_vector
            P, Q, kzl = pq.P_Q_kz(kx, ky, e, m)
            kz_storage.append(kzl)

            ## E-field modes that can propagate in the medium
            W_i = I;
            ## corresponding H-field modes.
            Om = cmath.sqrt(-1) * kzl * I;
            X_storage.append(Om)
            V_i = Q * np.linalg.inv(Om);

            # now defIne A and B
            A, B = sm.A_B_matrices(Wg, W_i, Vg, V_i);

            # calculate scattering matrix
            S_layer, Sl_dict = sm.S_layer(A, B, layer_thicknesses[i], k0, Om)
            S_matrices.append(S_layer);

            ## update global scattering matrix using redheffer star
            Sg, D_i, F_i = rs.RedhefferStar(Sg, S_layer);

        ##========= Working on the Transmission Side==============##
        Pt, Qt, kz_trans = pq.P_Q_kz(kx, ky, e_t, m_t);
        kz_storage.append(kz_trans);

        Om = cmath.sqrt(-1) * kz_trans * I;
        Vt = Qt * np.linalg.inv(Om);

        # get At, Bt
        At, Bt = sm.A_B_matrices(Wg, I, Vg, Vt)

        ST, ST_dict = sm.S_T(At, Bt)
        S_matrices.append(ST);
        # update global scattering matrix
        Sg, D_t, F_t = rs.RedhefferStar(Sg, ST);

        K_inc_vector = n_i * k0 * np.matrix([np.sin(theta) * np.cos(phi), \
                                             np.sin(theta) * np.sin(phi), np.cos(theta)]);

        # cinc is the c1+
        E_inc, cinc, Polarization = ic.initial_conditions(K_inc_vector, theta, normal_vector, pte, ptm)

        ## COMPUTE FIELDS
        Er = Sg[0:2, 0:2] * cinc;  # S11; #(cinc = initial mode amplitudes), cout = Sg*cinc; #2d because Ex, Ey...
        Et = Sg[2:, 0:2] * cinc;  # S21

        Er = np.squeeze(np.asarray(Er));
        Et = np.squeeze(np.asarray(Et));

        Erx = Er[0];
        Ery = Er[1];
        Etx = Et[0];
        Ety = Et[1];

        # apply the grad(E) = 0 equation to get z components
        Erz = -(kx * Erx + ky * Ery) / kzr;
        Etz = -(kx * Etx + ky * Ety) / kz_trans;  ## using divergence of E equation here

        # add in the Erz component to vectors
        Er = np.matrix([Erx, Ery, Erz]);  # a vector
        Et = np.matrix([Etx, Ety, Etz]);

        R = np.linalg.norm(Er) ** 2;
        T = np.linalg.norm(Et) ** 2;
        ref.append(R);
        trans.append(T);

    return ref, trans
def run_TMM_anisotropic(wavelengths, polarization_amplitudes, theta, phi, ER, UR, layer_thicknesses,\
                       transmission_medium, incident_medium):
    ref = [];
    trans = []
    wvlen_scan = np.linspace(0.5, 4, 1000);
    thickness = 0.5; # 1 layer
    for wvlen in wvlen_scan:

        k0 = 2*np.pi/wvlen;
        kx = np.sin(theta)*np.cos(phi);
        ky = np.sin(theta)*np.sin(phi);

        # we will build the system by rows?
        a11 = -1j*(ky*mu_tensor[1,2]/mu_tensor[2,2] + kx*(epsilon_tensor[2,0]/epsilon_tensor[2,2]))
        a12 = 1j*kx*(mu_tensor[1,2]/mu_tensor[2,2] - epsilon_tensor[2,1]/epsilon_tensor[2,2]);
        a13 = kx*ky/epsilon_tensor[2,2] + mu_tensor[1,0] - mu_tensor[1,2]*mu_tensor[2,0]/mu_tensor[2,2];
        a14 = -kx**2/epsilon_tensor[2,2] + mu_tensor[1,1]-  mu_tensor[1,2]*mu_tensor[2,1]/mu_tensor[2,2];

        a21 = 1j* ky *(mu_tensor[0,2]/mu_tensor[2,2] - epsilon_tensor[2,0]/epsilon_tensor[2,2]);
        a22 = -1j * kx*(mu_tensor[0,2]/mu_tensor[2,2]) +ky *(epsilon_tensor[2,1]/epsilon_tensor[2,2]);
        a23 = ky**2/epsilon_tensor[2,2] - mu_tensor[0,0] +  mu_tensor[0,2]*mu_tensor[2,0]/mu_tensor[2,2];
        a24 =  -kx*ky/epsilon_tensor[2,2] - mu_tensor[0,1] + mu_tensor[0,2]*mu_tensor[2,1]/mu_tensor[2,2];

        a31 = (kx*ky/mu_tensor[2,2] + epsilon_tensor[1,0] - epsilon_tensor[1,2]*epsilon_tensor[2,0]/epsilon_tensor[2,2])
        a32 = (-kx**2/mu_tensor[2,2] +epsilon_tensor[1,1] - epsilon_tensor[1,2]*epsilon_tensor[2,1]/epsilon_tensor[2,2]);
        a33 = -1j*(ky*(epsilon_tensor[1,2]/epsilon_tensor[2,2])+kx*(mu_tensor[2,0]/mu_tensor[2,2]));
        a34 = 1j*kx*(epsilon_tensor[1,2]/epsilon_tensor[2,2]-mu_tensor[2,1]/mu_tensor[2,2] )

        a41 = ky**2/mu_tensor[2,2] - epsilon_tensor[0,0] +  epsilon_tensor[0,2]*epsilon_tensor[2,0]/epsilon_tensor[2,2];
        a42 = -kx*ky/mu_tensor[2,2] - epsilon_tensor[0,1] + epsilon_tensor[0,2]*epsilon_tensor[2,1]/epsilon_tensor[2,2];
        a43 = 1j*ky*(epsilon_tensor[0,2]/epsilon_tensor[2,2]-mu_tensor[2,0]/mu_tensor[2,2] );
        a44 = -1j*(kx*(epsilon_tensor[0,2]/epsilon_tensor[2,2])+ky*(mu_tensor[2,1]/mu_tensor[2,2]));

        A = np.matrix([[a11, a12, a13, a14],
                      [a21, a22, a23, a24],
                      [a31, a32, a33, a34],
                      [a41, a42, a43, a44]]);

        #print(np.linalg.cond(A))
        eigenvals, eigenmodes = np.linalg.eig(A);
        rounded_eigenvals = np.round(eigenvals, 3)
        sorted_eigs, sorted_inds = nonHermitianEigenSorter(np.round(eigenvals,10));

        ## ========================================================
        W_i = eigenmodes[0:2, sorted_inds];
        V_i = eigenmodes[2:, sorted_inds];
        Om =  np.matrix(np.diag(sorted_eigs) );
        #print(np.round(W_i,3), np.round(V_i,3), np.round(Om,3))

        #then what... match boundary conditions... try using the gaylord formulation.
        # or use the scattering matrix formalism, where we still, technically deal with all field components...

        Sg11 = np.matrix(np.zeros((2, 2))); Sg12 = np.matrix(np.eye(2, 2));
        Sg21 = np.matrix(np.eye(2, 2)); Sg22 = np.matrix(np.zeros((2, 2)));  # matrices
        Sg = np.block([[Sg11, Sg12], [Sg21, Sg22]]);  # initialization is equivelant as that for S_reflection side matrix

        ### ================= Working on the Reflection Side =========== ##
        Pr, Qr, kzr = pq.P_Q_kz(kx, ky, e_r, m_r)

        ## ============== values to keep track of =======================##
        S_matrices = list();
        kz_storage = [kzr];
        X_storage = list();
        ## ==============================================================##

        # define vacuum wavevector k0
        lam0 = wvlen;  # k0 and lam0 are related by 2*pi/lam0 = k0
        k0 = 2*np.pi/lam0;
        ## modes of the layer
        Om_r = np.matrix(cmath.sqrt(-1) * kzr * I);
        X_storage.append(Om_r);
        W_ref = I;
        V_ref = Qr * Om_r.I;  # can't play games with V like with W because matrices for V are complex
        #print(Om_r)
        ## calculating A and B matrices for scattering matrix
        Ar, Br = sm.A_B_matrices(Wg, W_ref, Vg, V_ref);

        S_ref, Sr_dict = sm.S_R(Ar, Br);  # scatter matrix for the reflection region
        S_matrices.append(S_ref);
        Sg, D_r, F_r = rs.RedhefferStar(Sg, S_ref);

        # longitudinal k_vector
        ## ============ WORKING INSIDE ANISOTROPIC LAYER ================#
        # now defIne A and B
        Al, Bl = sm.A_B_matrices(Wg, W_i, Vg, V_i);

        # calculate scattering matrix
        S_layer, Sl_dict = sm.S_layer(Al, Bl, thickness, k0, Om)
        S_matrices.append(S_layer);

        ## update global scattering matrix using redheffer star
        Sg, D_i, F_i = rs.RedhefferStar(Sg, S_layer);

        ##========= Working on the Transmission Side==============##
        Pt, Qt, kz_trans = pq.P_Q_kz(kx, ky, e_t, m_t);
        kz_storage.append(kz_trans);

        Omt = cmath.sqrt(-1) * kz_trans * I;
        Vt = Qt * np.linalg.inv(Omt);

        # get At, Bt
        At, Bt = sm.A_B_matrices(Wg, I, Vg, Vt)

        ST, ST_dict = sm.S_T(At, Bt)
        S_matrices.append(ST);
        # update global scattering matrix
        Sg, D_t, F_t = rs.RedhefferStar(Sg, ST);

        K_inc_vector = n_i * k0 * np.matrix([np.sin(theta) * np.cos(phi), \
                                             np.sin(theta) * np.sin(phi), np.cos(theta)]);

        # cinc is the c1+
        E_inc, cinc, Polarization = ic.initial_conditions(K_inc_vector, theta, normal_vector, pte, ptm)

        ## COMPUTE FIELDS
        Er = Sg[0:2, 0:2] * cinc;  # S11; #(cinc = initial mode amplitudes), cout = Sg*cinc; #2d because Ex, Ey...
        Et = Sg[2:, 0:2] * cinc;  # S21

        Er = np.squeeze(np.asarray(Er));
        Et = np.squeeze(np.asarray(Et));

        Erx = Er[0];  Ery = Er[1]; Etx = Et[0]; Ety = Et[1];

        # apply the grad(E) = 0 equation to get z components, this equation comes out of the longitudinal equation 
        # or the divergence equation and is valid since the transmission region is VACUUM (as is the reflection region)
        Erz = -(kx * Erx + ky * Ery) / kzr; #uses the divergence law
        Etz = -(kx * Etx + ky * Ety) / kz_trans;  ## using divergence of E equation here

        # add in the Erz component to vectors
        Er = np.matrix([Erx, Ery, Erz]);  # a vector
        Et = np.matrix([Etx, Ety, Etz]);

        R = np.linalg.norm(Er) ** 2;
        T = np.linalg.norm(Et) ** 2;
        ref.append(R);
        trans.append(T);
        
    return ref, trans;
Exemplo n.º 7
0
    ## S matrices for the reflection region
    #Ar, Br = sm.A_B_matrices(Wg, Wr, Vg, Vr);
    Ar, Br = sm.A_B_matrices_half_space(Wr, Wg, Vr, Vg);  # make sure this order is right

    S_ref, Sr_dict = sm.S_R(Ar, Br);  # scatter matrix for the reflection region    ## calculating A and B matrices for scattering matrix
    Sg = Sr_dict;

    ## define S matrix for the GRATING REGION
    A, B = sm.A_B_matrices(W, Wg,  V, Vg);
    S, S_dict = sm.S_layer(A, B, d, k0, lambda_matrix)
    Sg_matrix, Sg = rs.RedhefferStar(Sg, S_dict)

    ## define S matrices for the Transmission region
    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); #scatter matrix for the reflection region
    Sg_matrix, Sg = rs.RedhefferStar(Sg, St_dict)

    #check scattering matrix is unitary
    #print(np.linalg.norm(np.linalg.inv(Sg_matrix)@Sg_matrix - np.matrix(np.eye(2*(2*num_ord+1)))))

    ## ======================== CALCULATE R AND T ===============================##
    K_inc_vector =  n1*np.matrix([np.sin(theta_inc), \
                                         0, np.cos(theta_inc)]);
    #K_inc isn't even used for anyting...

    #cinc is the incidence vector
    cinc = np.zeros((2*num_ord+1, )); #only need one set...
    cinc[num_ord] = 1;
    cinc = cinc.T;
    cinc = np.linalg.inv(Wr) @ cinc;
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)