Пример #1
0
    def init(self, no_bend=False):
        sx = 16
        sy = 32
        cell = mp.Vector3(sx, sy, 0)
        pad = 4
        w = 1
        wvg_ycen = -0.5 * (sy - w - (2 * pad))
        wvg_xcen = 0.5 * (sx - w - (2 * pad))
        height = 100

        if no_bend:
            no_bend_vertices = [mp.Vector3(-0.5 * sx - 5, wvg_ycen - 0.5 * w),
                                mp.Vector3(+0.5 * sx + 5, wvg_ycen - 0.5 * w),
                                mp.Vector3(+0.5 * sx + 5, wvg_ycen + 0.5 * w),
                                mp.Vector3(-0.5 * sx - 5, wvg_ycen + 0.5 * w)]

            geometry = [mp.Prism(no_bend_vertices, height, material=mp.Medium(epsilon=12))]
        else:
            bend_vertices = [mp.Vector3(-0.5 * sx, wvg_ycen - 0.5 * w),
                             mp.Vector3(wvg_xcen + 0.5 * w, wvg_ycen - 0.5 * w),
                             mp.Vector3(wvg_xcen + 0.5 * w, 0.5 * sy),
                             mp.Vector3(wvg_xcen - 0.5 * w, 0.5 * sy),
                             mp.Vector3(wvg_xcen - 0.5 * w, wvg_ycen + 0.5 * w),
                             mp.Vector3(-0.5 * sx, wvg_ycen + 0.5 * w)]

            geometry = [mp.Prism(bend_vertices, height, material=mp.Medium(epsilon=12))]

        fcen = 0.15
        df = 0.1
        sources = [mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ez,
                             center=mp.Vector3(1 + (-0.5 * sx), wvg_ycen), size=mp.Vector3(0, w))]

        pml_layers = [mp.PML(1.0)]
        resolution = 10
        nfreq = 100

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

        if no_bend:
            fr = mp.FluxRegion(center=mp.Vector3((sx / 2) - 1.5, wvg_ycen), size=mp.Vector3(0, w * 2))
        else:
            fr = mp.FluxRegion(center=mp.Vector3(wvg_xcen, (sy / 2) - 1.5), size=mp.Vector3(w * 2, 0))

        self.trans = self.sim.add_flux(fcen, df, nfreq, fr)
        refl_fr = mp.FluxRegion(center=mp.Vector3((-0.5 * sx) + 1.5, wvg_ycen),
                                size=mp.Vector3(0, w * 2))

        self.refl = self.sim.add_flux(fcen, df, nfreq, refl_fr)

        if no_bend:
            self.pt = mp.Vector3((sx / 2) - 1.5, wvg_ycen)
        else:
            self.pt = mp.Vector3(wvg_xcen, (sy / 2) - 1.5)
Пример #2
0
    def nonconvex_marching_squares(self, idx, npts):
        resolution = 25

        cell = mp.Vector3(10, 10)

        data_dir = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'data'))
        vertices_file = os.path.join(
            data_dir, 'nonconvex_prism_vertices{}.npz'.format(idx))
        vertices_obj = np.load(vertices_file)

        ## prism verticies precomputed from analytic "blob" shape using
        ## marching squares algorithm of skimage.measure.find_contours
        ## ref: https://github.com/NanoComp/meep/pull/1142
        vertices_data = vertices_obj["N{}".format(npts)]
        vertices = [mp.Vector3(v[0], v[1], 0) for v in vertices_data]

        geometry = [
            mp.Prism(vertices, height=mp.inf, material=mp.Medium(epsilon=12))
        ]

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

        sim.init_sim()

        prism_eps = sim.integrate_field_function([mp.Dielectric],
                                                 lambda r, eps: eps)

        print("epsilon-sum:, {} (prism-msq)".format(abs(prism_eps)))

        return prism_eps
Пример #3
0
    def init_sim(self, **kwargs):
        """
        Initializes the simulation. This has to be done after adding all structures in order to correctly determine the
        size of the simulation.

        :param kwargs: Parameters which are directly passed to Meep
        """
        z_min = np.min([
            structure['z_min'] for structure in self.structures
            if structure['structure']
        ])
        z_max = np.max([
            structure['z_max'] for structure in self.structures
            if structure['structure']
        ])

        bounds = geometric_union(
            (geometric_union(x['structure']) for x in self.structures)).bounds
        size = np.array(
            (bounds[2] - bounds[0], bounds[3] - bounds[1], (z_max - z_min)))
        self.center = np.round([(bounds[2] + bounds[0]) / 2,
                                (bounds[3] + bounds[1]) / 2,
                                (z_max + z_min) / 2])
        self.size = np.ceil(size + self.padding * 2 + self.pml_thickness * 2)
        if self.reduce_to_2d:
            self.center[2] = self.size[2] = 0

        structures = []
        for structure in self.structures:
            polygon = geometric_union(structure['structure'] + structure['extra_structures']) \
                .buffer(np.finfo(np.float32).eps, resolution=0).simplify(np.finfo(np.float32).eps)
            objs = shapely_collection_to_basic_objs(polygon)

            for obj in objs:
                if obj.is_empty:
                    continue
                for polygon in fracture_intelligently(obj, np.inf, np.inf):
                    structures += [
                        mp.Prism(vertices=[
                            mp.Vector3(
                                *point,
                                0 if self.reduce_to_2d else structure['z_min'])
                            for point in polygon.exterior.coords[:-1]
                        ],
                                 material=structure['material'],
                                 height=structure['z_max'] -
                                 structure['z_min'])
                    ]

        self.sim = mp.Simulation(mp.Vector3(*self.size),
                                 self.resolution,
                                 geometry=structures,
                                 geometry_center=mp.Vector3(*self.center),
                                 sources=self.sources,
                                 boundary_layers=[mp.PML(self.pml_thickness)],
                                 **kwargs)
        self.sim.init_sim()
Пример #4
0
    def convex_circle(self, npts, r, sym):
        resolution = 50

        cell = mp.Vector3(3, 3)

        ### prism vertices computed as equally-spaced points
        ### along the circumference of a circle with radius r
        angles = 2 * np.pi / npts * np.arange(npts)
        vertices = [
            mp.Vector3(r * np.cos(ang), r * np.sin(ang)) for ang in angles
        ]
        geometry = [
            mp.Prism(vertices, height=mp.inf, material=mp.Medium(epsilon=12))
        ]

        sim = mp.Simulation(
            cell_size=cell,
            geometry=geometry,
            symmetries=[mp.Mirror(direction=mp.X),
                        mp.Mirror(direction=mp.Y)] if sym else [],
            resolution=resolution)

        sim.init_sim()

        prism_eps = sim.integrate_field_function([mp.Dielectric],
                                                 lambda r, eps: eps)

        sim.reset_meep()

        geometry = [
            mp.Cylinder(radius=r,
                        center=mp.Vector3(),
                        height=mp.inf,
                        material=mp.Medium(epsilon=12))
        ]

        sim = mp.Simulation(
            cell_size=cell,
            geometry=geometry,
            symmetries=[mp.Mirror(direction=mp.X),
                        mp.Mirror(direction=mp.Y)] if sym else [],
            resolution=resolution)

        sim.init_sim()

        cyl_eps = sim.integrate_field_function([mp.Dielectric],
                                               lambda r, eps: eps)

        print(
            "epsilon-sum:, {} (prism-cyl), {} (cylinder), {} (relative error)".
            format(abs(prism_eps), abs(cyl_eps),
                   abs((prism_eps - cyl_eps) / cyl_eps)))

        return abs((prism_eps - cyl_eps) / cyl_eps)
Пример #5
0
    def convex_marching_squares(self, npts):
        resolution = 50

        cell = mp.Vector3(3, 3)

        data_dir = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'data'))
        vertices_file = os.path.join(data_dir, 'convex_prism_vertices.npz')
        vertices_obj = np.load(vertices_file)

        ## prism vertices precomputed for a circle of radius 1.0 using
        ## marching squares algorithm of skimage.measure.find_contours
        ## ref: https://github.com/NanoComp/meep/issues/1060
        vertices_data = vertices_obj["N{}".format(npts)]
        vertices = [mp.Vector3(v[0], v[1], 0) for v in vertices_data]

        geometry = [
            mp.Prism(vertices, height=mp.inf, material=mp.Medium(epsilon=12))
        ]

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

        sim.init_sim()

        prism_eps = sim.integrate_field_function([mp.Dielectric],
                                                 lambda r, eps: eps)

        sim.reset_meep()

        geometry = [
            mp.Cylinder(radius=1.0,
                        center=mp.Vector3(),
                        height=mp.inf,
                        material=mp.Medium(epsilon=12))
        ]

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

        sim.init_sim()

        cyl_eps = sim.integrate_field_function([mp.Dielectric],
                                               lambda r, eps: eps)

        print(
            "epsilon-sum:, {} (prism-msq), {} (cylinder), {} (relative error)".
            format(abs(prism_eps), abs(cyl_eps),
                   abs((prism_eps - cyl_eps) / cyl_eps)))

        return abs((prism_eps - cyl_eps) / cyl_eps)
