예제 #1
0
    def test_NPML(self):

        # NPML a number
        with self.assertRaises(AssertionError):
            Simulation(self.omega, self.eps_r, self.dl, 10, self.pol)

        # NPML too many elements
        with self.assertRaises(AssertionError):
            Simulation(self.omega, self.eps_r, self.dl, [10, 10, 10], self.pol)
예제 #2
0
    def test_1D(self):
        Nx = self.eps_r.shape[0]
        eps_1d = np.ones((Nx, ))

        S = Simulation(self.omega, eps_1d, self.dl, [10, 0], self.pol)

        S.src = np.zeros(S.eps_r.shape, dtype=np.complex64)
        S.src[Nx // 2, 0] = 1j
        (Hx, Hy, Ez) = S.solve_fields()
예제 #3
0
    def test_pol(self):

        # polarization not a string
        with self.assertRaises(AssertionError):
            Simulation(self.omega, self.eps_r, self.dl, self.NPML, 5)

        # polarization not the right string
        with self.assertRaises(AssertionError):
            Simulation(self.omega, self.eps_r, self.dl, self.NPML,
                       'WrongPolarization')
예제 #4
0
    def solve(self,
              epsilons: np.array,
              omega=OMEGA_1550,
              src_x=None,
              clip_buffers=False):

        total_length = self.device_length + 2 * self.buffer_length + 2 * self.npml
        start = self.npml + self.buffer_length
        end = start + self.device_length

        permittivities = np.ones(total_length, dtype=np.float64)

        # set permittivity and reflection zone
        permittivities[:start] = self.buffer_permittivity
        permittivities[start:end] = epsilons
        permittivities[end:] = self.buffer_permittivity

        if src_x is None:
            src_x = int(self.device_length / 2)

        sim = Simulation(omega,
                         permittivities,
                         self.dl, [self.npml, 0],
                         self.mode,
                         L0=self.L0,
                         use_dirichlet_bcs=self.use_dirichlet_bcs)
        sim.src[src_x + self.npml + self.buffer_length] = 1j

        if clip_buffers:
            clip0 = self.npml + self.buffer_length
            clip1 = -(self.npml + self.buffer_length)
        else:
            clip0 = None
            clip1 = None

        if self.mode == "Ez":
            Hx, Hy, Ez = sim.solve_fields()
            permittivities = permittivities[clip0:clip1]
            Hx = Hx[clip0:clip1]
            Hy = Hy[clip0:clip1]
            Ez = Ez[clip0:clip1]
            return permittivities, src_x, Hx, Hy, Ez

        elif self.mode == "Hz":
            Ex, Ey, Hz = sim.solve_fields()
            permittivities = permittivities[clip0:clip1]
            Ex = Ex[clip0:clip1]
            Ey = Ey[clip0:clip1]
            Hz = Hz[clip0:clip1]
            return permittivities, src_x, Ex, Ey, Hz

        else:
            raise ValueError("Polarization must be Ez or Hz!")
예제 #5
0
    def get_operators(self, omega=OMEGA_1550):

        total_length = self.device_length + 2 * self.buffer_length + 2 * self.npml

        perms = np.ones((total_length, total_length), dtype=np.float64)

        start = self.npml + self.buffer_length
        end = start + self.device_length

        # set permittivity and reflection zone
        perms[:, :start] = self.buffer_permittivity
        perms[:start, :] = self.buffer_permittivity
        perms[:, end:] = self.buffer_permittivity
        perms[end:, :] = self.buffer_permittivity

        sim = Simulation(omega,
                         perms,
                         self.dl, [self.npml, self.npml],
                         self.mode,
                         L0=self.L0,
                         use_dirichlet_bcs=self.use_dirichlet_bcs)

        Dyb, Dxb, Dxf, Dyf = unpack_derivs(sim.derivs)

        N = np.asarray(perms.shape)
        M = np.prod(N)

        vector_eps_z = EPSILON0 * self.L0 * perms.reshape((-1, ))
        T_eps_z = sp.spdiags(vector_eps_z, 0, M, M, format='csr')

        curl_curl = (Dxf @ Dxb + Dyf @ Dyb)

        other = omega**2 * MU0 * self.L0 * T_eps_z

        return curl_curl.todense(), other.todense()
예제 #6
0
    def test_freq(self):

        # negative frequency
        with self.assertRaises(AssertionError):
            Simulation(-self.omega, self.eps_r, self.dl, self.NPML, self.pol)
예제 #7
0
# geometric parameters for a 1 -> 2 port device
L = 6         # length of box (L0)
H = 4         # height of box (L0)
w = .3        # width of waveguides (L0)
d = H/1.5     # distance between waveguides (L0)
l = 4         # length of waveguide from PML to box (L0)
spc = 2       # space between box and PML (L0)

# define permittivity of three port system
eps_r, design_region = three_port(L, H, w, d, l, spc, dl, NPML, eps_m)
(Nx, Ny) = eps_r.shape
nx, ny = int(Nx/2), int(Ny/2)            # halfway grid points

# make a new simulation object
simulation = Simulation(omega, eps_r, dl, NPML, pol)

# set the input waveguide modal source
simulation.add_mode(neff=np.sqrt(eps_m), direction_normal='x', center=[NPML[0]+int(l/2/dl), ny], width=int(H/2/dl), scale=source_amp)
simulation.setup_modes()

# make a new simulation to get the modal profile of the top output port
top = Simulation(omega, eps_r, dl, NPML, 'Ez')
top.add_mode(neff=np.sqrt(eps_m), direction_normal='x', center=[-NPML[0]-int(l/2/dl), ny+int(d/2/dl)], width=int(H/2/dl))
top.setup_modes()
J_top = np.abs(top.src)

# make a new simulation to get the modal profile of the bottom output port
bot = Simulation(omega, eps_r, dl, NPML, 'Ez')
bot.add_mode(neff=np.sqrt(eps_m), direction_normal='x', center=[-NPML[0]-int(l/2/dl), ny-int(d/2/dl)], width=int(H/2/dl))
bot.setup_modes()
예제 #8
0
    def test_born_newton(self):
        """Tests whether born and newton methods get the same result"""

        n0 = 3.4
        omega = 2 * np.pi * 200e12
        dl = 0.01
        chi3 = 2.8E-18

        width = 1
        L = 5
        L_chi3 = 4

        width_voxels = int(width / dl)
        L_chi3_voxels = int(L_chi3 / dl)

        Nx = int(L / dl)
        Ny = int(3.5 * width / dl)

        eps_r = np.ones((Nx, Ny))
        eps_r[:,
              int(Ny / 2 -
                  width_voxels / 2):int(Ny / 2 +
                                        width_voxels / 2)] = np.square(n0)

        nl_region = np.zeros(eps_r.shape)
        nl_region[int(Nx / 2 - L_chi3_voxels / 2):int(Nx / 2 +
                                                      L_chi3_voxels / 2),
                  int(Ny / 2 - width_voxels / 2):int(Ny / 2 +
                                                     width_voxels / 2)] = 1

        simulation = Simulation(omega, eps_r, dl, [15, 15], 'Ez')
        simulation.add_mode(n0, 'x', [17, int(Ny / 2)], width_voxels * 3)
        simulation.setup_modes()
        simulation.add_nl(chi3,
                          nl_region,
                          eps_scale=True,
                          eps_max=np.max(eps_r))

        srcval_vec = np.logspace(1, 3, 3)
        pwr_vec = np.array([])
        T_vec = np.array([])
        for srcval in srcval_vec:
            simulation.setup_modes()
            simulation.src *= srcval

            # Newton
            simulation.solve_fields_nl(solver_nl='newton')
            E_newton = simulation.fields["Ez"]

            # Born
            simulation.solve_fields_nl(solver_nl='born')
            E_born = simulation.fields["Ez"]

            # More solvers (if any) should be added here with corresponding calls to assert_allclose() below

            assert_allclose(E_newton, E_born, rtol=1e-3)
예제 #9
0
# geometric parameters
L1 = 6         # length waveguides in design region (L0)
L2 = 6          # width of box (L0)
H1 = 6          # height waveguides in design region (L0)
H2 = 6          # height of box (L0)
w = .3          # width of waveguides (L0)
l = 3           # length of waveguide from PML to box (L0)
spc = 2         # space between box and PML (L0)

# define permittivity of three port system
eps_r, design_region = ortho_port(L1, L2, H1, H2, w, l, dl, NPML, eps_m)
(Nx, Ny) = eps_r.shape
nx, ny = int(Nx/2), int(Ny/2)            # halfway grid points

simulation = Simulation(omega,eps_r,dl,NPML,pol)

# set the modal source and probes
simulation = Simulation(omega, eps_r, dl, NPML, 'Ez')
simulation.add_mode(np.sqrt(eps_m), 'x', [NPML[0]+int(l/2/dl), ny], int(H1/2/dl), scale=source_amp)
simulation.setup_modes()

# left modal profile
right = Simulation(omega, eps_r, dl, NPML, 'Ez')
right.add_mode(np.sqrt(eps_m), 'x', [-NPML[0]-int(l/2/dl), ny], int(H1/2/dl))
right.setup_modes()
J_right = np.abs(right.src)

# top modal profile
top = Simulation(omega, eps_r, dl, NPML, 'Ez')
top.add_mode(np.sqrt(eps_m), 'y', [nx, -NPML[1]-int(l/2/dl)], int(L1/2/dl))
예제 #10
0
if plot_all:
    print('-> solving FDFD for continuous epsilon')
    F = fdfd(omega0, dl, eps_total, NPML)
    Hx, Hy, Ez = F.solve(source)
    plt.imshow(np.abs(imarr(Ez)), cmap='magma')
    plt.title('|Ez| for continuous permitivity')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.colorbar()
    plt.show()
""" DEFINE MODAL SOURCE / PROBE """

print('-> setting up modal source')

# make an angler simulation with the starting permittivity, to compute the modal source
sim = Simulation(omega0, eps_base, dl, [npml, npml], pol='Ez', L0=1)
center_y = npml + int((spc + subs + h1 / 2) / dl)
sim.add_mode(neff_hole,
             'x',
             center=[npml + int(spc / dl), center_y],
             width=int(5 * h1 / dl),
             scale=1,
             order=1)
sim.setup_modes()

# get the wg mode profile as an array
wg_mode = np.flipud(np.abs(sim.src.copy())).reshape((Nx, Ny, 1))

# compute the power in the waveguide mode for normalization
wg_mode_p = np.sum(np.square(np.abs(wg_mode)))
예제 #11
0
    def setUp(self):
        # create a simulation to test just like in notebook

        lambda0 = 2e-6  # free space wavelength (m)
        c0 = 3e8  # speed of light in vacuum (m/s)
        omega = 2 * np.pi * c0 / lambda0  # angular frequency (2pi/s)
        dl = 1.1e-1  # grid size (L0)
        NPML = [15, 15]  # number of pml grid points on x and y borders
        pol = 'Ez'  # polarization (either 'Hz' or 'Ez')
        source_amp = 100  # amplitude of modal source (A/L0^2?)

        # material constants
        n_index = 2.44  # refractive index
        eps_m = n_index**2  # relative permittivity
        max_ind_shift = 5.8e-2  # maximum allowed nonlinear index shift

        # geometric parameters
        L = 4  # length of box (L0)
        H = 4  # height of box (L0)
        w = .2  # width of waveguides (L0)
        d = H / 2.44  # distance between waveguides (L0)
        l = 3  # length of waveguide from PML to box (L0)
        spc = 2  # space between box and PML (L0)

        # define permittivity of three port system
        (eps_r, design_region) = three_port(L,
                                            H,
                                            w,
                                            d,
                                            dl,
                                            l,
                                            spc,
                                            NPML,
                                            eps_start=eps_m)
        (Nx, Ny) = eps_r.shape
        nx, ny = int(Nx / 2), int(Ny / 2)  # halfway grid points

        # set the modal source and probes
        self.simulation = Simulation(omega, eps_r, dl, NPML, 'Ez')
        self.simulation.add_mode(np.sqrt(eps_m),
                                 'x', [NPML[0] + int(l / 2 / dl), ny],
                                 int(H / 2 / dl),
                                 scale=source_amp)
        self.simulation.setup_modes()
        self.simulation.init_design_region(design_region, eps_m)

        # top modal profile
        top = Simulation(omega, eps_r, dl, NPML, 'Ez')
        top.add_mode(np.sqrt(eps_m), 'x',
                     [-NPML[0] - int(l / 2 / dl), ny + int(d / 2 / dl)],
                     int(H / 2 / dl))
        top.setup_modes()
        J_top = np.abs(top.src)

        # bottom modal profile
        bot = Simulation(omega, eps_r, dl, NPML, 'Ez')
        bot.add_mode(np.sqrt(eps_m), 'x',
                     [-NPML[0] - int(l / 2 / dl), ny - int(d / 2 / dl)],
                     int(d / dl))
        bot.setup_modes()
        J_bot = np.abs(bot.src)

        # define linear and nonlinear parts of objective function + the total objective function form
        J = lambda e, e_nl: npa.sum(npa.square(npa.abs(e)) * J_top) + npa.sum(
            npa.square(npa.abs(e_nl)) * J_bot)
        import autograd.numpy as npa

        def J(e, e_nl):
            linear_top = 1 * npa.sum(npa.square(npa.abs(e)) * J_top)
            linear_bot = -1 * npa.sum(npa.square(npa.abs(e)) * J_bot)
            nonlinear_top = -1 * npa.sum(npa.square(npa.abs(e_nl)) * J_top)
            nonlinear_bot = 1 * npa.sum(npa.square(npa.abs(e_nl)) * J_bot)
            objfn = linear_top + nonlinear_top + nonlinear_bot + linear_top
            return objfn

        self.design_region = design_region
        self.optimization = Optimization(J=J,
                                         simulation=self.simulation,
                                         design_region=self.design_region,
                                         eps_m=eps_m)