示例#1
0
    def add_eigenmode_source(self,
                             src,
                             port,
                             eig_band=1,
                             eig_parity=mp.NO_PARITY,
                             z=None,
                             height=None):
        """
        Adds an eigenmode source at the given port.

        :param src: Meep-Source (e.g. GaussianSource or ContinuousSource)
        :param port: Port at which the source is added
        :param eig_band: Number of the excited mode. The mode with the highest eigenvalue has the number 1
        :param eig_parity: Parity of the eigenmodes
        :param z: Z-position of the source
        :param height: Height of the area for calculating the eigenmode
        :return: Added Meep-Source
        """

        size = [
            0, port.total_width * 2
        ] if port.angle % np.pi < np.pi / 4 else [port.total_width * 2, 0]
        source = mp.EigenModeSource(src,
                                    mp.Vector3(*port.origin, z),
                                    size=mp.Vector3(*size, height),
                                    eig_band=eig_band,
                                    eig_parity=eig_parity)
        self.sources.append(source)
        return source
示例#2
0
    def setUp(self):

        cell = mp.Vector3(16, 8)

        geometry = [
            mp.Block(center=mp.Vector3(),
                     size=mp.Vector3(mp.inf, 1, mp.inf),
                     material=mp.Medium(epsilon=12)),
            mp.Block(center=mp.Vector3(y=0.3),
                     size=mp.Vector3(mp.inf, 0.1, mp.inf),
                     material=mp.Medium())
        ]

        sources = [
            mp.EigenModeSource(src=mp.ContinuousSource(0.15),
                               size=mp.Vector3(y=6),
                               center=mp.Vector3(x=-5),
                               component=mp.Dielectric,
                               eig_parity=mp.ODD_Z)
        ]

        pml_layers = [mp.PML(1.0)]

        self.sim = mp.Simulation(cell_size=cell,
                                 geometry=geometry,
                                 sources=sources,
                                 boundary_layers=pml_layers,
                                 force_complex_fields=True,
                                 resolution=10)
    def create_waveguide_source(self,
                                wavelength,
                                pos,
                                width,
                                direction='+x',
                                comp='y'):

        # parity
        parity = mp.ODD_Z if comp == 'z' else mp.EVEN_Z

        # size
        size = mp.Vector3(y=width) if 'x' in direction else mp.Vector3(x=width)

        # kpoints
        angles = {'+x': 0, '+y': 90, '-x': 180, '-y': 270}
        if direction in angles:
            angle = np.radians(angles[direction])
            direction = mp.Vector3(0.4).rotate(mp.Vector3(z=1), angle)

        s = mp.EigenModeSource(src=mp.ContinuousSource(wavelength=wavelength),
                               center=mp.Vector3(*pos),
                               size=size,
                               direction=mp.NO_DIRECTION,
                               eig_kpoint=direction,
                               eig_band=1,
                               eig_parity=parity,
                               eig_match_freq=True,
                               component=mp.ALL_COMPONENTS)
        self.sources.append(s)
示例#4
0
    def create_sim(self, beta_vector, vacuum=False):

        args=self.args
        sx=self.cell_size.x

        wvg=mp.Block(center=origin, material=mp.Medium(epsilon=args.eps_wvg),
                     size=mp.Vector3(self.cell_size.x,args.w_wvg))
        disc=mp.Cylinder(center=self.design_center, radius=args.r_disc,
                         epsilon_func=ParameterizedDielectric(self.design_center,
                                                              self.basis,
                                                              beta_vector))

        geometry=[wvg] if vacuum else [wvg, disc]

        envelope = mp.GaussianSource(args.fcen,fwidth=args.df)
        amp=1.0
        if callable(getattr(envelope, "fourier_transform", None)):
            amp /= envelope.fourier_transform(args.fcen)
        sources=[mp.EigenModeSource(src=envelope,
                                    center=self.source_center,
                                    size=self.source_size,
                                    eig_band=self.args.source_mode,
                                    amplitude=amp
                                   )
                ]

        sim=mp.Simulation(resolution=args.res, cell_size=self.cell_size,
                          boundary_layers=[mp.PML(args.dpml)], geometry=geometry,
                          sources=sources)

        if args.complex_fields:
            sim.force_complex_fields=True

        return sim
示例#5
0
    def test_eigsrc_kz(self, kz_2d):
        resolution = 30  # pixels/um

        cell_size = mp.Vector3(14, 14)

        pml_layers = [mp.PML(thickness=2)]

        geometry = [
            mp.Block(center=mp.Vector3(),
                     size=mp.Vector3(mp.inf, 1, mp.inf),
                     material=mp.Medium(epsilon=12))
        ]

        fsrc = 0.3  # frequency of eigenmode or constant-amplitude source
        bnum = 1  # band number of eigenmode
        kz = 0.2  # fixed out-of-plane wavevector component

        sources = [
            mp.EigenModeSource(src=mp.GaussianSource(fsrc, fwidth=0.2 * fsrc),
                               center=mp.Vector3(),
                               size=mp.Vector3(y=14),
                               eig_band=bnum,
                               eig_parity=mp.EVEN_Y,
                               eig_match_freq=True)
        ]

        sim = mp.Simulation(cell_size=cell_size,
                            resolution=resolution,
                            boundary_layers=pml_layers,
                            sources=sources,
                            geometry=geometry,
                            symmetries=[mp.Mirror(mp.Y)],
                            k_point=mp.Vector3(z=kz),
                            kz_2d=kz_2d)

        tran = sim.add_flux(
            fsrc, 0, 1,
            mp.FluxRegion(center=mp.Vector3(x=5), size=mp.Vector3(y=14)))

        sim.run(until_after_sources=50)

        res = sim.get_eigenmode_coefficients(tran, [1, 2],
                                             eig_parity=mp.EVEN_Y)

        total_flux = mp.get_fluxes(tran)[0]
        mode1_flux = abs(res.alpha[0, 0, 0])**2
        mode2_flux = abs(res.alpha[1, 0, 0])**2

        mode1_frac = 0.99
        self.assertGreater(mode1_flux / total_flux, mode1_frac)
        self.assertLess(mode2_flux / total_flux, 1 - mode1_frac)

        d = 3.5
        ez1 = sim.get_field_point(mp.Ez, mp.Vector3(2.3, -5.7, 4.8))
        ez2 = sim.get_field_point(mp.Ez, mp.Vector3(2.3, -5.7, 4.8 + d))
        ratio_ez = ez2 / ez1
        phase_diff = cmath.exp(1j * 2 * cmath.pi * kz * d)
        self.assertAlmostEqual(ratio_ez.real, phase_diff.real, places=10)
        self.assertAlmostEqual(ratio_ez.imag, phase_diff.imag, places=10)
示例#6
0
    def test_waveguide_flux(self):
        cell_size = mp.Vector3(10, 10, 0)

        pml_layers = [mp.PML(thickness=2.0)]

        rot_angles = range(
            0, 60, 20)  # rotation angle of waveguide, CCW around z-axis

        fluxes = []
        for t in rot_angles:
            rot_angle = math.radians(t)
            sources = [
                mp.EigenModeSource(src=mp.GaussianSource(1.0, fwidth=0.1),
                                   size=mp.Vector3(y=10),
                                   center=mp.Vector3(x=-3),
                                   direction=mp.NO_DIRECTION,
                                   eig_kpoint=mp.Vector3(
                                       math.cos(rot_angle),
                                       math.sin(rot_angle), 0),
                                   eig_band=1,
                                   eig_parity=mp.ODD_Z,
                                   eig_match_freq=True)
            ]

            geometry = [
                mp.Block(center=mp.Vector3(),
                         size=mp.Vector3(mp.inf, 1, mp.inf),
                         e1=mp.Vector3(1, 0, 0).rotate(mp.Vector3(0, 0, 1),
                                                       rot_angle),
                         e2=mp.Vector3(0, 1, 0).rotate(mp.Vector3(0, 0, 1),
                                                       rot_angle),
                         material=mp.Medium(index=1.5))
            ]

            sim = mp.Simulation(cell_size=cell_size,
                                resolution=50,
                                boundary_layers=pml_layers,
                                sources=sources,
                                geometry=geometry)

            tran = sim.add_flux(
                1.0, 0, 1,
                mp.FluxRegion(center=mp.Vector3(x=3), size=mp.Vector3(y=10)))

            sim.run(until_after_sources=100)

            fluxes.append(mp.get_fluxes(tran)[0])
            print("flux:, {:.2f}, {:.6f}".format(t, fluxes[-1]))

        self.assertAlmostEqual(fluxes[0], fluxes[1], places=0)
        self.assertAlmostEqual(fluxes[1], fluxes[2], places=0)

        # self.assertAlmostEqual(fluxes[0], fluxes[2], places=0)
        # sadly the above line requires a workaround due to the
        # following annoying numerical accident:
        # AssertionError: 100.33815231783535 != 99.81145343586365 within 0 places
        f0, f2 = fluxes[0], fluxes[2]
        self.assertLess(abs(f0 - f2), 0.5 * max(abs(f0), abs(f2)))
示例#7
0
    def place_adjoint_source(self,dJ,dt):
        '''Places an equivalent eigenmode monitor facing the opposite direction. Calculates the 
        correct scaling/time profile.

        dJ ........ the user needs to pass the dJ/dMonitor evaluation
        dt ........ the timestep size from sim.fields.dt of the forward sim
        '''
        dJ = np.atleast_1d(dJ)
        # determine starting kpoint for reverse mode eigenmode source
        direction_scalar = 1 if self.forward else -1
        if self.kpoint_func is None:
            if self.normal_direction == 0:
                k0 = direction_scalar * mp.Vector3(x=1)
            elif self.normal_direction == 1:
                k0 = direction_scalar * mp.Vector3(y=1)
            elif self.normal_direction == 2:
                k0 == direction_scalar * mp.Vector3(z=1)
        else:
            k0 = direction_scalar * self.kpoint_func(self.time_src.frequency,1)
        
        # -------------------------------------- #
        # Get scaling factor 
        # -------------------------------------- #
        # leverage linearity and combine source for multiple frequencies
        if dJ.ndim == 2:
            dJ = np.sum(dJ,axis=1)
        
        # Determine the correct resolution scale factor
        if self.sim.cell_size.y == 0:
            dV = 1/self.sim.resolution
        elif self.sim.cell_size.z == 0:
            dV = 1/self.sim.resolution * 1/self.sim.resolution
        else:
            dV = 1/self.sim.resolution * 1/self.sim.resolution * 1/self.sim.resolution
        da_dE = 0.5*(dV * self.cscale)
        scale = da_dE * dJ * 1j * 2 * np.pi * self.frequencies / np.array([self.time_src.fourier_transform(f) for f in self.frequencies]) # final scale factor
        if self.frequencies.size == 1:
            # Single frequency simulations. We need to drive it with a time profile.
            src = self.time_src
            amp = scale
        else:
            # TODO: In theory we should be able drive the source without normalizing out the time profile.
            # But for some reason, there is a frequency dependent scaling discrepency. It works now for 
            # multiple monitors and multiple sources, but we should figure out why this is.
            src = FilteredSource(self.time_src.frequency,self.frequencies,scale,dt,self.time_src) # generate source from broadband response
            amp = 1
        # generate source object
        self.source = mp.EigenModeSource(src,
                    eig_band=self.mode,
                    direction=mp.NO_DIRECTION,
                    eig_kpoint=k0,
                    amplitude=amp,
                    eig_match_freq=True,
                    size=self.volume.size,
                    center=self.volume.center,
                    **self.EigenMode_kwargs)
        
        return self.source
