GDS Taper#

Create a Taper and Simulate

import meow as mw
import gdsfactory as gf  # pip install meow-sim[gds]
import matplotlib.pyplot as plt
import numpy as np

Example Taper#

Note: meow expects the propagation direction to be the z-axis! This makes the zx-plane parallel with the chip and the y-axis perpendicular to the chip. Somewhat confusingly, the (x, y) GDS coordinate tuple hence maps onto the (z, x) meow coordinate tuple. Whereas the y coordinate from meow denotes the direction perpendicular to the chip. (I will probably change the meow convention in the future.)

def example_gds_cross_section(
    width: float = 0.450,
    clad_width: float = 2.0,
) -> gf.CrossSection:
    """a strip waveguide cross section

    Args:
        width:  the width of the strip waveguide
        clad_width: the width of the cladding
    """
    core_width = width
    port_names = ("in0", "out0")
    sections = (
        gf.Section(width=core_width, offset=0, layer=(1, 0), name="core"),
        gf.Section(
            width=clad_width,
            offset=0.5 * (core_width + clad_width),
            layer=(2, 0),
            name="upper",
        ),
        gf.Section(
            width=clad_width,
            offset=-0.5 * (core_width + clad_width),
            layer=(2, 0),
            name="lower",
        ),
    )
    cs = gf.cross_section.cross_section(
        width=width,
        port_names=port_names,
        auto_widen=False,
        sections=sections,
    )
    return cs
@gf.cell
def example_taper(
    width_input: float = 0.450,
    width_output: float = 1.0,
    length: float = 10.0,
) -> gf.Component:
    """create a linear taper

    Args:
        width_input: input width of the linear taper
        width_output: output width of the linear taper
        length: the length of the linear taper
    """
    input_cs = example_gds_cross_section(width_input)
    output_cs = example_gds_cross_section(width_output)
    transition = gf.path.transition(input_cs, output_cs, width_type="linear")
    length = gf.snap.snap_to_grid(length)  # type: ignore
    path = gf.path.straight(length)
    component = gf.path.extrude(path, transition)
    return component
taper = example_taper(width_input=0.45, width_output=1.0, length=20)
taper
/opt/conda/lib/python3.10/site-packages/gdsfactory/klive.py:49: UserWarning: Could not connect to klive server. Is klayout open and klive plugin installed?
  warnings.warn(
example_taper_length20: uid dda5d8ca, ports ['in0', 'out0'], references [], 4 polygons
../_images/7ca4e33d5e7f67b5130f8f5a6ec705574c4dfee398db37ef9f3398ba9d6d7424.png

Example Structure Map#

def example_extrusions(
    t_slab: float = 0.020,
    t_soi: float = 0.220,
    t_ox: float = 1.0,
):
    """create some simple extrusion rules

    Args:
        t_slab: the slab thickness
        t_soi: the SOI thickness
        t_ox: the oxide layer thickness
    """
    extrusions = {
        (1, 0): [
            mw.GdsExtrusionRule(
                material=mw.silicon,
                h_min=0.0,
                h_max=0.0 + t_soi,
                mesh_order=1,
            ),
            mw.GdsExtrusionRule(
                material=mw.silicon_oxide,
                h_min=-1.0,
                h_max=t_soi + t_ox,
                buffer=t_ox / 2,
                mesh_order=2,
            ),
        ],
        (2, 0): [
            mw.GdsExtrusionRule(
                material=mw.silicon,
                h_min=0.0,
                h_max=0.0 + t_slab,
                mesh_order=1,
            ),
            mw.GdsExtrusionRule(
                material=mw.silicon_oxide,
                h_min=-1.0,
                h_max=t_slab + t_ox,
                mesh_order=2,
            ),
        ],
    }
    return extrusions

Extrude GDS#

extrusion_rules = example_extrusions()
structs = mw.extrude_gds(taper, extrusion_rules)
mw.visualize(structs, scale=(1, 1, 0.2))

Divide into Cells#

w_sim = 1.0
h_sim = 1.0
mesh = 100
num_cells = 10
taper_length = np.diff(taper.bbox[:, 0]).item()
Ls = [taper_length / num_cells for _ in range(num_cells)]
print(Ls)

cells = mw.create_cells(
    structures=structs,
    mesh=mw.Mesh2d(
        x=np.linspace(-0.75, 0.75, mesh + 1),
        y=np.linspace(-0.3, 0.5, mesh + 1),
    ),
    Ls=Ls,
)

mw.visualize(cells[0], cbar=False)
plt.show()

mw.visualize(cells[-1], cbar=False)
plt.show()
[2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
../_images/235613ca9a77a6a6e42b5f0152b2155b517e2324d3021ec25da016b68fa0c9ac.png ../_images/4141b4939b715639302516549b371bf55b145552b37a03ad58a4e3862d7e5e0a.png

Find Cross Sections#

env = mw.Environment(wl=1.55, T=25.0)
css = [mw.CrossSection.from_cell(cell=cell, env=env) for cell in cells]

mw.visualize(css[0])
mw.visualize(css[-1])
../_images/c5b5c1ed5037fa4758df51daa5c98e138b66aabe019fee11752c978bb9796b98.png ../_images/37453cc28c457d8f3829d0e39c041d965579f85af66b90f6c9fda9c164e52ea2.png
num_modes = 4
modes = mw.compute_modes(css[0], num_modes=num_modes)
mw.visualize(modes[0])
../_images/adce79559bcbafa992634d3c749e66187a69daa1cd80801ee10e35b24c500ecb.png

Compute Modes (FDE)#

%%time
num_modes = 4
modes = [mw.compute_modes(cs, num_modes=num_modes) for cs in css]
CPU times: user 23.6 s, sys: 27.6 s, total: 51.2 s
Wall time: 31.7 s
mw.visualize(modes[0][0], fields=["Hx"])
mw.visualize(modes[-1][1], fields=["Hx"])
../_images/13e5edc1cdecea900945f6f2b5ecc4181d8cbd10a8d9e5a5cf56b85a1b157e0a.png ../_images/82033e0b334580e9fa795b791ae7a41ab3185367ec46a33ac054f13a8a21688f.png

Calculate S-matrix (EME)#

S, port_map = mw.compute_s_matrix(modes, cells)
print(port_map)
mw.visualize((abs(S), port_map))
{'left@0': 0, 'left@1': 1, 'left@2': 2, 'left@3': 3, 'right@0': 4, 'right@1': 5, 'right@2': 6, 'right@3': 7}
../_images/d88c4d23386a2386abffda6645d4f8c260320481a7ebe72e61e4a2ed24982d71.png