예제 #1
0
def adjoint_linear_Hz(simulation, b_aj, averaging=False, solver=DEFAULT_SOLVER, matrix_format=DEFAULT_MATRIX_FORMAT):
    # Compute the adjoint field for a linear problem
    # Note: the correct definition requires simulating with the transpose matrix A.T
    EPSILON_0_ = EPSILON_0*simulation.L0
    MU_0_ = MU_0*simulation.L0
    omega = simulation.omega

    (Nx, Ny) = (simulation.Nx, simulation.Ny)
    M = Nx*Ny
    A = simulation.A

    hz = solver_direct(A.T, b_aj, solver=solver)
    (Dyb, Dxb, Dxf, Dyf) = unpack_derivs(simulation.derivs) 
    (Dyb_T, Dxb_T, Dxf_T, Dyf_T) = (Dyb.T, Dxb.T, Dxf.T, Dyf.T)

    if averaging:
        vector_eps_x = grid_average(EPSILON_0_*simulation.eps_r, 'x').reshape((-1,))
        vector_eps_y = grid_average(EPSILON_0_*simulation.eps_r, 'y').reshape((-1,))
    else:
        vector_eps_x = EPSILON_0_*simulation.eps_r.reshape((-1,))
        vector_eps_y = EPSILON_0_*simulation.eps_r.reshape((-1,))

    T_eps_x_inv = sp.spdiags(1/vector_eps_x, 0, M, M, format=matrix_format)
    T_eps_y_inv = sp.spdiags(1/vector_eps_y, 0, M, M, format=matrix_format)
    
    # Note: to get the correct gradient in the end, we must use Dxf, Dyf here   
    ex =  1/1j/omega * T_eps_y_inv.dot(Dyf_T).dot(hz).T
    ey = -1/1j/omega * T_eps_x_inv.dot(Dxf_T).dot(hz).T

    Ex = ex.reshape((Nx, Ny))
    Ey = ey.reshape((Nx, Ny))

    return (Ex, Ey)
예제 #2
0
    def flux_probe(self, direction_normal, center, width, nl=False):
        # computes the total flux across the plane (line in 2D) defined by direction_normal, center, width

        # first extract the slice of the permittivity
        if direction_normal == "x":
            inds_x = [center[0], center[0]+1]
            inds_y = [int(center[1]-width/2), int(center[1]+width/2)]
        elif direction_normal == "y":
            inds_x = [int(center[0]-width/2), int(center[0]+width/2)]
            inds_y = [center[1], center[1]+1]
        else:
            raise ValueError("The value of direction_normal is neither x nor y!")

        if self.pol == 'Ez':

            if nl:
                field_val_Ez = self.fields_nl['Ez']
                field_val_Hy = self.fields_nl['Hy']
                field_val_Hx = self.fields_nl['Hx']
            else:
                field_val_Ez = self.fields['Ez']
                field_val_Hy = self.fields['Hy']
                field_val_Hx = self.fields['Hx']

            Ez_x = grid_average(field_val_Ez[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'x')[:-1,:-1]
            Ez_y = grid_average(field_val_Ez[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'y')[:-1,:-1]
            # NOTE: Last part drops the extra rows/cols used for grid_average

            if direction_normal == "x":
                Sx = -1/2*np.real(Ez_x*np.conj(field_val_Hy[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]]))
                return self.dl*np.sum(Sx)
            elif direction_normal == "y":
                Sy = 1/2*np.real(Ez_y*np.conj(field_val_Hx[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]]))
                return self.dl*np.sum(Sy)

        elif self.pol == 'Hz':

            if nl:
                field_val_Hz = self.fields_nl['Hz']
                field_val_Ey = self.fields_nl['Ey']
                field_val_Ex = self.fields_nl['Ex']
            else:
                field_val_Hz = self.fields['Hz']
                field_val_Ey = self.fields['Ey']
                field_val_Ex = self.fields['Ex']

            Hz_x = grid_average(field_val_Hz[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'x')[:-1, :-1]
            Hz_y = grid_average(field_val_Hz[inds_x[0]:inds_x[1]+1, inds_y[0]:inds_y[1]+1], 'y')[:-1, :-1]
            # NOTE: Last part drops the extra rows/cols used for grid_average

            if direction_normal == "x":
                Sx = 1/2*np.real(field_val_Ey[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]]*np.conj(Hz_x))
                return self.dl*np.sum(Sx)
            elif direction_normal == "y":
                Sy = -1/2*np.real(field_val_Ex[inds_x[0]:inds_x[1], inds_y[0]:inds_y[1]]*np.conj(Hz_y))
                return self.dl*np.sum(Sy)