示例#8
0
文件: objective.py 项目: wwwpi/meep
    def place_adjoint_source(self, dJ):
        '''Places an equivalent eigenmode monitor facing the opposite direction. Calculates the
        correct scaling/time profile.
        dJ ........ the user needs to pass the dJ/dMonitor evaluation
        '''
        dJ = np.atleast_1d(dJ)
        dt = self.sim.fields.dt  # the timestep size from sim.fields.dt of the forward sim
        # determine starting kpoint for reverse mode eigenmode source
        direction_scalar = 1 if self.forward else -1
        if self.kpoint_func is None:
            if self.normal_direction == 0:
                k0 = direction_scalar * mp.Vector3(x=1)
            elif self.normal_direction == 1:
                k0 = direction_scalar * mp.Vector3(y=1)
            elif self.normal_direction == 2:
                k0 == direction_scalar * mp.Vector3(z=1)
        else:
            k0 = direction_scalar * self.kpoint_func(self.time_src.frequency,
                                                     1)
        if dJ.ndim == 2:
            dJ = np.sum(dJ, axis=1)
        da_dE = 0.5 * self.cscale  # scalar popping out of derivative

        scale = adj_src_scale(self, dt)

        if self.frequencies.size == 1:
            # Single frequency simulations. We need to drive it with a time profile.
            amp = da_dE * dJ * scale  # final scale factor
            src = self.time_src
        else:
            # multi frequency simulations
            scale = da_dE * dJ * scale
            src = FilteredSource(self.time_src.frequency, self.frequencies,
                                 scale,
                                 dt)  # generate source from broadband response
            amp = 1

        # generate source object
        self.source = [
            mp.EigenModeSource(src,
                               eig_band=self.mode,
                               direction=mp.NO_DIRECTION,
                               eig_kpoint=k0,
                               amplitude=amp,
                               eig_match_freq=True,
                               size=self.volume.size,
                               center=self.volume.center,
                               **self.EigenMode_kwargs)
        ]

        return self.source
示例#9
0
    def test_custom_em_source(self):
        resolution = 20

        dpml = 2
        pml_layers = [mp.PML(thickness=dpml)]

        sx = 40
        sy = 12
        cell_size = mp.Vector3(sx + 2 * dpml, sy)

        v0 = 0.15  # pulse center frequency
        a = 0.2 * v0  # Gaussian envelope half-width
        b = -0.1  # linear chirp rate (positive: up-chirp, negative: down-chirp)
        t0 = 15  # peak time

        chirp = lambda t: np.exp(1j * 2 * np.pi * v0 *
                                 (t - t0)) * np.exp(-a * (t - t0)**2 + 1j * b *
                                                    (t - t0)**2)

        geometry = [
            mp.Block(center=mp.Vector3(0, 0, 0),
                     size=mp.Vector3(mp.inf, 1, mp.inf),
                     material=mp.Medium(epsilon=12))
        ]

        kx = 0.4  # initial guess for wavevector in x-direction of eigenmode
        kpoint = mp.Vector3(kx)
        bnum = 1

        sources = [
            mp.EigenModeSource(src=mp.CustomSource(src_func=chirp,
                                                   center_frequency=v0),
                               center=mp.Vector3(-0.5 * sx + dpml + 1),
                               size=mp.Vector3(y=sy),
                               eig_kpoint=kpoint,
                               eig_band=bnum,
                               eig_parity=mp.EVEN_Y + mp.ODD_Z,
                               eig_match_freq=True)
        ]

        sim = mp.Simulation(cell_size=cell_size,
                            boundary_layers=pml_layers,
                            resolution=resolution,
                            k_point=mp.Vector3(),
                            sources=sources,
                            geometry=geometry,
                            symmetries=[mp.Mirror(mp.Y)])

        t = np.linspace(0, 50, 1000)
        sim.run(until=t0 + 50)
示例#10
0
    def create_sim(self, beta_vector, vacuum=False):

        args = self.args
        sx = self.cell_size.x

        x_in = -0.5 * (args.l_design + args.l_stub)
        x_out = +0.5 * (args.l_design + args.l_stub)
        y_out1 = +0.25 * args.h_design
        y_out2 = -0.25 * args.h_design

        wvg_in = mp.Block(center=mp.Vector3(x_in, 0.0),
                          size=mp.Vector3(args.l_stub, args.w_in),
                          material=mp.Medium(epsilon=args.eps_in))
        wvg_out1 = mp.Block(center=mp.Vector3(x_out, y_out1),
                            size=mp.Vector3(args.l_stub, args.w_out1),
                            material=mp.Medium(epsilon=args.eps_out1))
        wvg_out2 = mp.Block(center=mp.Vector3(x_out, y_out2),
                            size=mp.Vector3(args.l_stub, args.w_out2),
                            material=mp.Medium(epsilon=args.eps_out2))
        design = mp.Block(center=origin,
                          size=mp.Vector3(args.l_design, args.h_design),
                          epsilon_func=ParameterizedDielectric(
                              self.design_center, self.basis, beta_vector))

        geometry = [wvg_in, wvg_out1, wvg_out2, design]

        envelope = mp.GaussianSource(args.fcen, fwidth=args.df)
        amp = 1.0
        if callable(getattr(envelope, "fourier_transform", None)):
            amp /= envelope.fourier_transform(args.fcen)
        sources = [
            mp.EigenModeSource(src=envelope,
                               center=self.source_center,
                               size=self.source_size,
                               eig_band=self.args.source_mode,
                               amplitude=amp)
        ]

        sim = mp.Simulation(resolution=args.res,
                            cell_size=self.cell_size,
                            boundary_layers=[mp.PML(args.dpml)],
                            geometry=geometry,
                            sources=sources)

        if args.complex_fields:
            sim.force_complex_fields = True

        return sim
示例#11
0
    def test_dft_energy(self):
        resolution = 20
        cell = mp.Vector3(10, 5)
        geom = [
            mp.Block(size=mp.Vector3(mp.inf, 1, mp.inf),
                     material=mp.Medium(epsilon=12))
        ]
        pml = [mp.PML(1)]
        fsrc = 0.15
        sources = [
            mp.EigenModeSource(src=mp.GaussianSource(frequency=fsrc,
                                                     fwidth=0.2 * fsrc),
                               center=mp.Vector3(-3),
                               size=mp.Vector3(y=5),
                               eig_band=1,
                               eig_parity=mp.ODD_Z + mp.EVEN_Y,
                               eig_match_freq=True)
        ]

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell,
                            geometry=geom,
                            boundary_layers=pml,
                            sources=sources,
                            symmetries=[mp.Mirror(direction=mp.Y)])

        flux = sim.add_flux(
            fsrc, 0, 1,
            mp.FluxRegion(center=mp.Vector3(3), size=mp.Vector3(y=5)))
        energy = sim.add_energy(
            fsrc, 0, 1,
            mp.EnergyRegion(center=mp.Vector3(3), size=mp.Vector3(y=5)))
        sim.run(until_after_sources=100)

        res = sim.get_eigenmode_coefficients(flux, [1],
                                             eig_parity=mp.ODD_Z + mp.EVEN_Y)
        mode_vg = res.vgrp[0]
        poynting_flux = mp.get_fluxes(flux)[0]
        e_energy = mp.get_electric_energy(energy)[0]
        ratio_vg = (0.5 * poynting_flux) / e_energy
        m_energy = mp.get_magnetic_energy(energy)[0]
        t_energy = mp.get_total_energy(energy)[0]

        self.assertAlmostEqual(m_energy + e_energy, t_energy)
        self.assertAlmostEqual(ratio_vg, mode_vg, places=3)
示例#12
0
    def place_adjoint_source(self, dJ):
        dJ = np.atleast_1d(dJ)
        if dJ.ndim == 2:
            dJ = np.sum(dJ, axis=1)
        time_src = self._create_time_profile()
        da_dE = 0.5 * self._cscale
        scale = self._adj_src_scale()

        if self.kpoint_func:
            eig_kpoint = -1 * self.kpoint_func(time_src.frequency, self.mode)
        else:
            center_frequency = 0.5 * (np.min(self.frequencies) +
                                      np.max(self.frequencies))
            direction = mp.Vector3(
                *(np.eye(3)[self._monitor.normal_direction] *
                  np.abs(center_frequency)))
            eig_kpoint = -1 * direction if self.forward else direction

        if self._frequencies.size == 1:
            amp = da_dE * dJ * scale
            src = time_src
        else:
            scale = da_dE * dJ * scale
            src = FilteredSource(
                time_src.frequency,
                self._frequencies,
                scale,
                self.sim.fields.dt,
            )
            amp = 1
        source = mp.EigenModeSource(
            src,
            eig_band=self.mode,
            direction=mp.NO_DIRECTION,
            eig_kpoint=eig_kpoint,
            amplitude=amp,
            eig_match_freq=True,
            size=self.volume.size,
            center=self.volume.center,
            **self.eigenmode_kwargs,
        )
        return [source]
示例#13
0
def bragg_source(geo=None, **kwargs):
    geo = kwargs_to_geo(geo, **kwargs)
    # sources = []
    # sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df),
    #                  component=mp.Ey,
    #                  center=mp.Vector3(-monitor_x(geo)-.5, 0),
    #                  size=mp.Vector3(0, geo.sm_width, geo.thickness))]
    sources = [
        mp.EigenModeSource(
            mp.GaussianSource(fcen, fwidth=df),
            eig_band=2,
            direction=mp.X,
            # eig_parity=mp.ODD_Y,
            component=mp.Ey,
            center=mp.Vector3(-monitor_x(geo) - .5, 0),
            size=mp.Vector3(0,
                            bragg_cell(geo).y,
                            bragg_cell(geo).z))
    ]
    return sources
示例#14
0
    def test_waveguide_flux(self):
        cell_size = mp.Vector3(10,10,0)

        pml_layers = [mp.PML(thickness=2.0)]

        rot_angles = range(0,60,20) # rotation angle of waveguide, CCW around z-axis

        fluxes = []
        for t in rot_angles:
            rot_angle = math.radians(t)
            sources = [mp.EigenModeSource(src=mp.GaussianSource(1.0,fwidth=0.1),
                                          size=mp.Vector3(y=10),
                                          center=mp.Vector3(x=-3),
                                          direction=mp.NO_DIRECTION,
                                          eig_kpoint=mp.Vector3(math.cos(rot_angle),math.sin(rot_angle),0),
                                          eig_band=1,
                                          eig_parity=mp.ODD_Z,
                                          eig_match_freq=True)]

            geometry = [mp.Block(center=mp.Vector3(),
                                 size=mp.Vector3(mp.inf,1,mp.inf),
                                 e1 = mp.Vector3(1,0,0).rotate(mp.Vector3(0,0,1), rot_angle),
                                 e2 = mp.Vector3(0,1,0).rotate(mp.Vector3(0,0,1), rot_angle),
                                 material=mp.Medium(index=1.5))]

            sim = mp.Simulation(cell_size=cell_size,
                                resolution=50,
                                boundary_layers=pml_layers,
                                sources=sources,
                                geometry=geometry)

            tran = sim.add_flux(1.0, 0, 1, mp.FluxRegion(center=mp.Vector3(x=3), size=mp.Vector3(y=10)))

            sim.run(until_after_sources=100)

            fluxes.append(mp.get_fluxes(tran)[0])
            print("flux:, {:.2f}, {:.6f}".format(t,fluxes[-1]))

        self.assertAlmostEqual(fluxes[0], fluxes[1], places=0)
        self.assertAlmostEqual(fluxes[1], fluxes[2], places=0)
        self.assertAlmostEqual(fluxes[0], fluxes[2], places=0)
