Пример #1
0
    def rotate(self, angle):
        """Rotate the polygon around its center of mass by `angle` radians
        """

        rotmat = bd.array([[bd.cos(angle), -bd.sin(angle)], \
                            [bd.sin(angle), bd.cos(angle)]])
        (xj, yj) = (bd.array(self.x_edges), bd.array(self.y_edges))
        com_x = bd.sum((xj + bd.roll(xj, -1)) * (xj * bd.roll(yj, -1) - \
                    bd.roll(xj, -1) * yj))/6/self.area
        com_y = bd.sum((yj + bd.roll(yj, -1)) * (xj * bd.roll(yj, -1) - \
                    bd.roll(xj, -1) * yj))/6/self.area
        new_coords = bd.dot(rotmat, bd.vstack((xj-com_x, yj-com_y)))

        self.x_edges = new_coords[0, :] + com_x
        self.y_edges = new_coords[1, :] + com_y

        return self
Пример #2
0
def D22(omega, g, eps_array, d_array, pol='TM'):
    """
    Function to get TE guided modes by solving D22=0
    Input
        omega           : frequency * 2π , in units of light speed/unit length
        g               : wave vector along propagation direction
        eps_array       : shape[M+1,1], slab permittivities
        d_array         : thicknesses of each layer
    Output
        D_22
    """
    if eps_array.size == 3:
        (eps1, eps2, eps3) = [e for e in eps_array]
        # (chis1, chis2, chis3) = [chi(omega, g, e) for e in eps_array]
        (chis1, chis2, chis3) = chis_3layer(omega, g, eps_array)

        tcos = -1j*bd.cos(chis2*d_array)
        tsin = -bd.sin(chis2*d_array)

        if pol.lower() == 'te':
            D22 = chis2*(chis1 + chis3)*tcos + \
                    (chis1*chis3 + bd.square(chis2))*tsin
        elif pol.lower() == 'tm':    
            D22 = chis2/eps2*(chis1/eps1 + chis3/eps3)*tcos + \
                    (chis1/eps1*chis3/eps3 + bd.square(chis2/eps2))*tsin
        return D22
    else:
        if pol.lower() == 'te':
            S_mat, T_mat = S_T_matrices_TE(omega, g, eps_array, d_array)
        elif pol.lower() == 'tm':
            S_mat, T_mat = S_T_matrices_TM(omega, g, eps_array, d_array)
        else:
            raise ValueError("Polarization should be 'TE' or 'TM'.")

        D = S_mat[0,:,:]
        for i,S in enumerate(S_mat[1:]):
            T = T_mat[i]
            D = bd.dot(S, bd.dot(T, bd.dot(T, D)))
        return D[1,1]
Пример #3
0
def I_alpha(a, d): # integrate exp(iaz)dz from -d/2 to d/2
    a = a + 1e-20
    return 2 / a * bd.sin(a*d/2)