Пример #6
0
    def setUp(self):
        resolution = 60
        self.cell_size = mp.Vector3(1.0, 1.0, 0)

        matgrid_resolution = 200
        matgrid_size = mp.Vector3(1.0, 1.0, mp.inf)
        Nx, Ny = int(matgrid_size.x * matgrid_resolution), int(
            matgrid_size.y * matgrid_resolution)
        x = np.linspace(-0.5 * matgrid_size.x, 0.5 * matgrid_size.x, Nx)
        y = np.linspace(-0.5 * matgrid_size.y, 0.5 * matgrid_size.y, Ny)
        xv, yv = np.meshgrid(x, y)
        rad = 0.201943
        w = 0.104283
        weights = np.logical_and(
            np.sqrt(np.square(xv) + np.square(yv)) > rad,
            np.sqrt(np.square(xv) + np.square(yv)) < rad + w,
            dtype=np.double)

        matgrid = mp.MaterialGrid(mp.Vector3(Nx, Ny),
                                  mp.air,
                                  mp.Medium(index=3.5),
                                  weights=weights,
                                  do_averaging=False,
                                  beta=0,
                                  eta=0.5)

        geometry = [
            mp.Cylinder(center=mp.Vector3(0.35, 0.1),
                        radius=0.1,
                        height=mp.inf,
                        material=mp.Medium(index=1.5)),
            mp.Block(center=mp.Vector3(-0.15, -0.2),
                     size=mp.Vector3(0.2, 0.24, mp.inf),
                     material=SiN),
            mp.Block(center=mp.Vector3(-0.2, 0.2),
                     size=mp.Vector3(0.4, 0.4, mp.inf),
                     material=matgrid),
            mp.Prism(vertices=[
                mp.Vector3(0.05, 0.45),
                mp.Vector3(0.32, 0.22),
                mp.Vector3(0.15, 0.10)
            ],
                     height=0.5,
                     material=Co)
        ]

        self.sim = mp.Simulation(resolution=resolution,
                                 cell_size=self.cell_size,
                                 geometry=geometry,
                                 eps_averaging=False)
        self.sim.init_sim()
Пример #7
0
def device_to_meep(device, mapping):
    # converts PHIDL to MEEP. You must give a layer mapping that can be derived from get_layer_mapping
    # TODO: partial etches. Currently this is only 2D
    geometry = list()
    for poly_grp in device.polygons:
        layer = poly_grp.layers[0]
        try:
            material = mapping[layer]
        except KeyError:
            print('layer {} not in meep mapping'.format(layer))
            continue
        if material is cell_material:
            cell = mp.Vector3(poly_grp.xsize, poly_grp.ysize)
            continue
        elif material is port_source:
            continue
        for poly in poly_grp.polygons:
            vertex_list = list()
            for vertex in poly:
                vertex_list.append(mp.Vector3(vertex[0], vertex[1]))
            geometry.append(mp.Prism(vertex_list, height=0, material=material))
    return cell, geometry
Пример #8
0
def get_simulation(
    component: Component,
    extend_ports_length: Optional[float] = 4.0,
    layer_stack: LayerStack = LAYER_STACK,
    res: int = 20,
    t_clad_top: float = 1.0,
    t_clad_bot: float = 1.0,
    tpml: float = 1.0,
    clad_material: str = "SiO2",
    is_3d: bool = False,
    wl_min: float = 1.5,
    wl_max: float = 1.6,
    wl_steps: int = 50,
    dfcen: float = 0.2,
    port_source_name: str = 1,
    port_field_monitor_name: str = 2,
    port_margin: float = 0.5,
    distance_source_to_monitors: float = 0.2,
) -> Dict[str, Any]:
    """Returns Simulation dict from gdsfactory.component

    based on meep directional coupler example
    https://meep.readthedocs.io/en/latest/Python_Tutorials/GDSII_Import/

    https://support.lumerical.com/hc/en-us/articles/360042095873-Metamaterial-S-parameter-extraction

    Args:
        component: gf.Component
        extend_ports_function: function to extend the ports for a component to ensure it goes beyond the PML
        layer_to_thickness: Dict of layer number (int, int) to thickness (um)
        res: resolution (pixels/um) For example: (10: 100nm step size)
        t_clad_top: thickness for cladding above core
        t_clad_bot: thickness for cladding below core
        tpml: PML thickness (um)
        clad_material: material for cladding
        is_3d: if True runs in 3D
        wavelengths: iterable of wavelengths to simulate
        dfcen: delta frequency
        sidewall_angle: in degrees
        port_source_name: input port name
        port_field_monitor_name:
        port_margin: margin on each side of the port
        distance_source_to_monitors: in (um) source goes before

    Returns:
        sim: simulation object

    Make sure you visualize the simulation region with gf.before you simulate a component

    .. code::

        import gdsfactory as gf
        import gmeep as gm

        c = gf.components.bend_circular()
        margin = 2
        cm = gm.add_monitors(c)
        gf.show(cm)

    """
    layer_to_thickness = layer_stack.get_layer_to_thickness()
    layer_to_material = layer_stack.get_layer_to_material()
    layer_to_zmin = layer_stack.get_layer_to_zmin()
    layer_to_sidewall_angle = layer_stack.get_layer_to_sidewall_angle()

    wavelengths = np.linspace(wl_min, wl_max, wl_steps)
    if port_source_name not in component.ports:
        warnings.warn(
            f"port_source_name={port_source_name} not in {component.ports.keys()}"
        )
        port_source = component.get_ports_list()[0]
        port_source_name = port_source.name
        warnings.warn(f"Selecting port_source_name={port_source_name} instead.")

    if port_field_monitor_name not in component.ports:
        warnings.warn(
            f"port_field_monitor_name={port_field_monitor_name} not in {component.ports.keys()}"
        )
        port_field_monitor = (
            component.get_ports_list()[0]
            if len(component.ports) < 2
            else component.get_ports_list()[1]
        )
        port_field_monitor_name = port_field_monitor.name
        warnings.warn(
            f"Selecting port_field_monitor_name={port_field_monitor_name} instead."
        )

    assert isinstance(
        component, Component
    ), f"component needs to be a gf.Component, got Type {type(component)}"

    component_extended = (
        gf.components.extension.extend_ports(
            component=component, length=extend_ports_length, centered=True
        )
        if extend_ports_length
        else component
    )

    component = component.ref()
    component.x = 0
    component.y = 0

    gf.show(component_extended)

    component_extended.flatten()
    component_extended = component_extended.ref()

    # geometry_center = [component_extended.x, component_extended.y]
    # geometry_center = [0, 0]
    # print(geometry_center)

    layers_thickness = [
        layer_to_thickness[layer]
        for layer in component.get_layers()
        if layer in layer_to_thickness
    ]

    t_core = max(layers_thickness)
    cell_thickness = tpml + t_clad_bot + t_core + t_clad_top + tpml if is_3d else 0

    cell_size = mp.Vector3(
        component.xsize + 2 * tpml,
        component.ysize + 2 * tpml,
        cell_thickness,
    )

    geometry = []
    layer_to_polygons = component_extended.get_polygons(by_spec=True)
    for layer, polygons in layer_to_polygons.items():
        if layer in layer_to_thickness and layer in layer_to_material:
            height = layer_to_thickness[layer] if is_3d else mp.inf
            zmin_um = layer_to_zmin[layer] if is_3d else 0
            # center = mp.Vector3(0, 0, (zmin_um + height) / 2)

            for polygon in polygons:
                vertices = [mp.Vector3(p[0], p[1], zmin_um) for p in polygon]
                material_name = layer_to_material[layer]
                material = get_material(name=material_name)
                geometry.append(
                    mp.Prism(
                        vertices=vertices,
                        height=height,
                        sidewall_angle=layer_to_sidewall_angle[layer],
                        material=material,
                        # center=center
                    )
                )

    freqs = 1 / wavelengths
    fcen = np.mean(freqs)
    frequency_width = dfcen * fcen

    # Add source
    port = component.ports[port_source_name]
    angle = port.orientation
    width = port.width + 2 * port_margin
    size_x = width * abs(np.sin(angle * np.pi / 180))
    size_y = width * abs(np.cos(angle * np.pi / 180))
    size_x = 0 if size_x < 0.001 else size_x
    size_y = 0 if size_y < 0.001 else size_y
    size_z = cell_thickness - 2 * tpml if is_3d else 20
    size = [size_x, size_y, size_z]
    center = port.center.tolist() + [0]  # (x, y, z=0)

    field_monitor_port = component.ports[port_field_monitor_name]
    field_monitor_point = field_monitor_port.center.tolist() + [0]  # (x, y, z=0)

    sources = [
        mp.EigenModeSource(
            src=mp.GaussianSource(fcen, fwidth=frequency_width),
            size=size,
            center=center,
            eig_band=1,
            eig_parity=mp.NO_PARITY if is_3d else mp.EVEN_Y + mp.ODD_Z,
            eig_match_freq=True,
        )
    ]

    sim = mp.Simulation(
        resolution=res,
        cell_size=cell_size,
        boundary_layers=[mp.PML(tpml)],
        sources=sources,
        geometry=geometry,
        default_material=get_material(name=clad_material),
        # geometry_center=geometry_center,
    )

    # Add port monitors dict
    monitors = {}
    for port_name in component.ports.keys():
        port = component.ports[port_name]
        angle = port.orientation
        width = port.width + 2 * port_margin
        size_x = width * abs(np.sin(angle * np.pi / 180))
        size_y = width * abs(np.cos(angle * np.pi / 180))
        size_x = 0 if size_x < 0.001 else size_x
        size_y = 0 if size_y < 0.001 else size_y
        size = mp.Vector3(size_x, size_y, size_z)
        size = [size_x, size_y, size_z]

        # if monitor has a source move monitor inwards
        length = -distance_source_to_monitors if port_name == port_source_name else 0
        xy_shifted = move_polar_rad_copy(
            np.array(port.center), angle=angle * np.pi / 180, length=length
        )
        center = xy_shifted.tolist() + [0]  # (x, y, z=0)
        m = sim.add_mode_monitor(freqs, mp.ModeRegion(center=center, size=size))
        m.z = 0
        monitors[port_name] = m
    return dict(
        sim=sim,
        cell_size=cell_size,
        freqs=freqs,
        monitors=monitors,
        sources=sources,
        field_monitor_point=field_monitor_point,
        port_source_name=port_source_name,
    )
    os.makedirs(dFolder)