示例#15
0
def run_sim(rot_angle=0):

    resolution = 50  # pixels/μm

    cell_size = mp.Vector3(14, 10, 0)

    pml_layers = [mp.PML(thickness=2, direction=mp.X)]

    fsrc = 1.0  # frequency of planewave (wavelength = 1/fsrc)

    n = 1.5  # refractive index of homogeneous material
    default_material = mp.Medium(index=n)

    k_point = mp.Vector3(fsrc * n).rotate(mp.Vector3(z=1), rot_angle)

    sources = [
        mp.EigenModeSource(
            src=mp.ContinuousSource(fsrc),
            center=mp.Vector3(),
            size=mp.Vector3(y=10),
            direction=mp.AUTOMATIC if rot_angle == 0 else mp.NO_DIRECTION,
            eig_kpoint=k_point,
            eig_band=1,
            eig_parity=mp.EVEN_Y + mp.ODD_Z if rot_angle == 0 else mp.ODD_Z,
            eig_match_freq=True)
    ]

    sim = mp.Simulation(cell_size=cell_size,
                        resolution=resolution,
                        boundary_layers=pml_layers,
                        sources=sources,
                        k_point=k_point,
                        default_material=default_material,
                        symmetries=[mp.Mirror(mp.Y)] if rot_angle == 0 else [])

    sim.run(until=100)

    plt.figure(dpi=100)
    sim.plot2D(fields=mp.Ez)
    plt.show()
示例#16
0
    def create_sim(self, beta_vector, vacuum=False):

        args = self.args

        hwvg = mp.Block(center=origin,
                        material=mp.Medium(epsilon=args.eps),
                        size=mp.Vector3(self.cell_size.x, args.wh))
        vwvg = mp.Block(center=origin,
                        material=mp.Medium(epsilon=args.eps),
                        size=mp.Vector3(args.wv, self.cell_size.y))
        router = mp.Block(
            center=self.design_center,
            size=self.design_size,
            epsilon_func=self.basis.parameterized_function(beta_vector))
        geometry = [hwvg, vwvg, router]

        envelope = mp.GaussianSource(args.fcen, fwidth=args.df)
        amp = 1.0
        if callable(getattr(envelope, "fourier_transform", None)):
            amp /= envelope.fourier_transform(args.fcen)
        sources = [
            mp.EigenModeSource(src=envelope,
                               center=self.source_center,
                               size=self.source_size,
                               eig_band=args.source_mode,
                               amplitude=amp)
        ]

        sim = mp.Simulation(resolution=args.res,
                            cell_size=self.cell_size,
                            boundary_layers=[mp.PML(self.dpml)],
                            geometry=geometry,
                            sources=sources)

        if args.complex_fields:
            sim.force_complex_fields = True

        return sim
示例#17
0
    def __init__(self,
                 cell_size=None,
                 background_geometry=[],
                 foreground_geometry=[],
                 sources=None,
                 source_region=[],
                 objective_regions=[],
                 basis=None,
                 design_region=None,
                 extra_regions=[],
                 objective_function=None,
                 extra_quantities=[]):
        """
        Parameters:
        -----------

        cell_size: array-like
        background_geometry: list of meep.GeometricObject
        foreground_geometry: list of meep.GeometricObject

              Size of computational cell and lists of GeometricObjects
              that {precede,follow} the design object in the overall geometry.

        sources: list of meep.Source
        source_region: Subregion
            (*either* `sources` **or** `source_region` should be non-None)
            Specification of forward source distribution, i.e. the source excitation(s) that
            produce the fields from which the objective function is computed.

            In general, sources will be an arbitrary caller-created list of Source
            objects, in which case source_region, source_component are ignored.

            As an alternative convenience convention, the caller may omit
            sources and instead specify source_region; in this case, a
            source distribution over the given region is automatically
            created based on the values of the module-wide configuration
            options fcen, df, source_component, source_mode.

        objective regions: list of Subregion
             subregions of the computational cell over which frequency-domain
             fields are tabulated and used to compute objective quantities

        basis: (Basis)
        design_region: (Subregion)
              (*either* `basis` **or** `design_region` should be non-None)
              Specification of function space for the design permittivity.

              In general, basis will be a caller-created instance of
              some subclass of meep.adjoint.Basis. Then the spatial
              extent of the design region is determined by basis and
              the design_region argument is ignored.

              As an alternative convenience convention, the caller
              may omit basis and set design_region; in this case,
              an appropriate basis for the given design_region is
              automatically created based on the values of various
              module-wide adj_opt such as 'element_type' and
              'element_length'. This convenience convention is
              only available for box-shaped (hyperrectangular)
              design regions.

        extra_regions: list of Subregion
            Optional list of additional subregions over which to tabulate frequency-domain
            fields.

        objective_function: str
            definition of the quantity to be maximized. This should be
            a mathematical expression in which the names of one or more
            objective quantities appear, and which should evaluate to
            a real number when numerical values are substituted for the
            names of all objective quantities.

        extra_quantities: list of str
            Optional list of additional objective quantities to be computed and reported
            together with the objective function.
        """

        #-----------------------------------------------------------------------
        # process convenience arguments:
        #  (a) if no basis was specified, create one using the given design
        #      region plus global option values
        #  (b) if no sources were specified, create one using the given source
        #      region plus global option values
        #-----------------------------------------------------------------------
        self.basis = basis or FiniteElementBasis(
            region=design_region,
            element_length=adj_opt('element_length'),
            element_type=adj_opt('element_type'))
        design_region = self.basis.domain
        design_region.name = design_region.name or 'design'

        if not sources:
            f, df, m, c = [
                adj_opt(s)
                for s in ['fcen', 'df', 'source_mode', 'source_component']
            ]
            envelope = mp.GaussianSource(f, fwidth=df)
            kws = {
                'center': V3(source_region.center),
                'size': V3(source_region.size),
                'src': envelope
            }  #, 'eig_band': m, 'component': c }
            sources = [
                mp.EigenModeSource(eig_band=m, **kws)
                if m > 0 else mp.Source(component=c, **kws)
            ]
        rescale_sources(sources)

        #-----------------------------------------------------------------------
        # initialize lower-level helper classes
        #-----------------------------------------------------------------------
        # DFTCells
        dft_cell_names = []
        objective_cells = [DFTCell(r) for r in objective_regions]
        extra_cells = [DFTCell(r) for r in extra_regions]
        design_cell = DFTCell(design_region, E_CPTS)
        dft_cells = objective_cells + extra_cells + [design_cell]

        # ObjectiveFunction
        obj_func = ObjectiveFunction(fstr=objective_function,
                                     extra_quantities=extra_quantities)

        # initial values of (a) design variables, (b) the spatially-varying
        # permittivity function they define (the 'design function'), (c) the
        # GeometricObject describing a material body with this permittivity
        # (the 'design object'), and (d) mp.Simulation superposing the design
        # object with the rest of the caller's geometry.
        # Note that sources and DFT cells are not added to the Simulation at
        # this stage; this is done later by internal methods of TimeStepper
        # on a just-in-time basis before starting a timestepping run.
        self.beta_vector = self.basis.project(adj_opt('eps_design'))
        self.design_function = self.basis.parameterized_function(
            self.beta_vector)
        design_object = mp.Block(center=V3(design_region.center),
                                 size=V3(design_region.size),
                                 epsilon_func=self.design_function.func())
        geometry = background_geometry + [design_object] + foreground_geometry
        sim = mp.Simulation(resolution=adj_opt('res'),
                            cell_size=V3(cell_size),
                            boundary_layers=[mp.PML(adj_opt('dpml'))],
                            geometry=geometry)

        # TimeStepper
        self.stepper = TimeStepper(obj_func, dft_cells, self.basis, sim,
                                   sources)

        #-----------------------------------------------------------------------
        # if the 'filebase' configuration option wasn't specified, set it
        # to the base filename of the caller's script
        #-----------------------------------------------------------------------
        if not adj_opt('filebase'):
            script = inspect.stack()[1][0].f_code.co_filename or 'meep_adjoint'
            script_base = os.path.basename(script).split('.')[0]
            set_adjoint_options({'filebase': os.path.basename(script_base)})

        if mp.am_master():
            init_log(filename=adj_opt('logfile')
                     or adj_opt('filebase') + '.log',
                     usecs=True)

        self.dashboard_state = None
示例#18
0
def main(args):

    resolution = args.res

    w1 = 1  # width of waveguide 1
    w2 = 2  # width of waveguide 2
    Lw = 10  # length of waveguide 1 and 2
    Lt = args.Lt  # taper length

    Si = mp.Medium(epsilon=12.0)

    dair = 3.0
    dpml = 5.0

    sx = dpml + Lw + Lt + Lw + dpml
    sy = dpml + dair + w2 + dair + dpml
    cell_size = mp.Vector3(sx, sy, 0)

    prism_x = sx + 1
    half_w1 = 0.5 * w1
    half_w2 = 0.5 * w2
    half_Lt = 0.5 * Lt

    if Lt > 0:
        vertices = [
            mp.Vector3(-prism_x, half_w1),
            mp.Vector3(-half_Lt, half_w1),
            mp.Vector3(half_Lt, half_w2),
            mp.Vector3(prism_x, half_w2),
            mp.Vector3(prism_x, -half_w2),
            mp.Vector3(half_Lt, -half_w2),
            mp.Vector3(-half_Lt, -half_w1),
            mp.Vector3(-prism_x, -half_w1)
        ]
    else:
        vertices = [
            mp.Vector3(-prism_x, half_w1),
            mp.Vector3(prism_x, half_w1),
            mp.Vector3(prism_x, -half_w1),
            mp.Vector3(-prism_x, -half_w1)
        ]

    geometry = [mp.Prism(vertices, height=100, material=Si)]

    boundary_layers = [mp.PML(dpml)]

    # mode wavelength
    lcen = 6.67

    # mode frequency
    fcen = 1 / lcen

    sources = [
        mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=0.2 * fcen),
                           component=mp.Ez,
                           size=mp.Vector3(0, sy - 2 * dpml, 0),
                           center=mp.Vector3(-0.5 * sx + dpml + 0.2 * Lw, 0,
                                             0),
                           eig_match_freq=True,
                           eig_parity=mp.ODD_Z + mp.EVEN_Y)
    ]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=boundary_layers,
                        geometry=geometry,
                        sources=sources)

    xm = -0.5 * sx + dpml + 0.5 * Lw  # x-coordinate of monitor
    mode_monitor = sim.add_eigenmode(
        fcen, 0, 1,
        mp.FluxRegion(center=mp.Vector3(xm, 0),
                      size=mp.Vector3(0, sy - 2 * dpml)))

    sim.run(until_after_sources=mp.stop_when_fields_decayed(
        50, mp.Ez, mp.Vector3(xm, 0, 0), 1e-9))

    coeffs = sim.get_eigenmode_coefficients(mode_monitor, [1])

    print("mode:, {}, {:.8f}, {:.8f}".format(Lt,
                                             abs(coeffs[0, 0, 0])**2,
                                             abs(coeffs[0, 0, 1])**2))