Пример #4
0
def D22s_vec(omegas, g, eps_array, d_array, pol='TM'):
    """
    Vectorized function to compute the matrix element D22 that needs to be zero
    Input
        omegas          : list of frequencies
        g               : wave vector along propagation direction (ß_x)
        eps_array       : shape[M+1,1], slab permittivities
        d_array         : thicknesses of each layer
        pol             : 'TE'/'TM'
    Output
        D_22            : list of the D22 matrix elements corresponding to each 
                            omega

    Note: This function is used to find intervals at which D22 switches sign.
    It is currently not used in the root finding, but it could be useful if 
    there is a routine that can take advantage of the vectorization. 
    """
    if isinstance(omegas, float):
        omegas = np.array([omegas])

    N_oms = omegas.size # mats below will be of shape [2*N_oms, 2]

    def S_TE(eps1, eps2, chis1, chis2):
        # print((np.real(chis1) + np.imag(chis1)) / chis1)
        S11 = 0.5 / chis2 * (chis1 + chis2)
        S12 = 0.5 / chis2 * (-chis1 + chis2)
        return (S11, S12, S12, S11)

    def S_TM(eps1, eps2, chis1, chis2):
        S11 = 0.5 / (chis2/eps2) * (chis1/eps1 + chis2/eps2)
        S12 = 0.5 / (chis2/eps2) * (-chis1/eps1 + chis2/eps2)
        return (S11, S12, S12, S11)

    def S_T_prod(mats, omegas, g, eps1, eps2, d):
        """
        Get the i-th S and T matrices for an array of omegas given the i-th slab 
        thickness d and permittivity of the slab eps1 and the next layer eps2
        """

        chis1 = chi(omegas, g, eps1)
        chis2 = chi(omegas, g, eps2)

        if pol.lower() == 'te':
            (S11, S12, S21, S22) = S_TE(eps1, eps2, chis1, chis2)
        elif pol.lower() == 'tm':
            (S11, S12, S21, S22) = S_TM(eps1, eps2, chis1, chis2)
        
        T11 = np.exp(1j*chis1*d)
        T22 = np.exp(-1j*chis1*d)

        T_dot_mats = np.zeros(mats.shape, dtype=np.complex)
        T_dot_mats[0::2, :] = mats[0::2, :]*T11[:, np.newaxis]
        T_dot_mats[1::2, :] = mats[1::2, :]*T22[:, np.newaxis]

        S_dot_T = np.zeros(mats.shape, dtype=np.complex)
        S_dot_T[0::2, 0] = S11*T_dot_mats[0::2, 0] + S12*T_dot_mats[1::2, 0]
        S_dot_T[0::2, 1] = S11*T_dot_mats[0::2, 1] + S12*T_dot_mats[1::2, 1]
        S_dot_T[1::2, 0] = S21*T_dot_mats[0::2, 0] + S22*T_dot_mats[1::2, 0]
        S_dot_T[1::2, 1] = S21*T_dot_mats[0::2, 1] + S22*T_dot_mats[1::2, 1]

        return S_dot_T

    if eps_array.size == 3:
        (eps1, eps2, eps3) = [e for e in eps_array]
        # (chis1, chis2, chis3) = [chi(omegas, g, e) for e in eps_array]
        (chis1, chis2, chis3) = chis_3layer(omegas, g, eps_array)

        tcos = -1j*bd.cos(chis2*d_array)
        tsin = -bd.sin(chis2*d_array)

        if pol.lower() == 'te':
            D22s = chis2*(chis1 + chis3)*tcos + \
                    (chis1*chis3 + bd.square(chis2))*tsin
        elif pol.lower() == 'tm':    
            D22s = chis2/eps2*(chis1/eps1 + chis3/eps3)*tcos + \
                    (chis1/eps1*chis3/eps3 + bd.square(chis2/eps2))*tsin

    else:
        # Starting matrix array is constructed from S0
        (eps1, eps2) = (eps_array[0], eps_array[1])
        chis1 = chi(omegas, g, eps1)
        chis2 = chi(omegas, g, eps2)

        if pol.lower() == 'te':
            (S11, S12, S21, S22) = S_TE(eps1, eps2, chis1, chis2)
        elif pol.lower() == 'tm':
            (S11, S12, S21, S22) = S_TM(eps1, eps2, chis1, chis2)

        mats = np.zeros((2*N_oms, 2), dtype=np.complex)
        mats[0::2, 0] = S11
        mats[1::2, 0] = S21
        mats[0::2, 1] = S12
        mats[1::2, 1] = S22

        for il in range(1, eps_array.size - 1):
            mats = S_T_prod(mats, omegas, g, eps_array[il], 
                                eps_array[il+1], d_array[il-1])

        D22s = mats[1::2, 1]

    return D22s
Пример #5
0
    def __init__(self,
                 eps=1,
                 x_cent=0,
                 y_cent=0,
                 f_as=np.array([0.]),
                 f_bs=np.array([]),
                 npts=100):
        """Create a shape defined by its Fourier coefficients in polar 
        coordinates.

        Parameters
        ----------
        eps : float
            Permittivity value
        x_cent : float
            x-coordinate of shape center
        y_cent : float
            y-coordinate of shape center
        f_as : Numpy array
            Fourier coefficients an (see Note)
        f_bs : Numpy array
            Fourier coefficients bn (see Note)
        npts : int
            Number of points in the polygonal discretization

        Note
        ----
        We use the discrete Fourier expansion 
        ``R(phi) = a0/2 + sum(an*cos(n*phi)) + sum(bn*sin(n*phi))``
        The coefficients ``f_as`` are an array containing ``[a0, a1, ...]``,  
        while ``f_bs`` define ``[b1, b2, ...]``.

        Note
        ----
        This is a subclass of Poly because we discretize the shape into 
        a polygon and use that to compute the fourier transform for the 
        mode expansions. For intricate shapes, increase ``npts``
        to make the discretization smoother. 

        """
        self.x_cent = x_cent
        self.y_cent = y_cent
        self.npts = npts

        phis = bd.linspace(0, 2 * np.pi, npts + 1)

        R_phi = f_as[0] / 2 * bd.ones(phis.shape)
        for (n, an) in enumerate(f_as[1:]):
            R_phi = R_phi + an * bd.cos((n + 1) * phis)

        for (n, bn) in enumerate(f_bs):
            R_phi = R_phi + bn * bd.sin((n + 1) * phis)

        if np.any(R_phi < 0):
            raise ValueError("Coefficients of FourierShape should be such "
                             "that R(phi) is non-negative for all phi.")

        x_edges = R_phi * bd.cos(phis)
        y_edges = R_phi * bd.sin(phis)

        super().__init__(eps, x_edges, y_edges)