w = w_actual/a_actual
a = 1
hx = hx_actual/a_actual
hy = hy_actual/a_actual
h = w/2/np.tan(theta*np.pi/180)


####################################################################

#sets size of lattice to be 3D; 1by1by1
geometry_lattice = mp.Lattice(size=mp.Vector3(a, w*3, h*3))

#https://meep.readthedocs.io/en/latest/Python_User_Interface/#prism
beam = mp.Prism([mp.Vector3(0,-w/2, h/2), mp.Vector3(0,w/2, h/2), mp.Vector3(0,0, -h/2)], a, axis=mp.Vector3(1,0,0), 
    center=None, material=mp.Medium(epsilon=n**2))
#Diamond: n = 2.4063; n^2 = ep_r


hole = mp.Ellipsoid(size=[hx, hy, mp.inf], material=mp.Medium(epsilon=1))

geometry = [beam, hole]

#Symmetry points
k_points = [
    mp.Vector3(0,0,0),               # Gamma
    mp.Vector3(0.5,0,0),          # X (normalized to a?)
]
#how many points to solve for between each specified point above
k_points = mp.interpolate(kpt_resolution, k_points) 
Пример #10
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))
Пример #11
0
                           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,
        boundary_layers=boundary_layers,
        geometry=[mp.Prism(vertices, height=mp.inf, material=Si)],
        sources=sources,
        symmetries=symmetries)

    mon_pt = mp.Vector3(-0.5 * sx + dpml_x + 0.7 * Lw, 0, 0)
    flux = sim.add_flux(
        fcen, 0, 1,
        mp.FluxRegion(center=mon_pt, size=mp.Vector3(0, sy - 2 * dpml_y, 0)))

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

    res = sim.get_eigenmode_coefficients(flux, [1],
                                         eig_parity=mp.ODD_Z + mp.EVEN_Y)
    incident_coeffs = res.alpha
    incident_flux = mp.get_fluxes(flux)
Пример #12
0
    mp.Vector3(-2 / 3 * r_cen1, 2 / 3 * r_cen1),
    mp.Vector3(2 / 3 * r_cen1, 4 / 3 * r_cen1)
]

vertices_cen2 = [
    mp.Vector3(4 / 3 * r_cen2, 2 / 3 * r_cen2),
    mp.Vector3(2 / 3 * r_cen2, -2 / 3 * r_cen2),
    mp.Vector3(-2 / 3 * r_cen2, -4 / 3 * r_cen2),
    mp.Vector3(-4 / 3 * r_cen2, -2 / 3 * r_cen2),
    mp.Vector3(-2 / 3 * r_cen2, 2 / 3 * r_cen2),
    mp.Vector3(2 / 3 * r_cen2, 4 / 3 * r_cen2)
]