示例#19
0
south_wvg = mp.Block(center=mp.Vector3(-0.25 * sy * mpa.YHAT),
                     material=Si,
                     size=mp.Vector3(waveguide_width, 0.5 * sy, waveguide_h))

geometry = [wvg_horizontal, wvg_vertical]

#----------------------------------------------------------------------
# Eigenmode source
#----------------------------------------------------------------------
source_center = -d_source * mpa.XHAT
source_size = 2.0 * waveguide_width * mpa.YHAT
kpoint = 3 * mpa.XHAT
sources = [
    mp.EigenModeSource(mp.GaussianSource(frequency=fcen, fwidth=fwidth),
                       eig_band=1,
                       direction=mp.NO_DIRECTION,
                       eig_kpoint=kpoint,
                       size=source_size,
                       center=source_center)
]
#----------------------------------------------------------------------
#- design region and basis
#----------------------------------------------------------------------

design_size = mp.Vector3(l_design, l_design, waveguide_h)
design_region = mpa.Subregion(fcen,
                              df,
                              nfreq,
                              name='design',
                              center=mp.Vector3(),
                              size=design_size)
element_length = 1
示例#20
0
# # Later objects get priority : fix
final_geometry = []
# for fix in geometry:
#     final_geometry.append(fix)
for fix in si_layer:
    final_geometry.append(fix)

cell = mp.GDSII_vol(gdsII_file, CELL_LAYER, cell_zmin, cell_zmax)
src_vol = mp.GDSII_vol(gdsII_file, SOURCE_LAYER, si_zmin, si_zmax)
p1 = mp.GDSII_vol(gdsII_file, 20, si_zmin, si_zmax)
p2 = mp.GDSII_vol(gdsII_file, 21, si_zmin, si_zmax)

sources = [
    mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=df),
                       size=src_vol.size,
                       center=src_vol.center,
                       eig_band=1,
                       eig_parity=mp.EVEN_Y + mp.ODD_Z,
                       eig_match_freq=True)
]