예제 #3
0
    def solve_fields(self,
                     include_nl=False,
                     timing=False,
                     averaging=False,
                     matrix_format=DEFAULT_MATRIX_FORMAT):
        # performs direct solve for A given source

        EPSILON_0_ = EPSILON_0 * self.L0
        MU_0_ = MU_0 * self.L0

        if include_nl == False:
            eps_tot = self.eps_r
            X = solver_direct(self.A,
                              self.src * 1j * self.omega,
                              timing=timing)
        else:
            eps_tot = self.eps_r + self.eps_nl
            X = solver_direct(self.A + self.Anl,
                              self.src * 1j * self.omega,
                              timing=timing)

        (Nx, Ny) = self.src.shape
        M = Nx * Ny
        (Dyb, Dxb, Dxf, Dyf) = unpack_derivs(self.derivs)

        if self.pol == 'Hz':
            if averaging:
                eps_x = grid_average(EPSILON_0_ * (eps_tot), 'x')
                vector_eps_x = eps_x.reshape((-1, ))
                eps_y = grid_average(EPSILON_0_ * (eps_tot), 'y')
                vector_eps_y = eps_y.reshape((-1, ))
            else:
                vector_eps_x = EPSILON_0_ * (eps_tot).reshape((-1, ))
                vector_eps_y = EPSILON_0_ * (eps_tot).reshape((-1, ))

            T_eps_x_inv = sp.spdiags(1 / vector_eps_x,
                                     0,
                                     M,
                                     M,
                                     format=matrix_format)
            T_eps_y_inv = sp.spdiags(1 / vector_eps_y,
                                     0,
                                     M,
                                     M,
                                     format=matrix_format)

            ex = 1 / 1j / self.omega * T_eps_y_inv.dot(Dyb).dot(X)
            ey = -1 / 1j / self.omega * T_eps_x_inv.dot(Dxb).dot(X)

            Ex = ex.reshape((Nx, Ny))
            Ey = ey.reshape((Nx, Ny))
            Hz = X.reshape((Nx, Ny))

            if include_nl == False:
                self.fields['Ex'] = Ex
                self.fields['Ey'] = Ey
                self.fields['Hz'] = Hz

            return (Ex, Ey, Hz)

        elif self.pol == 'Ez':
            hx = -1 / 1j / self.omega / MU_0_ * Dyb.dot(X)
            hy = 1 / 1j / self.omega / MU_0_ * Dxb.dot(X)

            Hx = hx.reshape((Nx, Ny))
            Hy = hy.reshape((Nx, Ny))
            Ez = X.reshape((Nx, Ny))

            if include_nl == False:
                self.fields['Hx'] = Hx
                self.fields['Hy'] = Hy
                self.fields['Ez'] = Ez

            return (Hx, Hy, Ez)

        else:
            raise ValueError('Invalid polarization: {}'.format(str(self.pol)))