geometry = [
    mp.Prism(vertices,
             center=mp.Vector3(1 / 3, 1 / 3),
             height=mp.inf,
             material=mp.Medium(epsilon=1)),
    mp.Prism(vertices,
             center=mp.Vector3(1 / 3, 0),
             height=mp.inf,
             material=mp.Medium(epsilon=1)),
    mp.Prism(vertices,
             center=mp.Vector3(0, -1 / 3),
             height=mp.inf,
             material=mp.Medium(epsilon=1)),
    mp.Prism(vertices,
             center=mp.Vector3(-1 / 3, -1 / 3),
             height=mp.inf,
             material=mp.Medium(epsilon=1)),
    mp.Prism(vertices,
             center=mp.Vector3(-1 / 3, 0),
Пример #13
0
geometry = []
q = miepy.quaternion.from_spherical_coords(0, 0)
R = miepy.quaternion.as_rotation_matrix(q)

X = W / np.sqrt(2 * (1 - np.cos(2 * np.pi / 3)))
vertices = [
    meep.Vector3(X, 0, 0),
    meep.Vector3(-X / 2,
                 np.sqrt(3) / 2 * X, 0),
    meep.Vector3(-X / 2, -np.sqrt(3) / 2 * X, 0)
]
geometry.append(
    meep.Prism(center=meep.Vector3(0, 0, 0),
               height=H,
               vertices=vertices,
               axis=meep.Vector3(0, 0, 1),
               material=material))

D = W * 3**.5 / 2
box = [D, D, H]
resolution = 1 / (8 * nm)
medium = meep.Medium(index=1)

fcen, df = meep_ext.freq_data(1 / (400 * nm), 1 / (1000 * nm))
nfreq = 40
polarization = 'x'

src_time = meep.GaussianSource(frequency=1.3 / um, fwidth=4.0 / um)
if polarization == 'x':
    source = lambda sim: meep_ext.x_polarized_plane_wave(sim, src_time)
Пример #14
0
def get_mode_solver_coupler(
    wg_width: float = 0.5,
    gap: float = 0.2,
    wg_widths: Optional[Floats] = None,
    gaps: Optional[Floats] = None,
    wg_thickness: float = 0.22,
    slab_thickness: float = 0.0,
    ncore: float = 3.47,
    nclad: float = 1.44,
    nslab: Optional[float] = None,
    ymargin: float = 2.0,
    sz: float = 2.0,
    resolution: int = 32,
    nmodes: int = 4,
    sidewall_angles: Union[Tuple[float, ...], float] = None,
    # sidewall_taper: int = 1,
) -> mpb.ModeSolver:
    """Returns a mode_solver simulation.

    Args:
        wg_width: wg_width (um)
        gap:
        wg_widths: list or tuple of waveguide widths.
        gaps: list or tuple of waveguide gaps.
        wg_thickness: wg height (um)
        slab_thickness: thickness for the waveguide slab
        ncore: core material refractive index
        nclad: clad material refractive index
        nslab: Optional slab material refractive index. Defaults to ncore.
        ymargin: margin in y.
        sz: simulation region thickness (um)
        resolution: resolution (pixels/um)
        nmodes: number of modes
        sidewall_angles: waveguide sidewall angle (radians),
            tapers from wg_width at top of slab, upwards, to top of waveguide

    ::

          _____________________________________________________
          |
          |
          |         widths[0]                 widths[1]
          |     <---------->     gaps[0]    <---------->
          |      ___________ <------------->  ___________     _
          |     |           |               |           |     |
        sz|_____|           |_______________|           |_____|
          |                                                   | wg_thickness
          |slab_thickness                                     |
          |___________________________________________________|
          |
          |<--->                                         <--->
          |ymargin                                       ymargin
          |____________________________________________________
          <--------------------------------------------------->
                                   sy



    """
    wg_widths = wg_widths or (wg_width, wg_width)
    gaps = gaps or (gap, )
    material_core = mp.Medium(index=ncore)
    material_clad = mp.Medium(index=nclad)
    material_slab = mp.Medium(index=nslab or ncore)

    # Define the computational cell.  We'll make x the propagation direction.
    # the other cell sizes should be big enough so that the boundaries are
    # far away from the mode field.

    sy = np.sum(wg_widths) + np.sum(gaps) + 2 * ymargin
    geometry_lattice = mp.Lattice(size=mp.Vector3(0, sy, sz))

    geometry = []

    y = -sy / 2 + ymargin

    gaps = list(gaps) + [0]
    for i, wg_width in enumerate(wg_widths):
        if sidewall_angles:
            geometry.append(
                mp.Prism(
                    vertices=[
                        mp.Vector3(y=y, z=slab_thickness),
                        mp.Vector3(y=y + wg_width, z=slab_thickness),
                        mp.Vector3(x=1, y=y + wg_width, z=slab_thickness),
                        mp.Vector3(x=1, y=y, z=slab_thickness),
                    ],
                    height=wg_thickness - slab_thickness,
                    center=mp.Vector3(
                        y=y + wg_width / 2,
                        z=slab_thickness + (wg_thickness - slab_thickness) / 2,
                    ),
                    # If only 1 angle is specified, use it for all waveguides
                    sidewall_angle=sidewall_angles if len(
                        np.unique(sidewall_angles)) == 1 else
                    sidewall_angles[i],
                    # axis=mp.Vector3(z=sidewall_taper),
                    material=material_core,
                ))
        else:
            geometry.append(
                mp.Block(
                    size=mp.Vector3(mp.inf, wg_width, wg_thickness),
                    material=material_core,
                    center=mp.Vector3(y=y + wg_width / 2, z=wg_thickness / 2),
                ))

        y += gaps[i] + wg_width

    # define the 2D blocks for the strip and substrate
    geometry += [
        mp.Block(
            size=mp.Vector3(mp.inf, mp.inf, slab_thickness),
            material=material_slab,
            center=mp.Vector3(z=slab_thickness / 2),
        ),
    ]

    # The k (i.e. beta, i.e. propagation constant) points to look at, in
    # units of 2*pi/um.  We'll look at num_k points from k_min to k_max.
    num_k = 9
    k_min = 0.1
    k_max = 3.0
    k_points = mp.interpolate(num_k, [mp.Vector3(k_min), mp.Vector3(k_max)])

    # Increase this to see more modes.  (The guided ones are the ones below the
    # light line, i.e. those with frequencies < kmag / 1.45, where kmag
    # is the corresponding column in the output if you grep for "freqs:".)
    # use this prefix for output files

    wg_widths_str = "_".join([str(i) for i in wg_widths])
    gaps_str = "_".join([str(i) for i in gaps])
    filename_prefix = (
        tmp /
        f"coupler_{wg_widths_str}_{gaps_str}_{wg_thickness}_{slab_thickness}")

    mode_solver = mpb.ModeSolver(
        geometry_lattice=geometry_lattice,
        geometry=geometry,
        k_points=k_points,
        resolution=resolution,
        num_bands=nmodes,
        filename_prefix=str(filename_prefix),
        default_material=material_clad,
    )
    mode_solver.nmodes = nmodes
    mode_solver.info = dict(
        wg_widths=wg_widths,
        gaps=gaps,
        wg_thickness=wg_thickness,
        slab_thickness=slab_thickness,
        ncore=ncore,
        nclad=nclad,
        sy=sy,
        sz=sz,
        resolution=resolution,
        nmodes=nmodes,
    )
    return mode_solver
Пример #15
0
def get_mode_solver_rib(
    wg_width: float = 0.45,
    wg_thickness: float = 0.22,
    slab_thickness: float = 0.0,
    ncore: float = 3.47,
    nclad: float = 1.44,
    nslab: Optional[float] = None,
    sy: float = 2.0,
    sz: float = 2.0,
    resolution: int = 32,
    nmodes: int = 4,
    sidewall_angle: float = None,
    # sidewall_taper: int = 1,
) -> mpb.ModeSolver:
    """Returns a mode_solver simulation.

    Args:
        wg_width: wg_width (um)
        wg_thickness: wg height (um)
        slab_thickness: thickness for the waveguide slab
        ncore: core material refractive index
        nclad: clad material refractive index
        nslab: Optional slab material refractive index. Defaults to ncore.
        sy: simulation region width (um)
        sz: simulation region height (um)
        resolution: resolution (pixels/um)
        nmodes: number of modes
        sidewall_angle: waveguide sidewall angle (radians),
            tapers from wg_width at top of slab, upwards, to top of waveguide

    ::

        . = origin

          __________________________
          |
          |
          |         width
          |     <---------->
          |      ___________   _ _ _
          |     |           |       |
        sz|_____|           |_______|
          |                         | wg_thickness
          |slab_thickness           |
          |___________._____________|
          |
          |
          |__________________________
          <------------------------>
                        sy
    """
    material_core = mp.Medium(index=ncore)
    material_clad = mp.Medium(index=nclad)
    material_slab = mp.Medium(index=nslab or ncore)

    # Define the computational cell.  We'll make x the propagation direction.
    # the other cell sizes should be big enough so that the boundaries are
    # far away from the mode field.
    geometry_lattice = mp.Lattice(size=mp.Vector3(0, sy, sz))

    geometry = []

    # define the 2d blocks for the strip and substrate
    if sidewall_angle:
        geometry.append(
            mp.Prism(
                vertices=[
                    mp.Vector3(y=-wg_width / 2, z=slab_thickness),
                    mp.Vector3(y=wg_width / 2, z=slab_thickness),
                    mp.Vector3(x=1, y=wg_width / 2, z=slab_thickness),
                    mp.Vector3(x=1, y=-wg_width / 2, z=slab_thickness),
                ],
                height=wg_thickness - slab_thickness,
                center=mp.Vector3(z=slab_thickness +
                                  (wg_thickness - slab_thickness) / 2, ),
                # If only 1 angle is specified, use it for all waveguides
                sidewall_angle=sidewall_angle,
                # axis=mp.Vector3(z=sidewall_taper),
                material=material_core,
            ))
    else:
        geometry.append(
            mp.Block(
                size=mp.Vector3(mp.inf, wg_width, wg_thickness),
                material=material_core,
                center=mp.Vector3(z=wg_thickness / 2),
            ))
        # uncomment this for not oxide cladded waveguides
        # geometry.append(
        # mp.Block(
        #     size=mp.Vector3(mp.inf, mp.inf, 0.5 * (sz - wg_thickness)),
        #     center=mp.Vector3(z=0.25 * (sz + wg_thickness)),
        #     material=material_clad,
        # ),
        # )

    geometry += [
        mp.Block(
            size=mp.Vector3(mp.inf, mp.inf, slab_thickness),
            material=material_slab,
            center=mp.Vector3(z=slab_thickness / 2),
        ),
    ]

    # The k (i.e. beta, i.e. propagation constant) points to look at, in
    # units of 2*pi/um.  We'll look at num_k points from k_min to k_max.
    num_k = 9
    k_min = 0.1
    k_max = 3.0
    k_points = mp.interpolate(num_k, [mp.Vector3(k_min), mp.Vector3(k_max)])

    # Increase this to see more modes.  (The guided ones are the ones below the
    # light line, i.e. those with frequencies < kmag / 1.45, where kmag
    # is the corresponding column in the output if you grep for "freqs:".)
    # use this prefix for output files

    filename_prefix = tmp / f"rib_{wg_width}_{wg_thickness}_{slab_thickness}"

    mode_solver = mpb.ModeSolver(
        geometry_lattice=geometry_lattice,
        geometry=geometry,
        k_points=k_points,
        resolution=resolution,
        num_bands=nmodes,
        default_material=material_clad,
        filename_prefix=str(filename_prefix),
    )
    mode_solver.nmodes = nmodes
    mode_solver.info = dict(
        wg_width=wg_width,
        wg_thickness=wg_thickness,
        slab_thickness=slab_thickness,
        ncore=ncore,
        nclad=nclad,
        sy=sy,
        sz=sz,
        resolution=resolution,
        nmodes=nmodes,
    )
    return mode_solver
Пример #16
0
                mp.Vector3(-r_cen1,  1/3**0.5*r_cen1)]

vertices_cen2 = [mp.Vector3(     0,  2/(3**0.5)*r_cen2),
                mp.Vector3( r_cen2,  1/3**0.5*r_cen2),
                mp.Vector3( r_cen2, -1/3**0.5*r_cen2),
                mp.Vector3(     0, -2/3**0.5*r_cen2),
                mp.Vector3(-r_cen2, -1/3**0.5*r_cen2),
                mp.Vector3(-r_cen2,  1/3**0.5*r_cen2)]


geometry = []

for i in range(2):
    for j in range(N):
        center = (-1/2+i+1/2*(j%2),(-N+j)*3**0.5/2)
        geometry +=[mp.Prism(vertices_air, center=mp.Vector3( center[0]+1/3,center[1]), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_air, center=mp.Vector3( center[0]-1/3,center[1]), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_air, center=mp.Vector3( center[0]+1/6,center[1]+3**.5/6), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_air, center=mp.Vector3( center[0]-1/6,center[1]+3**.5/6), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_air, center=mp.Vector3( center[0]+1/6,center[1]-3**.5/6), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_air, center=mp.Vector3( center[0]-1/6,center[1]-3**.5/6), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_cen1,center=mp.Vector3( center[0] + 0,center[1]+  0), height = mp.inf, material=mp.Medium(epsilon=eps_outer_1)),
                    mp.Prism(vertices_cen2,center=mp.Vector3( center[0] + 0,center[1]+  0), height = mp.inf, material=mp.Medium(epsilon=eps_inner_1))]


for i in range(2):
    for j in range(N):
        center = (-1/2+i+1/2*(j%2),(j)*3**0.5/2)
        geometry +=[mp.Prism(vertices_air, center=mp.Vector3( center[0]+1/3,center[1]), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_air, center=mp.Vector3( center[0]-1/3,center[1]), height = mp.inf, material=mp.Medium(epsilon=1)),
                    mp.Prism(vertices_air, center=mp.Vector3( center[0]+1/6,center[1]+3**.5/6), height = mp.inf, material=mp.Medium(epsilon=1)),
Пример #17
0
    mp.Vector3(r_air, 1 / 3**0.5 * r_air)
]

vertices_ll = [
    mp.Vector3(0, 0),
    mp.Vector3(0, 2 / (3**0.5) * r_air),
    mp.Vector3(-r_air, 1 / 3**0.5 * r_air),
    mp.Vector3(-r_air, -1 / 3**0.5 * r_air)
]

for i in range(2):
    for j in range(N):
        center = (-1 / 2 + i + 1 / 2 * (j % 2), (-N + j) * 3**0.5 / 2)
        geometry += [
            mp.Prism(vertices_hex,
                     center=mp.Vector3(center[0], center[1]),
                     height=mp.inf,
                     material=mp.Medium(epsilon=eps_cen_1)),
            mp.Prism(vertices_l,
                     center=mp.Vector3(
                         center[0],
                         center[1] - 3**.5 / 3 + 1 / 3**0.5 * r_air),
                     height=mp.inf,
                     material=mp.Medium(epsilon=eps_back_1)),
            mp.Prism(vertices_r,
                     center=mp.Vector3(
                         center[0],
                         center[1] + 3**.5 / 3 - 1 / 3**0.5 * r_air),
                     height=mp.inf,
                     material=mp.Medium(epsilon=eps_back_1)),
            mp.Prism(vertices_ul,
                     center=mp.Vector3(
Пример #18
0
def main(args):
    """
    Args:
       * **fields** (boolean): If true, outputs the fields at the relevant waveguide cross-sections (top-down and side-view)
       * **output_directory** (string): Name of the output directory (for storing the fields)
       * **eps_input_file** (string): Name of the hdf5 file that defines the geometry through prisms
       * **input_pol** (string): Either "TE", or "TM", corresponding to the desired input mode.  Defaults to "TE"
       * **res** (int): Resolution of the MEEP simulation
       * **nfreq** (int): The number of wavelength points to record in the transmission/reflection spectra
       * **input_direction** (1 or -1): Direction of propagation for the input eigenmode.  If +1, goes in +x, else if -1, goes in -x.  Defaults to +1.
       * **dpml** (float): Length (in microns) of the perfectly-matched layer (PML) at simulation boundaries.  Defaults to 0.5 um.
       * **wl_center** (float): Center wavelength (in microns)
       * **wl_span** (float): Wavelength span (determines the pulse width)
       * **port_vcenter** (float): Vertical center of the waveguide
       * **port_height** (float): Height of the port cross-section (flux plane)
       * **port_width** (float): Width of the port cross-section (flux plane)
       * **source_offset** (float): Offset (in x-direction) between reflection monitor and source.  Defaults to 0.1 um.
       * **center_x** (float): x-coordinate of the center of the simulation region
       * **center_y** (float): y-coordinate of the center of the simulation region
       * **center_z** (float): z-coordinate of the center of the simulation region
       * **sx** (float): Size of the simulation region in x-direction
       * **sx** (float): Size of the simulation region in y-direction
       * **sz** (float): Size of the simulation region in z-direction
       * **port_coords** (list): List of the port coordinates (variable length), in the format [x1, y1, x2, y2, x3, y3, ...] (*must* be even)
    """
    #Boolean inputs
    fields = args.fields

    #String inputs
    output_directory = args.output_directory
    eps_input_file = args.eps_input_file
    input_pol = args.input_pol

    #Int inputs
    res = args.res
    nfreq = args.nfreq
    input_direction = args.input_direction

    #Float inputs
    dpml = args.dpml
    wl_center = args.wl_center
    wl_span = args.wl_span
    port_vcenter = args.port_vcenter
    port_height = args.port_height
    port_width = args.port_width
    source_offset = args.source_offset
    center_x, center_y, center_z = args.center_x, args.center_y, args.center_z
    sx, sy, sz = args.sx, args.sy, args.sz

    #List of floats
    port_coords = [float(x) for x in args.port_coords[0].split(" ")]
    ports = [(port_coords[2 * i], port_coords[2 * i + 1])
             for i in range(int(len(port_coords) / 2))]

    if input_pol == "TE":
        parity = mp.ODD_Z
    elif input_pol == "TM":
        parity = mp.EVEN_Z
    else:
        raise ValueError(
            "Warning! Improper value of 'input_pol' was passed to mcts.py (input_pol given ="
            + str(input_pol) + ")")

    if len(port_coords) % 2 != 0:
        raise ValueError(
            "Warning! Improper port_coords was passed to `meep_compute_transmission_spectra`.  Must be even number of port_coords in [x1, y1, x2, y2, ..] format."
        )

    # Setup the simulation geometries

    prism_objects = get_prism_objects(eps_input_file)
    geometry = []
    for p in prism_objects:
        #        print('vertices='+str(p['vlist']))
        #        print('axis = '+str(mp.Vector3(0,1,0)))
        #        print('height = '+str(p['height']))
        print('material = ' + str(p['eps']))
        #        print('\n')
        geometry.append(
            mp.Prism(p['vlist'],
                     axis=mp.Vector3(0, 1, 0),
                     height=p['height'],
                     material=mp.Medium(epsilon=p['eps'])))

    # Setup the simulation sources
    fmax = 1.0 / (wl_center - 0.5 * wl_span)
    fmin = 1.0 / (wl_center + 0.5 * wl_span)
    fcen = (fmax + fmin) / 2.0
    df = fmax - fmin
    if abs(abs(input_direction) - 1) > 1E-6:
        print(input_direction)
        raise ValueError("Warning! input_direction is not +1 or -1.")

    # Use first port in 'ports' as the location of the eigenmode source
    sources = [
        mp.EigenModeSource(
            src=mp.GaussianSource(fcen, fwidth=df, cutoff=30),
            component=mp.ALL_COMPONENTS,
            size=mp.Vector3(0, 3 * float(port_height), 3 * float(port_width)),
            center=mp.Vector3(ports[0][0] + source_offset - center_x,
                              float(port_vcenter) - center_y,
                              ports[0][1] - center_z),
            eig_match_freq=True,
            eig_parity=parity,
            eig_kpoint=mp.Vector3(float(input_direction) * wl_center, 0, 0),
            eig_resolution=2 * res if res > 16 else 32,
        )
    ]

    # Setup the simulation
    sim = mp.Simulation(cell_size=mp.Vector3(sx, sy, sz),
                        boundary_layers=[mp.PML(dpml)],
                        geometry=geometry,
                        sources=sources,
                        dimensions=3,
                        resolution=res,
                        filename_prefix=False)
    """ Add power flux monitors """
    print("ADDING FLUX MONITORS")
    flux_plane_objects = []

    for port in ports:
        flux_region = mp.FluxRegion(size=mp.Vector3(0, float(port_height),
                                                    float(port_width)),
                                    center=mp.Vector3(
                                        float(port[0]) - center_x,
                                        float(port_vcenter) - center_y,
                                        float(port[1]) - center_z))
        fpo = sim.add_flux(fcen, df, nfreq, flux_region)
        flux_plane_objects.append(fpo)

    sim.use_output_directory(str(output_directory))
    """ Run the simulation """
    """ Monitor the amplitude in the center of the structure """
    decay_pt = mp.Vector3(0, port_vcenter, 0)

    sv = mp.Volume(size=mp.Vector3(sx, sy, 0), center=mp.Vector3(0, 0, 0))
    tv = mp.Volume(size=mp.Vector3(sx, 0, sz),
                   center=mp.Vector3(0, port_vcenter, 0))

    print("RUNNING SIMULATION")

    if fields:
        sim.run(mp.at_beginning(mp.output_epsilon),
                mp.at_beginning(
                    mp.with_prefix(str("sideview-"),
                                   mp.in_volume(sv, mp.output_epsilon))),
                mp.at_beginning(
                    mp.with_prefix(str("topview-"),
                                   mp.in_volume(tv, mp.output_epsilon))),
                mp.at_every(
                    1.0,
                    mp.to_appended(str("ez-sideview"),
                                   mp.in_volume(sv, mp.output_efield_z))),
                mp.at_every(
                    1.0,
                    mp.to_appended(str("ez-topview"),
                                   mp.in_volume(tv, mp.output_efield_z))),
                until_after_sources=mp.stop_when_fields_decayed(
                    20, mp.Ez, decay_pt, 1e-4))
    else:
        sim.run(until_after_sources=mp.stop_when_fields_decayed(
            20, mp.Ez, decay_pt, 1e-4))

    sim.display_fluxes(*flux_plane_objects)

    print("FINISHED SIMULATION")
Пример #19
0
 def geometry(self):
     return [
         mp.Prism([Vector3(*xy) for xy in p.exterior.coords[:-1]],
                  mp.inf,
                  material=self.shape_material) for p in self.polygons
     ]
Пример #20
0
def sim(queryrow, src_angle, nm_val, src_pol):
    global resolution
    result_df = pd.DataFrame(columns=result.columns)

    dpml = 1.0  # PML length
    dair = 4.0  # padding length between PML and grating
    dsub = 3.0  # substrate thickness
    d = queryrow["period"]  # grating period
    h = queryrow["height"]  # grating height
    g = queryrow["gap"]  # grating gap
    theta_1 = math.radians(queryrow["theta_1"])  # grating sidewall angle #1
    theta_2 = math.radians(queryrow["theta_2"])  # grating sidewall angle #2
    transmittance = 0

    sx = dpml + dair + h + dsub + dpml
    sy = d

    cell_size = mp.Vector3(sx, sy, 0)
    pml_layers = [mp.Absorber(thickness=dpml, direction=mp.X)]

    wvl = 0.5  # center wavelength
    fcen = 1 / wvl  # center frequency
    df = 0.05 * fcen  # frequency width

    ng = 1.716  # episulfide refractive index @ 0.532 um
    glass = mp.Medium(index=ng)

    if src_pol == 1:
        src_cmpt = mp.Ez
        eig_parity = mp.ODD_Z
    elif src_pol == 2:
        src_cmpt = mp.Hz
        eig_parity = mp.EVEN_Z
    else:
        sys.exit("error: src_pol={} is invalid".format(args.src_pol))

    # rotation angle of incident planewave source; CCW about Z axis, 0 degrees along +X axis
    theta_src = math.radians(src_angle)

    # k (in source medium) with correct length (plane of incidence: XY)
    k = mp.Vector3(math.cos(theta_src), math.sin(theta_src), 0).scale(fcen)
    if theta_src == 0:
        k = mp.Vector3(0, 0, 0)

    def pw_amp(k, x0):
        def _pw_amp(x):
            return cmath.exp(1j * 2 * math.pi * k.dot(x + x0))

        return _pw_amp

    src_pt = mp.Vector3(-0.5 * sx + dpml + 0.2 * dair, 0, 0)
    sources = [
        mp.Source(mp.GaussianSource(fcen, fwidth=df),
                  component=src_cmpt,
                  center=src_pt,
                  size=mp.Vector3(0, sy, 0),
                  amp_func=pw_amp(k, src_pt))
    ]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=pml_layers,
                        k_point=k,
                        sources=sources)

    refl_pt = mp.Vector3(-0.5 * sx + dpml + 0.7 * dair, 0, 0)
    refl_flux = sim.add_flux(
        fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0, sy, 0)))

    sim.run(until_after_sources=100)

    input_flux = mp.get_fluxes(refl_flux)
    input_flux_data = sim.get_flux_data(refl_flux)

    sim.reset_meep()

    geometry = [
        mp.Block(material=glass,
                 size=mp.Vector3(dpml + dsub, mp.inf, mp.inf),
                 center=mp.Vector3(0.5 * sx - 0.5 * (dpml + dsub), 0, 0)),
        mp.Prism(material=glass,
                 height=mp.inf,
                 vertices=[
                     mp.Vector3(0.5 * sx - dpml - dsub, 0.5 * sy, 0),
                     mp.Vector3(0.5 * sx - dpml - dsub - h,
                                0.5 * sy - h * math.tan(theta_2), 0),
                     mp.Vector3(0.5 * sx - dpml - dsub - h,
                                -0.5 * sy + g - h * math.tan(theta_1), 0),
                     mp.Vector3(0.5 * sx - dpml - dsub, -0.5 * sy + g, 0)
                 ])
    ]

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

    refl_flux = sim.add_flux(
        fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0, sy, 0)))
    sim.load_minus_flux_data(refl_flux, input_flux_data)

    tran_pt = mp.Vector3(0.5 * sx - dpml - 0.5 * dsub, 0, 0)
    tran_flux = sim.add_flux(
        fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0, sy, 0)))

    sim.run(until_after_sources=500)

    kdom_tol = 1e-2
    angle_tol = 1e-6

    Rsum = 0
    Tsum = 0
    if theta_src == 0:
        nm_r = int(0.5 * (np.floor((fcen - k.y) * d) - np.ceil(
            (-fcen - k.y) * d)))  # number of reflected orders

        res = sim.get_eigenmode_coefficients(refl_flux,
                                             range(1, nm_r + 1),
                                             eig_parity=eig_parity + mp.EVEN_Y)
        r_coeffs = res.alpha
        r_kdom = res.kdom
        for nm in range(nm_r):
            if nm != nm_val:
                continue
            if r_kdom[nm].x > kdom_tol:
                r_angle = np.sign(r_kdom[nm].y) * math.acos(
                    r_kdom[nm].x / fcen) if (
                        r_kdom[nm].x % fcen > angle_tol) else 0
                Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0]
                print("refl: (even_y), {}, {:.2f}, {:.8f}".format(
                    nm, math.degrees(r_angle), Rmode))
                Rsum += Rmode

        res = sim.get_eigenmode_coefficients(refl_flux,
                                             range(1, nm_r + 1),
                                             eig_parity=eig_parity + mp.ODD_Y)
        r_coeffs = res.alpha
        r_kdom = res.kdom
        for nm in range(nm_r):
            if nm != nm_val:
                continue
            if r_kdom[nm].x > kdom_tol:
                r_angle = np.sign(r_kdom[nm].y) * math.acos(
                    r_kdom[nm].x / fcen) if (
                        r_kdom[nm].x % fcen > angle_tol) else 0
                Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0]
                print("refl: (odd_y), {}, {:.2f}, {:.8f}".format(
                    nm, math.degrees(r_angle), Rmode))
                Rsum += Rmode

        nm_t = int(0.5 * (np.floor((fcen * ng - k.y) * d) - np.ceil(
            (-fcen * ng - k.y) * d)))  # number of transmitted orders

        res = sim.get_eigenmode_coefficients(tran_flux,
                                             range(1, nm_t + 1),
                                             eig_parity=eig_parity + mp.EVEN_Y)
        t_coeffs = res.alpha
        t_kdom = res.kdom
        for nm in range(nm_t):
            if nm != nm_val:
                continue
            if t_kdom[nm].x > kdom_tol:
                t_angle = np.sign(t_kdom[nm].y) * math.acos(
                    t_kdom[nm].x / (ng * fcen)) if (
                        t_kdom[nm].x % ng * fcen > angle_tol) else 0
                Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0]
                transmittance = transmittance + Tmode

                Tsum += Tmode

        res = sim.get_eigenmode_coefficients(tran_flux,
                                             range(1, nm_t + 1),
                                             eig_parity=eig_parity + mp.ODD_Y)
        t_coeffs = res.alpha
        t_kdom = res.kdom
        for nm in range(nm_t):
            if nm != nm_val:
                continue
            if t_kdom[nm].x > kdom_tol:
                t_angle = np.sign(t_kdom[nm].y) * math.acos(
                    t_kdom[nm].x / (ng * fcen)) if (
                        t_kdom[nm].x % ng * fcen > angle_tol) else 0
                Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0]
                transmittance = transmittance + Tmode

                Tsum += Tmode
    else:
        nm_r = int(np.floor((fcen - k.y) * d) - np.ceil(
            (-fcen - k.y) * d))  # number of reflected orders
        res = sim.get_eigenmode_coefficients(refl_flux,
                                             range(1, nm_r + 1),
                                             eig_parity=eig_parity)
        r_coeffs = res.alpha
        r_kdom = res.kdom
        for nm in range(nm_r):
            if nm != nm_val:
                continue
            if r_kdom[nm].x > kdom_tol:
                r_angle = np.sign(r_kdom[nm].y) * math.acos(
                    r_kdom[nm].x / fcen) if (
                        r_kdom[nm].x % fcen > angle_tol) else 0
                Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0]
                Rsum += Rmode

        nm_t = int(
            np.floor((fcen * ng - k.y) * d) - np.ceil(
                (-fcen * ng - k.y) * d))  # number of transmitted orders
        res = sim.get_eigenmode_coefficients(tran_flux,
                                             range(1, nm_t + 1),
                                             eig_parity=eig_parity)
        t_coeffs = res.alpha
        t_kdom = res.kdom
        for nm in range(nm_t):
            if nm != nm_val:
                continue
            if t_kdom[nm].x > kdom_tol:
                t_angle = np.sign(t_kdom[nm].y) * math.acos(
                    t_kdom[nm].x / (ng * fcen)) if (
                        t_kdom[nm].x % ng * fcen > angle_tol) else 0
                Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0]
                transmittance = transmittance + Tmode

    return transmittance