# Display simulation object
sim = mp.Simulation(resolution=res,
                    default_material=oxide,
                    eps_averaging=False,
                    subpixel_maxeval=1,
                    subpixel_tol=1,
                    cell_size=cell.size,
                    boundary_layers=[mp.PML(dpml)],
                    sources=sources,
                    geometry=final_geometry,
                    geometry_center=mp.Vector3(ring_radius / 2,
示例#21
0
def notch(w):

    print("#----------------------------------------")
    print("NOTCH WIDTH: %s nanometers" % (w * 1000))
    print("#----------------------------------------")

    # w is the width of the notch in the waveguide

    angrad = ang * pi / 180
    bottomoffset = e * h / tan(angrad)

    vertices = [
        mp.Vector3(w / 2 + bottomoffset, (.5 + e) * h),
        mp.Vector3(-w / 2 - bottomoffset, (.5 + e) * h),
        mp.Vector3(-w / 2 + bottomoffset, (.5 - e) * h),
        mp.Vector3(w / 2 - bottomoffset, (.5 - e) * h)
    ]

    if bottomoffset > w / 2:
        ratio = (w / 2) / bottomoffset
        vertices = [
            mp.Vector3(w / 2, h / 2),
            mp.Vector3(-w / 2, h / 2),
            mp.Vector3(0, (.5 - e * ratio) * h)
        ]

    print(vertices)

    #Waveguide Geometry
    cell = mp.Vector3(a, H)

    geometry = [
        mp.Block(cell, center=mp.Vector3(0, 0), material=default_material),
        mp.Block(mp.Vector3(a, hu + h / 2),
                 center=mp.Vector3(0, (hu + h / 2) / 2),
                 material=upper_material),
        mp.Block(mp.Vector3(a, hl + h / 2),
                 center=mp.Vector3(0, -(hl + h / 2) / 2),
                 material=lower_material),
        mp.Block(mp.Vector3(a, h),
                 center=mp.Vector3(0, 0),
                 material=core_material)
    ]

    if w > 0:
        geometry.append(mp.Prism(vertices, height=1, material=upper_material))

    pml_layers = [mp.Absorber(thickness=dpml)]

    r00 = None
    r01 = None
    r10 = None
    r11 = None

    t00 = None
    t01 = None
    t10 = None
    t11 = None

    su0 = None
    sd0 = None
    su1 = None
    sd1 = None

    modes = [0, 1]

    if only_fund:
        modes = [0]

    # eig_parity_fund = 	mp.EVEN_Z+mp.EVEN_Y;
    # eig_parity_first = 	mp.EVEN_Z+mp.ODD_Y;

    eig_parity_fund = mp.EVEN_Y
    eig_parity_first = mp.ODD_Y

    # for mode in [0, 1]:
    for mode in modes:

        if mode == 0:
            eig_parity = eig_parity_fund  # Fundamental
            print("-----------")
            print("MODE TYPE: FUNDAMENTAL")

        else:
            eig_parity = eig_parity_first  # First Order
            print("-----------")
            print("MODE TYPE: FIRST ORDER")

        sources = [
            mp.EigenModeSource(mp.ContinuousSource(frequency=fcen),
                               size=mp.Vector3(0, H),
                               center=mp.Vector3(Ls, 0),
                               eig_parity=eig_parity)
        ]

        sim = mp.Simulation(cell_size=cell,
                            boundary_layers=pml_layers,
                            geometry=geometry,
                            sources=sources,
                            resolution=resolution,
                            force_complex_fields=True)
        '''
		#--------------------------------------------------
		#FOR DISPLAYING THE GEOMETRY

		sim.run(until = 200)

		eps_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric)
		plt.figure(dpi=100)
		plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary')
		#plt.axis('off')
		plt.show()

		quit()
		#----------------------------------------------------
		'''
        '''
		#------------------------------------------------------
		#FOR GENERATING THE ELECTRIC FIELD GIF
		#Note: After running this program, write the following commands in Terminal:
		    # $ source deactivate mp
		    # $ cd notch-out/
		    # $ python ../NotchIP.py

		sim.use_output_directory()
		sim.run(mp.at_beginning(mp.output_epsilon),
		        mp.to_appended("ez", mp.at_every(0.6, mp.output_efield_z)),
		        until = 200)
		#sim.run(mp.at_every(0.6 , mp.output_png(mp.Ez, "-Zc dkbluered")), until=200)

		#---------------------------------------------------------
		'''

        #---------------------------------------------------------
        # FOR GENERATING THE TRANSMITTANCE SPECTRUM

        nfreq = 1  # number of frequencies at which to compute flux

        refl_fr1 = mp.FluxRegion(center=mp.Vector3(Lr1, 0),
                                 size=mp.Vector3(
                                     0, monitorheight))  # Reflected flux 1
        refl_fr2 = mp.FluxRegion(center=mp.Vector3(Lr2, 0),
                                 size=mp.Vector3(
                                     0, monitorheight))  # Reflected flux 2
        tran_fr = mp.FluxRegion(center=mp.Vector3(Lt, 0),
                                size=mp.Vector3(
                                    0, monitorheight))  # Transmitted flux
        su_fr = mp.FluxRegion(center=mp.Vector3(0, monitorheight / 2),
                              size=mp.Vector3(
                                  a, 0))  # Flux loss above the waveguide
        sd_fr = mp.FluxRegion(center=mp.Vector3(0, -monitorheight / 2),
                              size=mp.Vector3(
                                  a, 0))  # Flux loss below the waveguide

        # refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1)
        # refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2)
        # tran = 	sim.add_flux(fcen, df, nfreq, tran_fr)
        # su = 	sim.add_flux(fcen, df, nfreq, su_fr)
        # sd = 	sim.add_flux(fcen, df, nfreq, sd_fr)

        # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE STARTS HERE ------------------------

        refl_vals = []
        tran_vals = []

        def get_refl_slice(sim):
            # print(sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True))
            # refl_val = sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)
            refl_vals.append(
                sim.get_array(center=mp.Vector3(Lr1, 0),
                              size=mp.Vector3(0,
                                              monitorheight - 2 / resolution),
                              component=mp.Ez,
                              cmplx=True))

        def get_tran_slice(sim):
            # print(sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True))
            # tran_val = sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)
            tran_vals.append(
                sim.get_array(center=mp.Vector3(Lt, 0),
                              size=mp.Vector3(0,
                                              monitorheight - 2 / resolution),
                              component=mp.Ez,
                              cmplx=True))

        gif = True

        if gif:  # and w == 0.1:
            sim.use_output_directory()
            sim.run(mp.at_beginning(mp.output_epsilon),
                    mp.at_end(get_refl_slice),
                    mp.at_end(get_tran_slice),
                    until=100)

            refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1)
            refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2)
            tran = sim.add_flux(fcen, df, nfreq, tran_fr)
            su = sim.add_flux(fcen, df, nfreq, su_fr)
            sd = sim.add_flux(fcen, df, nfreq, sd_fr)

            # sim.run(mp.at_every(wavelength / 20, mp.output_efield_z), until=wavelength)
            # sim.run(mp.at_every(wavelength/20 , mp.output_png(mp.Ez, "-RZc bluered -A notch-out/notch-eps-000000000.h5 -a gray:.2")), until=19*wavelength/20)
            sim.run(mp.at_every(
                wavelength / 20,
                mp.output_png(
                    mp.Ez,
                    "-RZc bluered -A notch-out/notch-eps-000000.00.h5 -a gray:.2"
                )),
                    until=19 * wavelength / 20)
            sim.run(until=50)
        else:
            sim.run(mp.at_end(get_refl_slice),
                    mp.at_end(get_tran_slice),
                    until=100)

            sim.run(until_after_sources=mp.stop_when_fields_decayed(
                50, mp.Ez, mp.Vector3(), 1e-5))

        os.system(
            "h5topng notch-out/notch-eps-000000.00.h5; mv notch-out/notch-eps-000000.00.png "
            + case + "-" + str(int(w * 1000)) + "-" + str(mode) + "-eps.png")
        os.system("cp notch-out/notch-ez-000100.00.png " + case + "-" +
                  str(int(w * 1000)) + "-" + str(mode) + ".png")
        os.system("convert notch-out/notch-ez-*.png    " + case + "-" +
                  str(int(w * 1000)) + "-" + str(mode) + ".gif")

        # get_eigenmode(fcen, mp., refl_fr1, 1, kpoint)
        # v = mp.volume(mp.vec(Lr1, -monitorheight/2), mp.vec(Lr1, monitorheight/2))
        # mode = get_eigenmode(fcen, mp.X, v, v, 1, mp.vec(0, 0, 0), True, 0, 0, 1e-7, True)
        # print(mode.amplitude)

        # coef_refl_fund = 	mp.get_eigenmode_coefficients_and_kpoints(refl_fr1, 1, eig_parity=eig_parity_fund, 	eig_resolution=resolution, eig_tolerance=1e-7)
        # coef_refl_first = 	mp.get_eigenmode_coefficients_and_kpoints(refl_fr1, 1, eig_parity=eig_parity_first, eig_resolution=resolution, eig_tolerance=1e-7)
        #
        # coef_tran_fund = 	mp.get_eigenmode_coefficients_and_kpoints(tran_fr, 	1, eig_parity=eig_parity_fund, 	eig_resolution=resolution, eig_tolerance=1e-7)
        # coef_tran_first = 	mp.get_eigenmode_coefficients_and_kpoints(tran_fr, 	1, eig_parity=eig_parity_first, eig_resolution=resolution, eig_tolerance=1e-7)

        ep = mp.ODD_Z

        #coef_refl_fund, 	vgrp, kpoints_fund 	= 	sim.get_eigenmode_coefficients(refl1, [1], eig_parity=ep, 	eig_resolution=resolution, eig_tolerance=1e-7)
        #coef_refl_first, 	vgrp, kpoints_first =	sim.get_eigenmode_coefficients(refl1, [2], eig_parity=ep,	eig_resolution=resolution, eig_tolerance=1e-7)

        #coef_tran_fund, 	vgrp, kpoints_fund 	=	sim.get_eigenmode_coefficients(tran,  [1], eig_parity=ep, 	eig_resolution=resolution, eig_tolerance=1e-7)
        #coef_tran_first,	vgrp, kpoints_first = 	sim.get_eigenmode_coefficients(tran,  [2], eig_parity=ep, 	eig_resolution=resolution, eig_tolerance=1e-7)

        # print(kpoints_fund)
        # print(kpoints_first)
        # print(kpoints_fund[0])
        # print(type(kpoints_fund[0]))
        # print(dir(kpoints_fund[0]))

        # n_eff_fund = 	wavelength*kpoints_fund[0].x
        # n_eff_first = 	wavelength*kpoints_first[0].x

        n_eff_fund = neff
        n_eff_first = 1

        print(n_eff_fund)
        print(n_eff_first)

        # print(coef_refl_fund)
        # print(type(coef_refl_fund))
        # print(dir(coef_refl_fund))

        # print(coef_refl_fund[0])
        # print(coef_refl_fund[0][0,0,:])
        #
        # fund_refl_amp = 		coef_refl_fund[0][0,0,1];
        # first_order_refl_amp =	coef_refl_first[0][0,0,1];
        # fund_tran_amp =			coef_tran_fund[0][0,0,0];
        # first_order_tran_amp =	coef_tran_first[0][0,0,0];

        print("get_eigenmode_coefficients:\n")

        #print(coef_refl_fund)
        #print(coef_refl_first)
        #print(coef_tran_fund)
        #print(coef_tran_first)

        print("\n")
        # print(coef_refl_fund[0,0,:])

        #fund_refl_amp = 		coef_refl_fund[0,0,1];
        #first_order_refl_amp =	coef_refl_first[0,0,1];
        #fund_tran_amp =			coef_tran_fund[0,0,0];
        #first_order_tran_amp =	coef_tran_first[0,0,0];

        refl_val = refl_vals[0]
        tran_val = tran_vals[0]

        # n_eff must satisfy n_e <= n_eff <= n_c for the mode to be bound.

        def fund_func(n_eff):
            if n_eff >= n_c and n_eff <= n_e:
                return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan(
                    pi * h / wavelength * sqrt(n_e**2 - n_eff**2))

        def first_order_func(n_eff):
            if n_eff >= n_c and n_eff <= n_e:
                return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan(
                    pi * h / wavelength * sqrt(n_e**2 - n_eff**2) - pi / 2)

        initial_guess = (n_c + n_e) / 2

        # n_eff_fund = 	fsolve(fund_func, initial_guess)
        # n_eff_first = 	fsolve(first_order_func, n_c)

        print(n_eff_fund, n_eff_first)

        assert (n_eff_fund > n_eff_first)

        if len(n_eff_funds) == 0:
            n_eff_funds.append(n_eff_fund)

        if len(n_eff_firsts) == 0:
            n_eff_firsts.append(n_eff_first)

        ky0_fund = np.abs(2 * pi / wavelength * sqrt(n_e**2 - n_eff_fund**2))
        ky0_first = np.abs(2 * pi / wavelength * sqrt(n_e**2 - n_eff_first**2))

        ky1_fund = ky0_fund  # np.abs(2 * pi / wavelength * sqrt(n_eff_fund **2 - n_c**2))
        ky1_first = ky0_first  # np.abs(2 * pi / wavelength * sqrt(n_eff_first**2 - n_c**2))

        E_fund = lambda y: cos(ky0_fund * y) if np.abs(y) < h / 2 else cos(
            ky0_fund * h / 2) * np.exp(-ky1_fund * (np.abs(y) - h / 2))
        E_first_order = lambda y: sin(ky0_first * y) if np.abs(
            y) < h / 2 else sin(ky0_first * h / 2) * np.exp(-ky1_first * (
                np.abs(y) - h / 2)) * np.sign(y)
        # y_list = np.arange(-H/2+.5/resolution, H/2-.5/resolution, 1/resolution)

        #print("Y LIST: ", y_list)
        #print("SIZE OF Y LIST: ", y_list.size)

        E_fund_vec = np.zeros(y_list.size)
        E_first_order_vec = np.zeros(y_list.size)

        for index in range(y_list.size):
            y = y_list[index]
            E_fund_vec[index] = E_fund(y)
            E_first_order_vec[index] = E_first_order(y)

        # print(dir(sim))
        # print(type(sim.get_eigenmode_coefficients))
        # print(dir(sim.get_eigenmode_coefficients))
        # print(type(sim.get_eigenmode))
        # print(dir(sim.get_eigenmode))
        # print(sim.get_eigenmode.__code__.co_varnames)
        # print(sim.get_eigenmode.__defaults__)

        # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, 1, None)
        # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, 2, None)
        # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, 3, None)
        # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, 4, None)

        # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, 1, mp.Vector3(0, 0, 0))
        # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, 2, mp.Vector3(0, 0, 0))
        # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, 3, mp.Vector3(0, 0, 0))
        # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, 4, mp.Vector3(0, 0, 0))

        # print(refl1.where)
        # numEA = 0
        # E1 = sim.fields.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 1, mp.vec(0,0,0), True, 0, numEA, 1e-7, True)

        # print(type(E1))
        # print(dir(E1))
        #
        # print(refl1.where)
        # # print(E1, E2, E3, E4)
        # print(E1.amplitude, E1.band_num, E1.group_velocity, E1.k)
        # print(type(E1.amplitude))
        # print(dir(E1.amplitude))
        # print(doc(E1.amplitude))
        # print(self(E1.amplitude))
        # print(E1.amplitude(y_list))
        # print(type(E1.amplitude(y_list)))
        # print(dir(E1.amplitude(y_list)))
        # print(E1.amplitude, E2.amplitude, E3.amplitude, E4.amplitude)

        # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 1, mp.vec(0, 0, 0))
        # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 2, mp.vec(0, 0, 0))
        # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 3, mp.vec(0, 0, 0))
        # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 4, mp.vec(0, 0, 0))

        # print(y_list)
        #
        # E1a = np.zeros(y_list.size, dtype='Complex128');
        # E2a = np.zeros(y_list.size, dtype='Complex128');
        # E3a = np.zeros(y_list.size, dtype='Complex128');
        # E4a = np.zeros(y_list.size, dtype='Complex128');
        #
        # # print(mp.eigenmode_amplitude.__code__.co_varnames)
        # # print(mp.eigenmode_amplitude.__defaults__)
        #
        # for i in range(y_list.size):
        # 	# print(E1)
        # 	# print(E1.swigobj)
        # 	# print(E1.amplitude)
        # 	# print(mp.vec(Lr1, y_list[i], 0))
        # 	# print(mp.Vector3(Lr1, y_list[i], 0))
        # 	# print(mp.Ez)
        # 	# E1a[i] = mp.eigenmode_amplitude(E1.swigobj, mp.vec(Lr1, y_list[i], 0), mp.Ez);
        # 	eval_point = mp.vec(Lr1, y_list[i], 0)
        # 	# print(eval_point)
        # 	E1a[i] = mp.eigenmode_amplitude(E1.swigobj, eval_point, mp.Ex)
        # 	E2a[i] = mp.eigenmode_amplitude(E2.swigobj, eval_point, mp.Ex)
        # 	E3a[i] = mp.eigenmode_amplitude(E3.swigobj, eval_point, mp.Ex)
        # 	E4a[i] = mp.eigenmode_amplitude(E4.swigobj, eval_point, mp.Ex)
        # 	# E1a[i] = mp.eigenmode_amplitude(E1.amplitude, mp.Vector3(Lr1, y_list[i], 0), mp.Ez);
        #
        # plt.plot(y_list, np.abs(E1a)**2, 'bo-', label='E1')
        # plt.plot(y_list, np.abs(E2a)**2, 'ro-', label='E2')
        # plt.plot(y_list, np.abs(E3a)**2, 'go-', label='E3')
        # plt.plot(y_list, np.abs(E4a)**2, 'co-', label='E4')
        # # plt.axis([40.0, 300.0, 0.0, 100.0])
        # plt.xlabel("y (um)")
        # plt.ylabel("Field (a.u.)")
        # plt.legend(loc="center right")
        # plt.show()

        # print("r VECTOR: ", 	refl_val)
        # print("t VECTOR: ", 	tran_val)
        # print("E0 VECTOR: ", 	E_fund_vec)
        # print("E1 VECTOR: ", 	E_first_order_vec)

        # fund_refl_amp_2 = 			np.conj(np.dot(refl_val, E_fund_vec) 		/ np.dot(E_fund_vec, E_fund_vec))					# Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz)
        # first_order_refl_amp_2 = 	np.conj(np.dot(refl_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec))
        # fund_tran_amp_2 = 			np.conj(np.dot(tran_val, E_fund_vec) 		/ np.dot(E_fund_vec, E_fund_vec))
        # first_order_tran_amp_2 = 	np.conj(np.dot(tran_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec))

        fund_refl_amp = np.conj(
            np.dot(refl_val, E0) / np.dot(E0, E0)
        )  # Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz)
        first_order_refl_amp = 0  # np.conj(np.dot(refl_val, E1[:,2]) / np.dot(E1[:,2], E1[:,2]))
        fund_tran_amp = np.conj(np.dot(tran_val, E0) / np.dot(E0, E0))
        first_order_tran_amp = 0  # np.conj(np.dot(tran_val, E1[:,2]) / np.dot(E1[:,2], E1[:,2]))

        fund_refl = np.conj(fund_refl_amp) * E0
        not_fund_refl = refl_val - fund_refl
        fund_tran = np.conj(fund_tran_amp) * E0
        not_fund_tran = tran_val - fund_tran

        fund_refl_power = np.dot(np.conj(fund_refl), fund_refl)
        not_fund_refl_power = np.dot(np.conj(not_fund_refl), not_fund_refl)
        fund_tran_power = np.dot(np.conj(fund_tran), fund_tran)
        not_fund_tran_power = np.dot(np.conj(not_fund_tran), not_fund_tran)

        fund_refl_ratio = np.abs(fund_refl_power /
                                 (fund_refl_power + not_fund_refl_power))
        first_order_refl_ratio = 0
        fund_tran_ratio = np.abs(fund_tran_power /
                                 (fund_tran_power + not_fund_tran_power))
        first_order_tran_ratio = 0

        # plt.plot(y_list, np.abs(refl_val),	'bo-',label='reflectance')
        # plt.plot(y_list, np.abs(tran_val),	'ro-',label='transmittance')
        # plt.plot(y_list, E0,	'go-',label='E0')
        # plt.plot(y_list, fund_refl_amp*E0,	'co-',label='over')
        # # plt.axis([40.0, 300.0, 0.0, 100.0])
        # plt.xlabel("y (um)")
        # plt.ylabel("Field")
        # plt.legend(loc="center right")
        # plt.show()
        #
        # print("\n")
        #
        # print(tran_val.size, refl_val.size)
        #
        # print("\n")
        #
        # print(tran_val, refl_val, E0)
        #
        # print("\n")
        # # print(np.conj(tran_val), tran_val, E1[:,2])
        # #
        # # print(np.conj(refl_val), refl_val, E1[:,2])
        #
        # refl_tot_power = np.abs(np.dot(np.conj(refl_val), refl_val))
        # tran_tot_power = np.abs(np.dot(np.conj(tran_val), tran_val))
        #
        # print(fund_refl_amp, refl_tot_power, fund_tran_amp, tran_tot_power)

        # print(fund_refl_amp 		, fund_refl_amp_2 		)
        # print(first_order_refl_amp 	, first_order_refl_amp_2)
        # print(fund_tran_amp 		, fund_tran_amp_2 		)
        # print(first_order_tran_amp 	, first_order_tran_amp_2)
        #
        # print(np.angle(fund_refl_amp), 			np.angle(fund_refl_amp_2))
        # print(np.angle(first_order_refl_amp), 	np.angle(first_order_refl_amp_2))
        # print(np.angle(fund_tran_amp), 			np.angle(fund_tran_amp_2))
        # print(np.angle(first_order_tran_amp), 	np.angle(first_order_tran_amp_2))

        # fund_refl_power = 			np.abs(fund_tran_amp)			** 2
        # fund_refl_power = 			np.abs(fund_refl_amp)			** 2
        # first_order_refl_power = 	np.abs(first_order_refl_amp) 	** 2
        # fund_tran_power = 			np.abs(fund_tran_amp) 			** 2
        # first_order_tran_power = 	np.abs(first_order_tran_amp) 	** 2

        # print(fund_refl_power, first_order_refl_power, fund_tran_power, first_order_tran_power)

        # fund_refl_ratio = 			fund_refl_power 		/ (fund_refl_power + first_order_refl_power)
        # first_order_refl_ratio = 	first_order_refl_power 	/ (fund_refl_power + first_order_refl_power)
        # fund_tran_ratio = 			fund_tran_power 		/ (fund_tran_power + first_order_tran_power)
        # first_order_tran_ratio = 	first_order_tran_power 	/ (fund_tran_power + first_order_tran_power)

        # fund_refl_power = 			np.abs(fund_refl_amp)			** 2
        # first_order_refl_power = 	np.abs(first_order_refl_amp)	** 2
        # fund_tran_power = 			np.abs(fund_tran_amp)			** 2
        # first_order_tran_power = 	np.abs(first_order_tran_amp)	** 2
        #
        # fund_refl_ratio = 			fund_refl_power 		/ refl_tot_power
        # first_order_refl_ratio = 	first_order_refl_power 	/ refl_tot_power
        # fund_tran_ratio = 			fund_tran_power 		/ tran_tot_power
        # first_order_tran_ratio = 	first_order_tran_power 	/ tran_tot_power
        #
        # fund_refl_ratio = 			1
        # first_order_refl_ratio = 	0
        # fund_tran_ratio = 			1
        # first_order_tran_ratio = 	0

        print("Percentage of reflected light in fundamental mode: ",
              fund_refl_ratio * 100)
        print("Percentage of reflected light in first order mode: ",
              first_order_refl_ratio * 100)
        print("Percentage of transmitted light in fundamental mode: ",
              fund_tran_ratio * 100)
        print("Percentage of transmitted light in first order mode: ",
              first_order_tran_ratio * 100)

        # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE ENDS HERE ------------------------

        wl = []  #list of wavelengths

        refl1_flux = mp.get_fluxes(refl1)
        refl2_flux = mp.get_fluxes(refl2)
        tran_flux = mp.get_fluxes(tran)
        su_flux = mp.get_fluxes(su)
        sd_flux = mp.get_fluxes(sd)

        flux_freqs = mp.get_flux_freqs(refl1)

        for i in range(nfreq):
            wl = np.append(wl, 1 / flux_freqs[i])
            print(1 / flux_freqs[i])

        # for ind, elt in enumerate(wl):
        #     #print(round(elt, 4))
        #     if round(elt, 3) == 0.637:
        #         #print("ALERT: MATCH FOUND")
        #         index = ind

        index = 0

        rp = refl1_flux[index]
        tp = tran_flux[index]

        # print("rp/tp:\n")
        # print(rp)
        # print(tp)
        # print("\n")

        R = -refl1_flux[index] / (refl2_flux[index] - refl1_flux[index])
        T = tran_flux[index] / (refl2_flux[index] - refl1_flux[index])
        S = (refl2_flux[index] - tran_flux[index]) / (refl2_flux[index] -
                                                      refl1_flux[index])
        Su = su_flux[index] / (refl2_flux[index] - refl1_flux[index])
        Sd = -sd_flux[index] / (refl2_flux[index] - refl1_flux[index])

        S_correction = (1 - R - T) / (Su + Sd)

        # print(R, T, S, Su, Sd)

        r = sqrt(R)
        t = sqrt(T)

        # The amplitude ... times the phase ... accounting for the distance to the detector (Reverse exp(-kz) of phase).
        # r_fund = 	(r * fund_refl_ratio) 			* (fund_refl_amp 		/ np.abs(fund_refl_amp)) 		* (np.exp( 2j*pi * (-Lr1 - w/2) * n_eff_fund  / wavelength))	# Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center.
        # r_first = 	(r * first_order_refl_ratio) 	* (first_order_refl_amp / np.abs(first_order_refl_amp)) * (np.exp( 2j*pi * (-Lr1 - w/2) * n_eff_first / wavelength))
        # t_fund =    (t * fund_tran_ratio) 			* (fund_tran_amp 		/ np.abs(fund_tran_amp))		* (np.exp( 2j*pi * ( Lt  - w/2) * n_eff_fund  / wavelength))
        # t_first =   (t * first_order_tran_ratio) 	* (first_order_tran_amp / np.abs(first_order_tran_amp)) * (np.exp( 2j*pi * ( Lt  - w/2) * n_eff_first / wavelength))

        r_fund = (r * fund_refl_ratio) * np.exp(
            1j * np.angle(fund_refl_amp) + 2j * pi *
            (-Lr1 - w / 2) * n_eff_fund / wavelength
        )  # Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center.
        r_first = (r * first_order_refl_ratio
                   ) * np.exp(1j * np.angle(first_order_refl_amp) + 2j * pi *
                              (-Lr1 - w / 2) * n_eff_first / wavelength)
        t_fund = (t * fund_tran_ratio
                  ) * np.exp(1j * np.angle(fund_tran_amp) + 2j * pi *
                             (Lt - w / 2) * n_eff_fund / wavelength)
        t_first = (t * first_order_tran_ratio
                   ) * np.exp(1j * np.angle(first_order_tran_amp) + 2j * pi *
                              (Lt - w / 2) * n_eff_first / wavelength)

        if mode == 0:
            r00 = r_fund
            r01 = r_first

            t00 = t_fund
            t01 = t_first

            su0 = sqrt(np.abs(Su * S_correction))
            sd0 = sqrt(np.abs(Sd * S_correction))
            # su0 = sqrt(Su)
            # sd0 = sqrt(Sd)

            r00s.append(r00)
            r01s.append(r01)
            t00s.append(t00)
            t01s.append(t01)
            su0s.append(su0)
            sd0s.append(sd0)

            if only_fund:
                r10s.append(0)
                r11s.append(0)
                t10s.append(0)
                t11s.append(1)
                su1s.append(0)
                sd1s.append(0)
        else:
            r10 = r_fund
            r11 = r_first

            t10 = t_fund
            t11 = t_first

            su1 = sqrt(np.abs(Su * S_correction))
            sd1 = sqrt(np.abs(Sd * S_correction))
            # su1 = sqrt(Su)
            # sd1 = sqrt(Sd)

            r10s.append(r10)
            r11s.append(r11)
            t10s.append(t10)
            t11s.append(t11)
            su1s.append(su1)
            sd1s.append(sd1)

        norm_Su = S * Su / (Su + Sd)

        NET = round((R + T + S) * 100, 0)
        if NET > 100.0:
            NET = 100.0

        NET_LOSS = round((Su + Sd) / S * 100, 0)
        if NET_LOSS > 100.0:
            NET_LOSS = 100.0
        '''
		np.append(ws, [w * 1000])
		np.append(Rs, [R * 100])
		np.append(Ts, [T * 100])
		np.append(Ss, [S * 100])
		np.append(NET_LIST, [NET])
		np.append(Sus, [Su * 100])
		np.append(Sds, [Sd * 100])
		np.append(NET_LOSS_LIST, [NET_LOSS])
		np.append(norm_Sus, [norm_Su * 100])
		'''

        if mode == 0:
            ws.append(w * 1000)
            Rs.append(R * 100)
            Ts.append(T * 100)
            Ss.append(S * 100)
            NET_LIST.append(NET)
            Sus.append(Su * 100)
            Sds.append(Sd * 100)
            NET_LOSS_LIST.append(NET_LOSS)
            norm_Sus.append(norm_Su * 100)

        if mode == 0:

            f1.write("--------------------------------------------------- \n")

            f1.write("Notch Width: %s nanometers \n" % (w * 1000))
            f1.write("Reflection Percentage: %s\n" % (R * 100))
            f1.write("Transmission Percentage: %s\n" % (T * 100))
            f1.write("Total Loss Percentage: %s\n" % (S * 100))
            f1.write("Percentage of Light Accounted For: %s\n" % (NET))
            f1.write("Upper Loss Percentage: %s\n" % (Su * 100))
            f1.write("Lower Loss Percentage: %s\n" % (Sd * 100))
            f1.write("Percentage of Total Loss Accounted For: %s\n" %
                     (NET_LOSS))
            f1.write("Normalized Upper Loss Percentage: %s\n" %
                     (norm_Su * 100))
            f1.write("\n \n")

            f1.write("FUNDAMENTAL MODE \n")
            f1.write("n_eff:   %s\n" % (n_eff_fund))
            f1.write("Re(r00): %s\n" % (np.real(r00)))
            f1.write("Im(r00): %s\n" % (np.imag(r00)))
            f1.write("Re(r01): %s\n" % (np.real(r01)))
            f1.write("Im(r01): %s\n" % (np.imag(r01)))
            f1.write("Re(t00): %s\n" % (np.real(t00)))
            f1.write("Im(t00): %s\n" % (np.imag(t00)))
            f1.write("Re(t01): %s\n" % (np.real(t01)))
            f1.write("Im(t01): %s\n" % (np.imag(t01)))
            f1.write("Re(su0): %s\n" % (np.real(su0)))
            f1.write("Im(su0): %s\n" % (np.imag(su0)))
            f1.write("Re(sd0): %s\n" % (np.real(sd0)))
            f1.write("Im(sd0): %s\n" % (np.imag(sd0)))
            f1.write("\n")

        else:

            f1.write("FIRST ORDER MODE \n")
            f1.write("n_eff:   %s\n" % (n_eff_first))
            f1.write("Re(r10): %s\n" % (np.real(r10)))
            f1.write("Im(r10): %s\n" % (np.imag(r10)))
            f1.write("Re(r11): %s\n" % (np.real(r11)))
            f1.write("Im(r11): %s\n" % (np.imag(r11)))
            f1.write("Re(t10): %s\n" % (np.real(t10)))
            f1.write("Im(t10): %s\n" % (np.imag(t10)))
            f1.write("Re(t11): %s\n" % (np.real(t11)))
            f1.write("Im(t11): %s\n" % (np.imag(t11)))
            f1.write("Re(su1): %s\n" % (np.real(su1)))
            f1.write("Im(su1): %s\n" % (np.imag(su1)))
            f1.write("Re(sd1): %s\n" % (np.real(sd1)))
            f1.write("Im(sd1): %s\n" % (np.imag(sd1)))

            f1.write("--------------------------------------------------- \n")

        sim.reset_meep()