예제 #4
0
def grad_linear_Ey(optimization, dJ, Hz, args, averaging=False):

    EPSILON_0_ = EPSILON_0 * optimization.simulation.L0
    MU_0_ = MU_0 * optimization.simulation.L0
    omega = optimization.simulation.omega
    Dxb = optimization.simulation.derivs['Dxf']
    Dyb = optimization.simulation.derivs['Dyf']

    eps_tot = optimization.simulation.eps_r
    M = eps_tot.size

    if averaging:
        eps_x = grid_average(EPSILON_0_ * (eps_tot), 'x')
        vector_eps_x = eps_x.reshape((-1, ))
        eps_y = grid_average(EPSILON_0_ * (eps_tot), 'y')
        vector_eps_y = eps_y.reshape((-1, ))
    else:
        vector_eps_x = EPSILON_0_ * (eps_tot).reshape((-1, ))
        vector_eps_y = EPSILON_0_ * (eps_tot).reshape((-1, ))

    T_eps_x_inv = sp.spdiags(1 / vector_eps_x,
                             0,
                             M,
                             M,
                             format=DEFAULT_MATRIX_FORMAT)
    T_eps_y_inv = sp.spdiags(1 / vector_eps_y,
                             0,
                             M,
                             M,
                             format=DEFAULT_MATRIX_FORMAT)

    # get fields
    Hz_vec = np.reshape(Hz, (-1, ))
    Ex_vec = 1 / 1j / omega * T_eps_y_inv.dot(Dyb).dot(Hz_vec)
    Ey_vec = -1 / 1j / omega * T_eps_x_inv.dot(Dxb).dot(Hz_vec)

    partial = -dJ(*args)
    partial_vec = partial.reshape((-1, ))

    b_aj_vec = -1 / 1j / omega * T_eps_x_inv.dot(Dxb.T).dot(partial_vec)
    b_aj = b_aj_vec.reshape(Hz.shape)

    (Ex_aj, Ey_aj) = adjoint_linear_Hz(optimization.simulation,
                                       b_aj,
                                       averaging=averaging)
    Ex_aj_vec = np.reshape(Ex_aj, (-1, )).T
    Ey_aj_vec = np.reshape(Ey_aj, (-1, )).T

    # set up filtering bits
    rho = optimization.simulation.rho
    rho_t = rho2rhot(rho, optimization.W)
    rho_b = rhot2rhob(rho_t, eta=optimization.eta, beta=optimization.beta)
    eps_mat = (optimization.eps_m - 1)

    filt_mat = drhot_drho(optimization.W)
    proj_mat = drhob_drhot(rho_t, eta=optimization.eta, beta=optimization.beta)

    if averaging:

        design_region_x = grid_average(optimization.design_region, 'x')
        dAdeps_x = design_region_x * omega**2 * EPSILON_0_
        design_region_y = grid_average(optimization.design_region, 'y')
        dAdeps_y = design_region_y * omega**2 * EPSILON_0_
        dAdeps_vec_x = np.reshape(dAdeps_x, (-1, ))
        dAdeps_vec_y = np.reshape(dAdeps_y, (-1, ))
        dfdrho_x = eps_mat * filt_mat.multiply(
            Ex_vec * proj_mat * dAdeps_vec_x)
        dfdrho_y = eps_mat * filt_mat.multiply(
            Ey_vec * proj_mat * dAdeps_vec_x)
        sensitivity_vec = dfdrho_x.dot(Ex_aj_vec) + dfdrho_y.dot(Ey_aj_vec)

    else:

        dAdeps = optimization.design_region * omega**2 * EPSILON_0_  # Note: physical constants go here if need be!
        dAdeps_vec = np.reshape(dAdeps, (-1, ))
        dfdrho_x = eps_mat * filt_mat.multiply(Ex_vec * proj_mat * dAdeps_vec)
        dfdrho_y = eps_mat * filt_mat.multiply(Ey_vec * proj_mat * dAdeps_vec)
        sensitivity_vec = dfdrho_x.dot(Ex_aj_vec) + dfdrho_y.dot(Ey_aj_vec)

    return 1 * np.real(np.reshape(sensitivity_vec, rho.shape))