Пример #21
0
                           [point0.y, cpoint0.y, cpoint1.y, point1.y]])
curve = bezier.Curve(nodes, degree=3)
points1 = curve.evaluate_multi(factor)
new_points = points1.transpose()
wg = waveguide.Waveguide(new_points, width)
poly2 = wg.poly()
tmp_poly = np.asarray(poly)
# plt.plot(tmp_poly[:,0],tmp_poly[:,1],'-')

vertices1 = [mp.Vector3(tmp[0], tmp[1]) for tmp in poly]
vertices2 = [mp.Vector3(tmp[0], tmp[1]) for tmp in poly2]
#vertices.extend([tmp for tmp in reversed(tmp_ver)])

geometry = [
    mp.Prism(vertices1,
             height=mp.inf,
             center=mp.Vector3(0.0, 2.0),
             material=mp.Medium(epsilon=12)),
    mp.Prism(vertices2,
             height=mp.inf,
             center=mp.Vector3(1.0, -2.0),
             material=mp.Medium(epsilon=12))
]

# sources = [mp.Source(mp.ContinuousSource(frequency=0.15),
#                     component=mp.Ez,
#                     center=mp.Vector3(-7,0))]

sim = mp.Simulation(cell_size=cell,
                    boundary_layers=pml_layers,
                    geometry=geometry,
                    sources=sources,
Пример #22
0
    def test_linear_taper_2d(self):
        resolution = 10
        w1 = 1
        w2 = 2
        Lw = 2
        dair = 3.0
        dpml = 5.0
        sy = dpml + dair + w2 + dair + dpml
        half_w1 = 0.5 * w1
        half_w2 = 0.5 * w2
        Si = mp.Medium(epsilon=12.0)
        boundary_layers = [mp.PML(dpml)]
        lcen = 6.67
        fcen = 1 / lcen
        symmetries = [mp.Mirror(mp.Y)]
        Lt = 2
        sx = dpml + Lw + Lt + Lw + dpml
        cell_size = mp.Vector3(sx, sy, 0)
        prism_x = sx + 1
        half_Lt = 0.5 * Lt
        src_pt = mp.Vector3(-0.5 * sx + dpml + 0.2 * Lw, 0, 0)
        sources = [
            mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=0.2 * fcen),
                               center=src_pt,
                               size=mp.Vector3(0, sy - 2 * dpml, 0),
                               eig_match_freq=True,
                               eig_parity=mp.ODD_Z + mp.EVEN_Y)
        ]

        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)
        ]

        sim = mp.Simulation(
            resolution=resolution,
            cell_size=cell_size,
            boundary_layers=boundary_layers,
            geometry=[mp.Prism(vertices, height=mp.inf, material=Si)],
            sources=sources,
            symmetries=symmetries)

        mon_pt = mp.Vector3(-0.5 * sx + dpml + 0.5 * Lw, 0, 0)
        flux = sim.add_flux(
            fcen, 0, 1,
            mp.FluxRegion(center=mon_pt, size=mp.Vector3(0, sy - 2 * dpml, 0)))

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

        res = sim.get_eigenmode_coefficients(flux, [1],
                                             eig_parity=mp.ODD_Z + mp.EVEN_Y)
        incident_coeffs = res.alpha
        incident_flux = mp.get_fluxes(flux)
        incident_flux_data = sim.get_flux_data(flux)

        sim.reset_meep()

        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)
        ]

        sim = mp.Simulation(
            resolution=resolution,
            cell_size=cell_size,
            boundary_layers=boundary_layers,
            geometry=[mp.Prism(vertices, height=mp.inf, material=Si)],
            sources=sources,
            symmetries=symmetries)

        refl_flux = sim.add_flux(
            fcen, 0, 1,
            mp.FluxRegion(center=mon_pt, size=mp.Vector3(0, sy - 2 * dpml, 0)))
        sim.load_minus_flux_data(refl_flux, incident_flux_data)

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

        res = sim.get_eigenmode_coefficients(refl_flux, [1],
                                             eig_parity=mp.ODD_Z + mp.EVEN_Y)
        coeffs = res.alpha
        taper_flux = mp.get_fluxes(refl_flux)

        self.assertAlmostEqual(abs(coeffs[0, 0, 1])**2 /
                               abs(incident_coeffs[0, 0, 0])**2,
                               -taper_flux[0] / incident_flux[0],
                               places=4)