示例#22
0
time = 500

#----------------------------------------------------------------------
# Eigenmode source
#----------------------------------------------------------------------

fcen = 1/1.55
width = 0.2
fwidth = width * fcen
source_center  = [-1,0,0]
source_size    = mp.Vector3(0,2,0)
kpoint = mp.Vector3(1,0,0)
src = mp.GaussianSource(frequency=fcen,fwidth=fwidth)
source = [mp.EigenModeSource(src,
                    eig_band = 1,
                    direction=mp.NO_DIRECTION,
                    eig_kpoint=kpoint,
                    size = source_size,
                    center=source_center)]
#----------------------------------------------------------------------
#- geometric objects
#----------------------------------------------------------------------

Nx = 10
Ny = 10

design_region = mp.Volume(center=mp.Vector3(), size=mp.Vector3(1, 1, 0))
rho_vector = 11*np.random.rand(Nx*Ny) + 1
basis = mpa.BilinearInterpolationBasis(volume=design_region,Nx=Nx,Ny=Ny,rho_vector=rho_vector)

geometry = [
    mp.Block(center=mp.Vector3(x=-Sx/4), material=mp.Medium(index=3.45), size=mp.Vector3(Sx/2, 0.5, 0)), # horizontal waveguide
示例#23
0
    def run_mode_coeffs(self, mode_num, kpoint_func):

        resolution = 15

        w = 1   # width of waveguide
        L = 10  # length of waveguide

        Si = mp.Medium(epsilon=12.0)

        dair = 3.0
        dpml = 3.0

        sx = dpml + L + dpml
        sy = dpml + dair + w + dair + dpml
        cell_size = mp.Vector3(sx, sy, 0)

        prism_x = sx + 1
        prism_y = w / 2
        vertices = [mp.Vector3(-prism_x, prism_y),
                    mp.Vector3(prism_x, prism_y),
                    mp.Vector3(prism_x, -prism_y),
                    mp.Vector3(-prism_x, -prism_y)]

        geometry = [mp.Prism(vertices, height=mp.inf, material=Si)]

        boundary_layers = [mp.PML(dpml)]

        # mode frequency
        fcen = 0.20  # > 0.5/sqrt(11) to have at least 2 modes

        sources = [mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=0.5*fcen),
                                      eig_band=mode_num,
                                      size=mp.Vector3(0,sy-2*dpml,0),
                                      center=mp.Vector3(-0.5*sx+dpml,0,0),
                                      eig_match_freq=True,
                                      eig_resolution=32) ]

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell_size,
                            boundary_layers=boundary_layers,
                            geometry=geometry,
                            sources=sources,
                            symmetries=[mp.Mirror(mp.Y, phase=1 if mode_num % 2 == 1 else -1)])

        xm = 0.5*sx - dpml  # x-coordinate of monitor
        mflux = sim.add_mode_monitor(fcen, 0, 1, mp.ModeRegion(center=mp.Vector3(xm,0), size=mp.Vector3(0,sy-2*dpml)))
        mode_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=mp.Vector3(xm,0), size=mp.Vector3(0,sy-2*dpml)))

        # sim.run(until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, mp.Vector3(-0.5*sx+dpml,0), 1e-10))
        sim.run(until_after_sources=100)

        modes_to_check = [1, 2]  # indices of modes for which to compute expansion coefficients
        res = sim.get_eigenmode_coefficients(mflux, modes_to_check, kpoint_func=kpoint_func)

        self.assertTrue(res.kpoints[0].close(mp.Vector3(0.604301, 0, 0)))
        self.assertTrue(res.kpoints[1].close(mp.Vector3(0.494353, 0, 0), tol=1e-2))
        self.assertTrue(res.kdom[0].close(mp.Vector3(0.604301, 0, 0)))
        self.assertTrue(res.kdom[1].close(mp.Vector3(0.494353, 0, 0), tol=1e-2))

        mode_power = mp.get_fluxes(mode_flux)[0]

        TestPassed = True
        TOLERANCE = 5.0e-3
        c0 = res.alpha[mode_num - 1, 0, 0] # coefficient of forward-traveling wave for mode #mode_num
        for nm in range(1, len(modes_to_check)+1):
            if nm != mode_num:
                cfrel = np.abs(res.alpha[nm - 1, 0, 0]) / np.abs(c0)
                cbrel = np.abs(res.alpha[nm - 1, 0, 1]) / np.abs(c0)
                if cfrel > TOLERANCE or cbrel > TOLERANCE:
                    TestPassed = False

        self.sim = sim

        # test 1: coefficient of excited mode >> coeffs of all other modes
        self.assertTrue(TestPassed, msg="cfrel: {}, cbrel: {}".format(cfrel, cbrel))
        # test 2: |mode coeff|^2 = power
        self.assertAlmostEqual(mode_power / abs(c0**2), 1.0, places=1)

        return res