Пример #23
0
    def init(self, no_bend=False, gdsii=False):
        sx = 16
        sy = 32
        cell = mp.Vector3(sx, sy, 0)
        pad = 4
        w = 1
        wvg_ycen = -0.5 * (sy - w - (2 * pad))
        wvg_xcen = 0.5 * (sx - w - (2 * pad))
        height = mp.inf
        data_dir = os.path.abspath(
            os.path.join(os.path.dirname(__file__), 'data'))
        gdsii_file = os.path.join(data_dir, 'bend-flux.gds')

        if no_bend:
            if gdsii:
                geometry = mp.get_GDSII_prisms(mp.Medium(epsilon=12),
                                               gdsii_file, 1, 0, height)
            else:
                no_bend_vertices = [
                    mp.Vector3(-0.5 * sx - 5, wvg_ycen - 0.5 * w),
                    mp.Vector3(+0.5 * sx + 5, wvg_ycen - 0.5 * w),
                    mp.Vector3(+0.5 * sx + 5, wvg_ycen + 0.5 * w),
                    mp.Vector3(-0.5 * sx - 5, wvg_ycen + 0.5 * w)
                ]

                geometry = [
                    mp.Prism(no_bend_vertices,
                             height,
                             material=mp.Medium(epsilon=12))
                ]
        else:
            if gdsii:
                geometry = mp.get_GDSII_prisms(mp.Medium(epsilon=12),
                                               gdsii_file, 2, 0, height)
            else:
                bend_vertices = [
                    mp.Vector3(-0.5 * sx, wvg_ycen - 0.5 * w),
                    mp.Vector3(wvg_xcen + 0.5 * w, wvg_ycen - 0.5 * w),
                    mp.Vector3(wvg_xcen + 0.5 * w, 0.5 * sy),
                    mp.Vector3(wvg_xcen - 0.5 * w, 0.5 * sy),
                    mp.Vector3(wvg_xcen - 0.5 * w, wvg_ycen + 0.5 * w),
                    mp.Vector3(-0.5 * sx, wvg_ycen + 0.5 * w)
                ]

                geometry = [
                    mp.Prism(bend_vertices,
                             height,
                             material=mp.Medium(epsilon=12))
                ]

        fcen = 0.15
        df = 0.1
        sources = [
            mp.Source(mp.GaussianSource(fcen, fwidth=df),
                      component=mp.Ez,
                      center=mp.Vector3(1 + (-0.5 * sx), wvg_ycen),
                      size=mp.Vector3(0, w))
        ]

        pml_layers = [mp.PML(1.0)]
        resolution = 10
        nfreq = 100

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

        if no_bend:
            fr = mp.FluxRegion(center=mp.Vector3((sx / 2) - 1.5, wvg_ycen),
                               size=mp.Vector3(0, w * 2))
        else:
            fr = mp.FluxRegion(center=mp.Vector3(wvg_xcen, (sy / 2) - 1.5),
                               size=mp.Vector3(w * 2, 0))

        self.trans = self.sim.add_flux(fcen, df, nfreq, fr)
        refl_fr = mp.FluxRegion(center=mp.Vector3((-0.5 * sx) + 1.5, wvg_ycen),
                                size=mp.Vector3(0, w * 2))

        self.refl = self.sim.add_flux(fcen, df, nfreq, refl_fr)

        if no_bend:
            self.pt = mp.Vector3((sx / 2) - 1.5, wvg_ycen)
        else:
            self.pt = mp.Vector3(wvg_xcen, (sy / 2) - 1.5)