示例#24
0
                 center=mp.Vector3(x,
                                   h * (1 - e) / 2),
                 material=default_material))

    Ls = -2 * x  # Position of source
    Lr1 = -2 * x - 1.25  # Position of reflection monitor 1
    Lr2 = -2 * x + 1.25  # Position of reflection monitor 2
    Lt = -Lr2  # Position of transmission monitor
    scatter_monitor_size = 2 * Lt

    assert (Lr1 > -a / 2 + dpml
            )  # Make sure that nothing we care about is sitting inside the PML

    sources = [
        mp.EigenModeSource(mp.ContinuousSource(frequency=fcen),
                           size=mp.Vector3(0, H),
                           center=mp.Vector3(Ls, 0))
    ]

    pml_layers = [mp.Absorber(thickness=dpml)]

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        geometry=geometry,
                        sources=sources,
                        resolution=resolution)

    sim.reset_meep()

    nfreq = 1
示例#25
0
文件: coupler.py 项目: mniehus/meep
def main(args):
    cell_zmax = 0.5 * cell_thickness if args.three_d else 0
    cell_zmin = -0.5 * cell_thickness if args.three_d else 0
    si_zmax = t_Si if args.three_d else 0

    # read cell size, volumes for source region and flux monitors,
    # and coupler geometry from GDSII file
    upper_branch = mp.get_GDSII_prisms(silicon, gdsII_file, UPPER_BRANCH_LAYER,
                                       si_zmin, si_zmax)
    lower_branch = mp.get_GDSII_prisms(silicon, gdsII_file, LOWER_BRANCH_LAYER,
                                       si_zmin, si_zmax)

    cell = mp.GDSII_vol(gdsII_file, CELL_LAYER, cell_zmin, cell_zmax)
    p1 = mp.GDSII_vol(gdsII_file, PORT1_LAYER, si_zmin, si_zmax)
    p2 = mp.GDSII_vol(gdsII_file, PORT2_LAYER, si_zmin, si_zmax)
    p3 = mp.GDSII_vol(gdsII_file, PORT3_LAYER, si_zmin, si_zmax)
    p4 = mp.GDSII_vol(gdsII_file, PORT4_LAYER, si_zmin, si_zmax)
    src_vol = mp.GDSII_vol(gdsII_file, SOURCE_LAYER, si_zmin, si_zmax)

    # displace upper and lower branches of coupler (as well as source and flux regions)
    if args.d != default_d:
        delta_y = 0.5 * (args.d - default_d)
        delta = mp.Vector3(y=delta_y)
        p1.center += delta
        p2.center -= delta
        p3.center += delta
        p4.center -= delta
        src_vol.center += delta
        cell.size += 2 * delta
        for np in range(len(lower_branch)):
            lower_branch[np].center -= delta
            for nv in range(len(lower_branch[np].vertices)):
                lower_branch[np].vertices[nv] -= delta
        for np in range(len(upper_branch)):
            upper_branch[np].center += delta
            for nv in range(len(upper_branch[np].vertices)):
                upper_branch[np].vertices[nv] += delta

    geometry = upper_branch + lower_branch

    if args.three_d:
        oxide_center = mp.Vector3(z=-0.5 * t_oxide)
        oxide_size = mp.Vector3(cell.size.x, cell.size.y, t_oxide)
        oxide_layer = [
            mp.Block(material=oxide, center=oxide_center, size=oxide_size)
        ]
        geometry = geometry + oxide_layer

    sources = [
        mp.EigenModeSource(
            src=mp.GaussianSource(fcen, fwidth=df),
            volume=src_vol,
            eig_band=1,
            eig_parity=mp.NO_PARITY if args.three_d else mp.EVEN_Y + mp.ODD_Z,
            eig_match_freq=True)
    ]

    sim = mp.Simulation(resolution=args.res,
                        cell_size=cell.size,
                        boundary_layers=[mp.PML(dpml)],
                        sources=sources,
                        geometry=geometry)

    mode1 = sim.add_mode_monitor(fcen, 0, 1, mp.ModeRegion(volume=p1))
    mode2 = sim.add_mode_monitor(fcen, 0, 1, mp.ModeRegion(volume=p2))
    mode3 = sim.add_mode_monitor(fcen, 0, 1, mp.ModeRegion(volume=p3))
    mode4 = sim.add_mode_monitor(fcen, 0, 1, mp.ModeRegion(volume=p4))

    sim.run(until_after_sources=100)

    # S parameters
    p1_coeff = sim.get_eigenmode_coefficients(
        mode1, [1],
        eig_parity=mp.NO_PARITY if args.three_d else mp.EVEN_Y +
        mp.ODD_Z).alpha[0, 0, 0]
    p2_coeff = sim.get_eigenmode_coefficients(
        mode2, [1],
        eig_parity=mp.NO_PARITY if args.three_d else mp.EVEN_Y +
        mp.ODD_Z).alpha[0, 0, 1]
    p3_coeff = sim.get_eigenmode_coefficients(
        mode3, [1],
        eig_parity=mp.NO_PARITY if args.three_d else mp.EVEN_Y +
        mp.ODD_Z).alpha[0, 0, 0]
    p4_coeff = sim.get_eigenmode_coefficients(
        mode4, [1],
        eig_parity=mp.NO_PARITY if args.three_d else mp.EVEN_Y +
        mp.ODD_Z).alpha[0, 0, 0]

    # transmittance
    p2_trans = abs(p2_coeff)**2 / abs(p1_coeff)**2
    p3_trans = abs(p3_coeff)**2 / abs(p1_coeff)**2
    p4_trans = abs(p4_coeff)**2 / abs(p1_coeff)**2

    print("trans:, {:.2f}, {:.6f}, {:.6f}, {:.6f}".format(
        args.d, p2_trans, p3_trans, p4_trans))