Пример #24
0
cell_size = mp.Vector3(2, 2, 2)

# A hexagon is defined as a prism with six vertices centered on the origin
vertices = [
    mp.Vector3(-1, 0),
    mp.Vector3(-0.5,
               math.sqrt(3) / 2),
    mp.Vector3(0.5,
               math.sqrt(3) / 2),
    mp.Vector3(1, 0),
    mp.Vector3(0.5, -math.sqrt(3) / 2),
    mp.Vector3(-0.5, -math.sqrt(3) / 2)
]

geometry = [
    mp.Prism(vertices, height=1.0, material=mp.Medium(index=3.5)),
    mp.Cone(radius=1.0, radius2=0.1, height=2.0, material=mp.air)
]

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

#%%

sim.init_sim()

x, y, z, *more = sim.get_array_metadata(
)  # (x,y,z,w) = sim.get_array_metadata()
# Returns coordinates and interpolation weights of the fields :)
del more

eps_data = sim.get_epsilon()
Пример #25
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
Пример #26
0
    def run_mode_coeffs(self, mode_num, kpoint_func, nf=1, 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
        df = 0.5 * fcen

        source = mp.EigenModeSource(src=mp.GaussianSource(fcen, fwidth=df),
                                    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=2 * resolution)

        sim = mp.Simulation(
            resolution=resolution,
            cell_size=cell_size,
            boundary_layers=boundary_layers,
            geometry=geometry,
            sources=[source],
            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, df, nf,
            mp.ModeRegion(center=mp.Vector3(xm, 0),
                          size=mp.Vector3(0, sy - 2 * dpml)))
        mode_flux = sim.add_flux(
            fcen, df, nf,
            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)

        ##################################################
        # If the number of analysis frequencies is >1, we
        # are testing the unit-power normalization
        # of the eigenmode source: we observe the total
        # power flux through the mode_flux monitor (which
        # equals the total power emitted by the source as
        # there is no scattering in this ideal waveguide)
        # and check that it agrees with the prediction
        # of the eig_power() class method in EigenmodeSource.
        ##################################################
        if nf > 1:
            power_observed = mp.get_fluxes(mode_flux)
            freqs = mp.get_flux_freqs(mode_flux)
            power_expected = [source.eig_power(f) for f in freqs]
            return freqs, power_expected, power_observed

        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))
        self.assertAlmostEqual(res.cscale[0], 0.50000977, places=5)
        self.assertAlmostEqual(res.cscale[1], 0.50096888, places=5)
        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