示例#26
0
    ]
geometry = [
    mp.Prism(vertices,height=thickness,material=Si) # taper structure
        ]

# Setup domain
resolution = 20
cell_size = mp.Vector3(12,4,0)
boundary_layers = [mp.PML(1.0)]

# Blast it with TE polarized source. Don't worry about an eigenmode source, 
# since we want to measure multiple modes.
sources = [
    mp.EigenModeSource(
    src=mp.GaussianSource(1/1.55,fwidth=0.1/1.55),
    center=[-length/2 - 2],
    size=[0,cell_size.y,cell_size.y],
    eig_parity=mp.ODD_Z+mp.EVEN_Y
    )
]

# Set up simulation object
sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=boundary_layers,
                        geometry=geometry,
                        default_material=SiO2,
                        sources=sources)

# Add the mode monitors
fcen = 1/1.55 # 1.55 microns
df = 0.1*fcen # 10% bandwidth
示例#27
0
def main(args):
    resolution = 30  # pixels/μm

    Si = mp.Medium(index=3.45)

    dpml = 1.0
    pml_layers = [mp.PML(dpml)]

    sx = 5
    sy = 3
    cell = mp.Vector3(sx + 2 * dpml, sy + 2 * dpml, 0)

    a = 1.0  # waveguide width
    s = args.s  # waveguide separation distance

    geometry = [
        mp.Block(center=mp.Vector3(-0.5 * (s + a)),
                 size=mp.Vector3(a, a, mp.inf),
                 material=Si),
        mp.Block(center=mp.Vector3(0.5 * (s + a)),
                 size=mp.Vector3(a, a, mp.inf),
                 material=Si)
    ]

    xodd = args.xodd
    symmetries = [
        mp.Mirror(mp.X, phase=-1.0 if xodd else 1.0),
        mp.Mirror(mp.Y, phase=-1.0)
    ]

    k_point = mp.Vector3(z=0.5)

    fcen = 0.22
    df = 0.06
    sources = [
        mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                  component=mp.Ey,
                  center=mp.Vector3(-0.5 * (s + a)),
                  size=mp.Vector3(a, a)),
        mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                  component=mp.Ey,
                  center=mp.Vector3(0.5 * (s + a)),
                  size=mp.Vector3(a, a),
                  amplitude=-1.0 if xodd else 1.0)
    ]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell,
                        boundary_layers=pml_layers,
                        geometry=geometry,
                        symmetries=symmetries,
                        k_point=k_point,
                        sources=sources)

    h = mp.Harminv(mp.Ey, mp.Vector3(0.5 * (s + a)), fcen, df)

    sim.run(mp.after_sources(h), until_after_sources=200)

    f = h.modes[0].freq
    print("freq:, {}, {}".format(s, f))

    sim.reset_meep()

    eig_sources = [
        mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df),
                           size=mp.Vector3(a, a),
                           center=mp.Vector3(-0.5 * (s + a)),
                           eig_kpoint=k_point,
                           eig_match_freq=True,
                           eig_parity=mp.ODD_Y),
        mp.EigenModeSource(src=mp.GaussianSource(f, fwidth=df),
                           size=mp.Vector3(a, a),
                           center=mp.Vector3(0.5 * (s + a)),
                           eig_kpoint=k_point,
                           eig_match_freq=True,
                           eig_parity=mp.ODD_Y,
                           amplitude=-1.0 if xodd else 1.0)
    ]

    sim.change_sources(eig_sources)

    flux_reg = mp.FluxRegion(direction=mp.Z,
                             center=mp.Vector3(),
                             size=mp.Vector3(1.2 * (2 * a + s), 1.2 * a))
    wvg_flux = sim.add_flux(f, 0, 1, flux_reg)

    force_reg1 = mp.ForceRegion(mp.Vector3(0.5 * s),
                                direction=mp.X,
                                weight=1.0,
                                size=mp.Vector3(y=a))
    force_reg2 = mp.ForceRegion(mp.Vector3(0.5 * s + a),
                                direction=mp.X,
                                weight=-1.0,
                                size=mp.Vector3(y=a))
    wvg_force = sim.add_force(f, 0, 1, force_reg1, force_reg2)

    sim.run(until_after_sources=5000)

    sim.display_fluxes(wvg_flux)
    sim.display_forces(wvg_force)
示例#28
0
lcen = 6.67
# mode frequency
fcen = 1 / lcen

symmetries = [mp.Mirror(mp.Y)]

for m in range(5):
    Lt = 2**m
    sx = dpml_x + Lw + Lt + Lw + dpml_x
    cell_size = mp.Vector3(sx, sy, 0)

    src_pt = mp.Vector3(-0.5 * sx + dpml_x + 0.2 * Lw, 0, 0)
    sources = [
        mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=0.2 * fcen),
                           component=mp.Ez,
                           center=src_pt,
                           size=mp.Vector3(0, sy - 2 * dpml_y, 0),
                           eig_match_freq=True,
                           eig_parity=mp.ODD_Z + mp.EVEN_Y)
    ]

    # straight waveguide
    vertices = [
        mp.Vector3(-0.5 * sx - 1, 0.5 * w1),
        mp.Vector3(0.5 * sx + 1, 0.5 * w1),
        mp.Vector3(0.5 * sx + 1, -0.5 * w1),
        mp.Vector3(-0.5 * sx - 1, -0.5 * w1)
    ]

    sim = mp.Simulation(
        resolution=resolution,
        cell_size=cell_size,
示例#29
0
deps = 1e-5
dp = deps * np.random.rand(Nx * Ny)

w = 1.0
waveguide_geometry = [
    mp.Block(material=silicon,
             center=mp.Vector3(),
             size=mp.Vector3(mp.inf, w, mp.inf))
]

fcen = 1 / 1.55
df = 0.23 * fcen
sources = [
    mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=df),
                       center=mp.Vector3(-0.5 * sxy + dpml, 0),
                       size=mp.Vector3(0, sxy),
                       eig_band=1,
                       eig_parity=eig_parity)
]


def forward_simulation(design_params, mon_type, frequencies=None):
    matgrid = mp.MaterialGrid(mp.Vector3(Nx, Ny),
                              mp.air,
                              silicon,
                              weights=design_params.reshape(Nx, Ny),
                              grid_type='U_MEAN')

    matgrid_geometry = [
        mp.Block(center=mp.Vector3(),
                 size=mp.Vector3(design_shape.x, design_shape.y, 0),
示例#30
0
    def __init__(self, objective_regions=[], objective=None,
                       basis=None, design_region=None,
                       cell_size=None, background_geometry=[], foreground_geometry=[],
                       sources=None, source_region=[],
                       extra_quantities=[], extra_regions=[]):
        """
        Parameters:

          objective regions (list of Subregion):
              subregions of the computational cell over which frequency-domain
              fields are tabulated and used to compute objective quantities

          objective (str):
              definition of the quantity to be maximized. This should be
              a mathematical expression in which the names of one or more
              objective quantities appear, and which should evaluate to
              a real number when numerical values are substituted for the
              names of all objective quantities.


          basis (Basis):
          design_region (Subregion):
              (precisely one of these should be non-None) Specification
              of function space for the design permittivity.

              In general, basis will be a caller-created instance of
              some subclass of meep.adjoint.Basis. Then the spatial
              extent of the design region is determined by basis and
              the design_region argument is ignored.

              As an alternative convenience convention, the caller
              may omit basis and set design_region; in this case,
              an appropriate basis for the given design_region is
              automatically created based on the values of various
              module-wide options such as 'element_type' and
              'element_length'. This convenience convention is
              only available for box-shaped (hyperrectangular)
              design regions.


          cell_size (Vector3)
          background_geometry (list of GeometricObject)
          foreground_geometry (list of GeometricObject)

              Size of computational cell and lists of GeometricObjects
              that {precede,follow} the design object in the overall geometry.


          sources (list of Source)
          source_region (Subregion)
              (Specify either sources OR source_region) Specification
              of forward source distribution, i.e. the source excitation(s) that
              produce the fields from which the objective function is computed.

              In general, sources will be an arbitrary caller-created list of Source
              objects, in which case source_region, source_component are ignored.

              As an alternative convenience convention, the caller may omit
              sources and instead specify source_region; in this case, a
              source distribution over the given region is automatically
              created based on the values of module-wide options (such
              as fcen, df, source_component, source_mode)


          extra_quantities  (list of str)
          extra_regions (list of Subregion)
              By default, the module will compute only those DFT fields and
              objective quantities needed to evaluate the specified objective
              function. These arguments may be used to specify lists of ancillary
              quantities and/or ancillary DFT cells (where 'ancillary' means
              'not needed to compute the objective function value) to be computed
              and reported/plotted as well.

        """

        from meep_adjoint import options

        #-----------------------------------------------------------------------
        # process convenience arguments:
        #  (a) if no basis was specified, create one using the given design
        #      region plus global option values
        #  (b) if no sources were specified, create one using the given source
        #      region plus global option values
        #-----------------------------------------------------------------------
        if basis is None:
            basis = FiniteElementBasis(region=design_region,
                                       element_length=options('element_length'),
                                       element_type=options('element_type'))
        design_region = basis.domain

        if not sources:
            f, df, m, c = [ options(s) for s in ['fcen', 'df', 'source_mode', 'source_component'] ]
            envelope    = mp.GaussianSource(f, fwidth=df)
            kws         = { 'center': V3(source_region.center), 'size': V3(source_region.size),
                            'src': envelope} #, 'eig_band': m, 'component': c }
            sources     = [ mp.EigenModeSource(eig_band=m,**kws) if m>0 else mp.Source(component=c, **kws) ]
        adjust_sources(sources)

        #-----------------------------------------------------------------------
        #initialize helper classes
        #-----------------------------------------------------------------------

        # DFTCells
        objective_cells = [ DFTCell(r) for r in objective_regions ]
        extra_cells     = [ DFTCell(r) for r in extra_regions ]
        design_cell     = DFTCell(design_region, E_CPTS)
        dft_cells       = objective_cells + extra_cells + [design_cell]

        # ObjectiveFunction
        obj_func        = ObjectiveFunction(fstr=objective,
                                            extra_quantities=extra_quantities)

        # initial values of (a) design variables, (b) the spatially-varying
        # permittivity function they define (the 'design function'), (c) the
        # GeometricObject describing a material body with this permittivity
        # (the 'design object'), and (d) mp.Simulation superposing the design
        # object on the rest of the caller's geometry.
        # Note that sources are not added to the simulation at this stage;
        # that is done on a just-in-time basis by internal methods of TimeStepper.
        beta_vector     = basis.project(options('eps_func'))
#        eps_func        = basis.parameterized_function(beta_vector)
        eps_func, set_coefficients = parameterized_function2(basis,beta_vector)
        design_object   = mp.Block(center=V3(design_region.center), size=V3(design_region.size),
                                   epsilon_func=eps_func)
        geometry        = background_geometry + [design_object] + foreground_geometry
        sim             = mp.Simulation(resolution=options['res'],
                                        boundary_layers=[mp.PML(options['dpml'])],
                                        cell_size=V3(cell_size), geometry=geometry)

        # TimeStepper
        self.stepper    = TimeStepper(obj_func, dft_cells, basis, eps_func, set_coefficients,
                                      sim, fwd_sources=sources)