Пример #27
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()
Пример #28
0
def build_geom(sx, sy, dsub, gp, gh, lw, tr, br, sa, material):
    tw = gh / np.tan(
        sa * 2 * np.pi / 360)  # part to subtract from top of grating width
    a = (gh - tr) / np.tan(
        sa * 2 * np.pi / 360)  # intermediate for vertex calculation

    #vertices for trapezoids approximating grating cross-section
    vtx = [
        mp.Vector3(-0.5 * lw - 0.5 * a + gp / 2, -1 * (-0.5 * gh), 0),
        mp.Vector3(0.5 * lw + 0.5 * a + gp / 2, -1 * (-0.5 * gh), 0),
        mp.Vector3(0.5 * lw - 0.5 * a + gp / 2, -1 * (0.5 * gh - tr), 0),
        mp.Vector3(-0.5 * lw + 0.5 * a + gp / 2, -1 * (0.5 * gh - tr), 0)
    ]

    vtx2 = [
        mp.Vector3(-0.5 * lw - 0.5 * a - gp / 2, -1 * (-0.5 * gh), 0),
        mp.Vector3(0.5 * lw + 0.5 * a - gp / 2, -1 * (-0.5 * gh), 0),
        mp.Vector3(0.5 * lw - 0.5 * a - gp / 2, -1 * (0.5 * gh - tr), 0),
        mp.Vector3(-0.5 * lw + 0.5 * a - gp / 2, -1 * (0.5 * gh - tr), 0)
    ]

    #rounded corners for top of trapezoids
    c1 = mp.Cylinder(radius=tr,
                     height=mp.inf,
                     axis=mp.Vector3(0, 0, 1),
                     center=mp.Vector3(-gp / 2 - lw / 2 + tw / 2 + tr,
                                       -1 * (-sy / 2 + dsub + gh - tr), 0),
                     material=material)
    c2 = mp.Cylinder(radius=tr,
                     height=mp.inf,
                     axis=mp.Vector3(0, 0, 1),
                     center=mp.Vector3(-gp / 2 + lw / 2 - tw / 2 - tr,
                                       -1 * (-sy / 2 + dsub + gh - tr), 0),
                     material=material)
    c3 = mp.Cylinder(radius=tr,
                     height=mp.inf,
                     axis=mp.Vector3(0, 0, 1),
                     center=mp.Vector3(gp / 2 - lw / 2 + tw / 2 + tr,
                                       -1 * (-sy / 2 + dsub + gh - tr), 0),
                     material=material)
    c4 = mp.Cylinder(radius=tr,
                     height=mp.inf,
                     axis=mp.Vector3(0, 0, 1),
                     center=mp.Vector3(gp / 2 + lw / 2 - tw / 2 - tr,
                                       -1 * (-sy / 2 + dsub + gh - tr), 0),
                     material=material)

    #blocks for top of trapezoids inbetween rounded corners
    b1 = mp.Block(center=mp.Vector3(-gp / 2,
                                    -1 * (-sy / 2 + dsub + gh - tr / 2)),
                  size=mp.Vector3(lw - tw - 2 * tr, tr, mp.inf),
                  material=material)
    b2 = mp.Block(center=mp.Vector3(gp / 2,
                                    -1 * (-sy / 2 + dsub + gh - tr / 2)),
                  size=mp.Vector3(lw - tw - 2 * tr, tr, mp.inf),
                  material=material)

    #ellipsoid cutout to make bottom of grating round
    e1 = mp.Ellipsoid(center=mp.Vector3(0, -1 * (-sy / 2 + dsub), 0),
                      size=mp.Vector3(gp - lw - a, br, mp.inf),
                      material=mp.Medium(epsilon=1))
    e2 = mp.Ellipsoid(center=mp.Vector3(-gp, -1 * (-sy / 2 + dsub), 0),
                      size=mp.Vector3(gp - lw - a, br, mp.inf),
                      material=mp.Medium(epsilon=1))
    e3 = mp.Ellipsoid(center=mp.Vector3(gp, -1 * (-sy / 2 + dsub), 0),
                      size=mp.Vector3(gp - lw - a, br, mp.inf),
                      material=mp.Medium(epsilon=1))

    geometry = [
        mp.Block(material=material,
                 size=mp.Vector3(sx, dsub, mp.inf),
                 center=mp.Vector3(0, -1 * (-0.5 * sy + 0.5 * dsub), 0)),
        mp.Prism(vtx,
                 height=mp.inf,
                 center=mp.Vector3(0, -1 * (-0.5 * sy + dsub + 0.5 * gh), 0),
                 material=material),
        mp.Prism(vtx2,
                 height=mp.inf,
                 center=mp.Vector3(0, -1 * (-0.5 * sy + dsub + 0.5 * gh), 0),
                 material=material), c1, c2, c3, c4, b1, b2, e1, e2, e3
    ]

    return geometry
Пример #29
0
width1 = 0.5
width2 = 1
length = 4
span = 6
vertices = [
    mp.Vector3(-length/2-span,width1/2),
    mp.Vector3(-length/2,width1/2),
    mp.Vector3(length/2,width2/2),
    mp.Vector3(length/2+span,width2/2),
    mp.Vector3(length/2+span,-width2/2),
    mp.Vector3(length/2,-width2/2),
    mp.Vector3(-length/2,-width1/2),
    mp.Vector3(-length/2-span,-width1/2)
    ]
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
Пример #30
0
# A hexagon is defined as a prism with six vertices centered on the origin
vertices = [
    mp.Vector3(-1, 0),
    mp.Vector3(-0.5,
               math.sqrt(3) / 2),
    mp.Vector3(0.5,
               math.sqrt(3) / 2),
    mp.Vector3(1, 0),
    mp.Vector3(0.5, -math.sqrt(3) / 2),
    mp.Vector3(-0.5, -math.sqrt(3) / 2)
]

geometry = [  #mp.Block(center=mp.Vector3(0,0,0), size=cell_size, material=mp.air),
    mp.Prism(vertices,
             height=1.9,
             material=mp.metal,
             center=mp.Vector3(0, 0, 0))
]

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

sim.init_sim()

eps_data = sim.get_epsilon()
#eps_data = sim.get_array()

#sim.plot3D(eps_data)

#from mayavi import mlab
#s = mlab.contour3d()
#mlab.show()