Esempio n. 1
0
def difftest(component: Component):
    """Runs an XOR over a component and makes boolean comparison with a GDS reference.
    If it runs for the fist time it just stores the GDS reference.
    raises GeometryDifference if there are differences and show differences in klayout.
    """

    # containers function_name is different from component.name
    filename = (f"{component.function_name}_{component.name}.gds"
                if hasattr(component, "function_name")
                and component.name != component.function_name else
                f"{component.name}.gds")

    ref_file = cwd / "gds_ref" / filename
    run_file = cwd / "gds_run" / filename

    pp.write_gds(component, gdspath=run_file)

    if not ref_file.exists():
        print(f"Creating GDS reference for {component.name} in {ref_file}")
        pp.write_gds(component, gdspath=ref_file)
    try:
        run_xor(str(ref_file), str(run_file), tolerance=1, verbose=False)
    except GeometryDifference:
        diff = gdsdiff(ref_file, run_file)
        pp.show(diff)
        raise
Esempio n. 2
0
def debug():
    c = mzi2x2()
    h0 = c.hash_geometry()

    gdspath1 = "{}.gds".format(c.name)
    gdspath2 = "{}_2.gds".format(c.name)
    gdspath3 = "{}_3.gds".format(c.name)
    pp.write_gds(c, gdspath1)

    c1 = pp.import_gds(gdspath1, overwrite_cache=True)

    c2 = pp.import_gds(gdspath2, overwrite_cache=True)

    c3 = pp.import_gds(gdspath3, overwrite_cache=True)

    dbg = False
    dh1 = hash_cells(c1, {}, dbg=dbg)
    dh2 = hash_cells(c2, {}, dbg=dbg)
    dh3 = hash_cells(c3, {}, dbg=dbg)

    h1 = dh1[c1.name]
    h2 = dh2[c2.name]
    h3 = dh3[c3.name]
    print(h1)
    print(h2)
    print(h3)

    print(h0)
    print(gdspy.gdsii_hash(gdspath1))
    print(gdspy.gdsii_hash(gdspath2))
    print(gdspy.gdsii_hash(gdspath3))
Esempio n. 3
0
def test_mask(precision=1e-9):
    workspace_folder = CONFIG["samples_path"] / "mask_pack"
    build_path = workspace_folder / "build"
    mask_path = build_path / "mask"

    mask_path.mkdir(parents=True, exist_ok=True)

    gdspath = mask_path / "sample_mask.gds"
    markdown_path = gdspath.with_suffix(".md")
    json_path = gdspath.with_suffix(".json")
    test_metadata_path = gdspath.with_suffix(".tp.json")

    components = [spiral_te(length=length) for length in [2, 4, 6]]
    components += [
        coupler_te(length=length, gap=0.2) for length in [10, 20, 30, 40]
    ]
    c = pp.pack(components)
    m = c[0]
    m.name = "sample_mask"
    pp.write_gds(m, gdspath)

    merge_metadata(gdspath=gdspath)

    assert gdspath.exists()
    assert markdown_path.exists()
    assert json_path.exists()
    assert test_metadata_path.exists()
    return gdspath
Esempio n. 4
0
def test_placer():
    cwd = pathlib.Path(__file__).parent
    filepath = cwd / "config.yml"
    gdspath = cwd / "build" / "mask" / "test_placer.gds"

    top_level = component_grid_from_yaml(filepath)
    pp.write_gds(top_level, gdspath)
    assert gdspath.exists()
    return gdspath
Esempio n. 5
0
def test_density():
    """
    Return ratio of total area on a layer over the bounding box of the component
    """
    import pp
    layer = (1, 0)
    c = pp.c.rectangle(size=(4, 2), layer=layer)
    pp.write_gds(c)
    area = compute_area(c, layer)
    assert np.isclose(8, area)
Esempio n. 6
0
def test_mask():
    workspace_folder = pathlib.Path(__file__).parent
    filepath_yml = workspace_folder / "config.yml"
    config = load_config(filepath_yml)
    gdspath = str(config["mask"]["gds"])

    top_level = component_grid_from_yaml(config)
    pp.write_gds(top_level, gdspath)
    assert config["mask"]["gds"].exists()
    return gdspath
Esempio n. 7
0
def mask2():
    N = 15
    bend_radius = 15

    e = []
    e.append(
        ubc.spiral_te(
            N=N,
            bend_radius=bend_radius,
            y_straight_inner_top=0,
            x_inner_length_cutback=0,
        ))
    e.append(
        ubc.spiral_te(
            N=N,
            bend_radius=bend_radius,
            y_straight_inner_top=30,
            x_inner_length_cutback=85,
        ))
    c = pack(e)
    m = c[0]
    m.name = "EBeam_JoaquinMatres_2"
    add_floorplan(m)
    gdspath = pp.write_gds(m, precision=1e-9)
    change_grid_klayout(gdspath)
    pp.show(m)
def test_wmin_failing(layer=(1, 0)):
    w = 50
    min_width = 50 + 10  # device edges are smaller than min_width
    c = pp.c.rectangle(size=(w, w), layer=layer)
    gdspath = pp.write_gds(c, "wmin.gds")

    # r = check_width(gdspath, min_width=min_width, layer=layer)
    # print(check_width(gdspath, min_width=min_width, layer=layer))
    assert check_width(gdspath, min_width=min_width, layer=layer) == 2
    assert check_width(c, min_width=min_width, layer=layer) == 2
def test_wmin_passing(layer=(1, 0)):
    w = 50
    min_width = 50 - 10  # device edges are bigger than the min_width
    c = pp.c.rectangle(size=(w, w), layer=layer)
    gdspath = pp.write_gds(c, "wmin.gds")

    # print(check_width(c, min_width=min_width, layer=layer))
    # assert check_width(gdspath, min_width=min_width, layer=layer) is None
    # assert check_width(c, min_width=min_width, layer=layer) is None
    assert check_width(gdspath, min_width=min_width, layer=layer) == 0
    assert check_width(c, min_width=min_width, layer=layer) == 0
Esempio n. 10
0
def mask1():
    e = [ubc.mzi_te(delta_length=dl) for dl in [9.32, 93.19]]
    e += [
        ubc.ring_single_te(bend_radius=12, gap=gap, length_x=coupling_length)
        for gap in [0.2] for coupling_length in [2.5, 4.5, 6.5]
    ]
    c = pack(e)
    m = c[0]
    m.name = "EBeam_JoaquinMatres_1"
    add_floorplan(m)
    gdspath = pp.write_gds(m, precision=1e-9)
    change_grid_klayout(gdspath)
    pp.show(m)
Esempio n. 11
0
def show(gds_filename: Union[PosixPath, str],
         keep_position: bool = True) -> None:
    """ Show GDS in klayout """
    if not os.path.isfile(gds_filename):
        raise ValueError(f"{gds_filename} does not exist")
    data = {
        "gds": os.path.abspath(gds_filename),
        "keep_position": keep_position,
    }
    data_string = json.dumps(data)
    try:
        conn = socket.create_connection(("127.0.0.1", 8082), timeout=1.0)
        data_string = data_string + "\n"
        data_string = (data_string.encode()
                       if hasattr(data_string, "encode") else data_string)
        conn.sendall(data_string)
        conn.close()
    except socket.error:
        print(
            "error sending GDS to klayout. Make sure have Klayout opened and that you have installed klive with `pf install`"
        )


if __name__ == "__main__":
    import pp

    c = pp.c.waveguide()
    gdspath = pp.write_gds(c)
    show(gdspath)
Esempio n. 12
0
    ps = gds.fast_boolean(ps, None, "or")
    """ component """
    c = pp.Component()
    c.length = length
    c.add_polygon(ps, layer=wg_layer)

    c.add_port(
        name="W0",
        midpoint=(s[0], s[1]),
        orientation=180,
        layer=wg_layer,
        width=wg_width,
    )
    c.add_port(
        name="E0",
        midpoint=(e[0], e[1]),
        orientation=180,
        layer=wg_layer,
        width=wg_width,
    )
    return c


if __name__ == "__main__":
    c = spiral_circular(length=1e3, pins=True)
    print(c.ports)
    print(c.ports.keys())
    print(c.get_ports_array())
    pp.show(c)
    pp.write_gds(c)
Esempio n. 13
0
def mmi1x2_biased(
    wg_width=0.5,
    width_taper=1.0,
    length_taper=10,
    length_mmi=5.496,
    width_mmi=2.5,
    gap_mmi=0.25,
    layer=pp.LAYER.WG,
):
    return mmi1x2(
        wg_width=pp.bias.width(wg_width),
        width_taper=pp.bias.width(width_taper),
        length_taper=length_taper,
        length_mmi=length_mmi,
        width_mmi=pp.bias.width(width_mmi),
        gap_mmi=pp.bias.gap(gap_mmi),
        layer=layer,
    )


if __name__ == "__main__":
    c = mmi1x2(pins=True)
    print(c.ports)
    # print(c.get_ports_array())
    # c = mmi1x2_biased()
    # pp.write_to_libary("mmi1x2", width_mmi=10, overwrite=True)
    # print(c.get_optical_ports())
    pp.write_gds(c, pp.CONFIG["gdsdir"] / "mmi1x2.gds")
    pp.show(c)
    # print(c.get_settings())
Esempio n. 14
0
def _demo_waveguide():
    c = waveguide()
    pp.write_gds(c)
    return c
Esempio n. 15
0
def _demo_bend():
    c = bend_circular()
    pp.write_gds(c)
Esempio n. 16
0
File: add_gc.py Progetto: tvt173/ubc
    gc_port_name="W0",
    get_input_labels_function=get_input_labels,
    with_align_ports=False,
):
    c = pp.routing.add_io_optical(
        component=component,
        component_name=component_name,
        bend_factory=bend_factory,
        straight_factory=straight_factory,
        route_filter=route_filter,
        grating_coupler=grating_coupler,
        layer_label=layer_label,
        taper_factory=taper_factory,
        gc_port_name=gc_port_name,
        get_input_labels_function=get_input_labels_function,
        with_align_ports=with_align_ports,
    )
    c = rotate(c, -90)
    return c


if __name__ == "__main__":
    import ubc

    # c = gc_te1550()
    # print(c.ports)
    c = add_gc(component=ubc.mzi(delta_length=100))
    # c = add_gc(component=waveguide())
    pp.show(c)
    pp.write_gds(c, "mzi.gds")
Esempio n. 17
0
def write(
    component,
    session=None,
    run=True,
    overwrite=False,
    dirpath=pp.CONFIG["sp"],
    height_nm=220,
    **settings,
):
    """
    writes Sparameters from a gdsfactory component using Lumerical FDTD

    Args:
        component: gdsfactory Component
        session: you can pass a session=lumapi.FDTD() for debugging
        run: True-> runs Lumerical , False -> only draws simulation
        overwrite: run even if simulation results already exists
        dirpath: where to store the simulations
        height_nm: height
        layer2nm: dict of {(1, 0): 220}
        layer2material: dict of {(1, 0): "si"}
        remove_layers: list of tuples (layers to remove)
        background_material: for the background
        port_width: port width (m)
        port_height: port height (m)
        port_extension_um: port extension (um)
        mesh_accuracy: 2 (1: coarse, 2: fine, 3: superfine)
        zmargin: for the FDTD region 1e-6 (m)
        ymargin: for the FDTD region 2e-6 (m)
        wavelength_start: 1.2e-6 (m)
        wavelength_stop: 1.6e-6 (m)
        wavelength_points: 500

    Return:
        results: dict(wavelength_nm, S11, S12 ...) after simulation, or if simulation exists and returns the Sparameters directly
    """
    if hasattr(component, "simulation_settings"):
        settings.update(component.simulation_settings)
    sim_settings = s = dict(
        layer2nm=layer2nm,
        layer2material=layer2material,
        remove_layers=[pp.LAYER.WGCLAD],
        background_material="sio2",
        port_width=3e-6,
        port_height=1.5e-6,
        port_extension_um=1,
        mesh_accuracy=2,
        zmargin=1e-6,
        ymargin=2e-6,
        wavelength_start=1.2e-6,
        wavelength_stop=1.6e-6,
        wavelength_points=500,
    )
    for setting in settings.keys():
        assert (
            setting in s
        ), f"`{setting}` is not a valid setting ({list(settings.keys())})"
    s.update(**settings)
    ss = namedtuple("sim_settings", s.keys())(*s.values())

    assert ss.port_width < 5e-6
    assert ss.port_height < 5e-6
    assert ss.zmargin < 5e-6
    assert ss.ymargin < 5e-6

    ports = component.ports

    component.remove_layers(ss.remove_layers)
    component._bb_valid = False

    c = pp.extend_ports(component=component, length=ss.port_extension_um)
    gdspath = pp.write_gds(c)

    filepath = component.get_sparameters_path(dirpath=dirpath,
                                              height_nm=height_nm)
    filepath_json = filepath.with_suffix(".json")
    filepath_sim_settings = filepath.with_suffix(".settings.json")
    filepath_fsp = filepath.with_suffix(".fsp")

    if run and filepath_json.exists() and not overwrite:
        return json.loads(open(filepath_json).read())

    if not run and session is None:
        print("""
you need to pass `run=True` flag to run the simulation
To debug, you can create a lumerical FDTD session and pass it to the simulator

```
import lumapi
s = lumapi.FDTD()

import pp
c = pp.c.waveguide() # or whatever you want to simulate
pp.sp.write(component=c, run=False, session=s)
```
""")

    pe = ss.port_extension_um * 1e-6 / 2
    x_min = c.xmin * 1e-6 + pe
    x_max = c.xmax * 1e-6 - pe

    y_min = c.ymin * 1e-6 - ss.ymargin
    y_max = c.ymax * 1e-6 + ss.ymargin

    port_orientations = [p.orientation for p in ports.values()]
    if 90 in port_orientations and len(ports) > 2:
        y_max = c.ymax * 1e-6 - pe
        x_max = c.xmax * 1e-6

    elif 90 in port_orientations:
        y_max = c.ymax * 1e-6 - pe
        x_max = c.xmax * 1e-6 + ss.ymargin

    z = 0
    z_span = 2 * ss.zmargin + max(ss.layer2nm.values()) * 1e-9

    import lumapi

    s = session or lumapi.FDTD(hide=False)
    s.newproject()
    s.selectall()
    s.deleteall()
    s.addrect(
        x_min=x_min,
        x_max=x_max,
        y_min=y_min,
        y_max=y_max,
        z=z,
        z_span=z_span,
        index=1.5,
        name="clad",
    )

    material = ss.background_material
    if material not in materials:
        raise ValueError(f"{material} not in {list(materials.keys())}")
    material = materials[material]
    s.setnamed("clad", "material", material)

    s.addfdtd(
        dimension="3D",
        x_min=x_min,
        x_max=x_max,
        y_min=y_min,
        y_max=y_max,
        z=z,
        z_span=z_span,
        mesh_accuracy=ss.mesh_accuracy,
        use_early_shutoff=True,
    )

    layers = component.get_layers()
    for layer, nm in ss.layer2nm.items():
        if layer not in layers:
            continue
        assert layer in ss.layer2material, f"{layer} not in {ss.layer2material.keys()}"

        material = ss.layer2material[layer]
        if material not in materials:
            raise ValueError(f"{material} not in {list(materials.keys())}")
        material = materials[material]

        s.gdsimport(str(gdspath), c.name, f"{layer[0]}:{layer[1]}")
        silicon = f"GDS_LAYER_{layer[0]}:{layer[1]}"
        s.setnamed(silicon, "z span", nm * 1e-9)
        s.setnamed(silicon, "material", material)

    for i, port in enumerate(ports.values()):
        s.addport()
        p = f"FDTD::ports::port {i+1}"
        s.setnamed(p, "x", port.x * 1e-6)
        s.setnamed(p, "y", port.y * 1e-6)
        s.setnamed(p, "z span", ss.port_height)

        deg = int(port.orientation)
        # assert port.orientation in [0, 90, 180, 270], f"{port.orientation} needs to be [0, 90, 180, 270]"
        if -45 <= deg <= 45:
            direction = "Backward"
            injection_axis = "x-axis"
            dxp = 0
            dyp = ss.port_width
        elif 45 < deg < 90 + 45:
            direction = "Backward"
            injection_axis = "y-axis"
            dxp = ss.port_width
            dyp = 0
        elif 90 + 45 < deg < 180 + 45:
            direction = "Forward"
            injection_axis = "x-axis"
            dxp = 0
            dyp = ss.port_width
        elif 180 + 45 < deg < -45:
            direction = "Forward"
            injection_axis = "y-axis"
            dxp = ss.port_width
            dyp = 0

        else:
            raise ValueError(
                f"port {port.name} with orientation {port.orientation} is not a valid"
                " number ")

        s.setnamed(p, "direction", direction)
        s.setnamed(p, "injection axis", injection_axis)
        s.setnamed(p, "y span", dyp)
        s.setnamed(p, "x span", dxp)
        # s.setnamed(p, "theta", deg)
        s.setnamed(p, "name", port.name)

    s.setglobalsource("wavelength start", ss.wavelength_start)
    s.setglobalsource("wavelength stop", ss.wavelength_stop)
    s.setnamed("FDTD::ports", "monitor frequency points", ss.wavelength_points)

    if run:
        s.save(str(filepath_fsp))
        s.deletesweep("s-parameter sweep")

        s.addsweep(3)
        s.setsweep("s-parameter sweep", "Excite all ports", 0)
        s.setsweep("S sweep", "auto symmetry", True)
        s.runsweep("s-parameter sweep")

        # collect results
        # S_matrix = s.getsweepresult("s-parameter sweep", "S matrix")
        sp = s.getsweepresult("s-parameter sweep", "S parameters")

        # export S-parameter data to file named s_params.dat to be loaded in INTERCONNECT
        s.exportsweep("s-parameter sweep", str(filepath))
        print(f"wrote sparameters to {filepath}")

        keys = [key for key in sp.keys() if key.startswith("S")]
        ra = {
            f"{key}a": list(np.unwrap(np.angle(sp[key].flatten())))
            for key in keys
        }
        rm = {f"{key}m": list(np.abs(sp[key].flatten())) for key in keys}

        results = {"wavelength_nm": list(sp["lambda"].flatten() * 1e9)}
        results.update(ra)
        results.update(rm)
        with open(filepath_json, "w") as f:
            json.dump(results, f)

        with open(filepath_sim_settings, "w") as f:
            s = sim_settings
            s["layer2nm"] = [
                f"{k[0]}_{k[1]}_{v}" for k, v in s["layer2nm"].items()
            ]
            s["layer2material"] = [
                f"{k[0]}_{k[1]}_{v}" for k, v in s["layer2material"].items()
            ]
            json.dump(s, f)

        return results
Esempio n. 18
0
            p.name = k

    elif straight_heater_factory == waveguide:
        ports_map = {
            "W0": ("CP1", "W0"),
            "W1": ("CP1", "W1"),
            "E0": ("CP2", "E0"),
            "E1": ("CP2", "E1"),
        }

        component = netlist_to_component(components, connections, ports_map)

    return component


def get_mzi_delta_length(m, neff=2.4, wavelength=1.55):
    """ m*wavelength = neff * delta_length """
    return m * wavelength / neff


if __name__ == "__main__":
    import pp

    # print(get_mzi_delta_length(m=15))
    # print(get_mzi_delta_length(m=150))

    # c = mzi2x2()
    c = mzi2x2(straight_heater_factory=waveguide_heater)
    pp.write_gds(c, 'mzi.gds')
    pp.show(c)
Esempio n. 19
0
def test_wire():
    c = wire()
    pp.write_gds(c)
    return c
Esempio n. 20
0
def write(
    component: Component,
    session: Optional[object] = None,
    run: bool = True,
    overwrite: bool = False,
    dirpath: PosixPath = pp.CONFIG["sp"],
    **settings,
) -> pd.DataFrame:
    """Return and write component Sparameters from Lumerical FDTD.

    if simulation exists and returns the Sparameters directly
    unless overwrite=False

    Args:
        component: gdsfactory Component
        session: you can pass a session=lumapi.FDTD() for debugging
        run: True-> runs Lumerical , False -> only draws simulation
        overwrite: run even if simulation results already exists
        dirpath: where to store the simulations
        layer2nm: dict of GDSlayer to thickness (nm) {(1, 0): 220}
        layer2material: dict of {(1, 0): "si"}
        remove_layers: list of tuples (layers to remove)
        background_material: for the background
        port_width: port width (m)
        port_height: port height (m)
        port_extension_um: port extension (um)
        mesh_accuracy: 2 (1: coarse, 2: fine, 3: superfine)
        zmargin: for the FDTD region 1e-6 (m)
        ymargin: for the FDTD region 2e-6 (m)
        wavelength_start: 1.2e-6 (m)
        wavelength_stop: 1.6e-6 (m)
        wavelength_points: 500

    Return:
        Sparameters pandas DataFrame (wavelength_nm, S11m, S11a, S12a ...)
        suffix `a` for angle and `m` for module

    """
    sim_settings = default_simulation_settings

    if hasattr(component, "simulation_settings"):
        sim_settings.update(component.simulation_settings)
    for setting in sim_settings.keys():
        assert (
            setting in sim_settings
        ), f"`{setting}` is not a valid setting ({list(sim_settings.keys())})"
    for setting in settings.keys():
        assert (
            setting in sim_settings
        ), f"`{setting}` is not a valid setting ({list(sim_settings.keys())})"

    sim_settings.update(**settings)

    # easier to access dict in a namedtuple `ss.port_width`
    ss = namedtuple("sim_settings",
                    sim_settings.keys())(*sim_settings.values())

    assert ss.port_width < 5e-6
    assert ss.port_height < 5e-6
    assert ss.zmargin < 5e-6
    assert ss.ymargin < 5e-6

    ports = component.ports

    component.remove_layers(ss.remove_layers)
    component._bb_valid = False

    c = pp.extend_ports(component=component, length=ss.port_extension_um)
    gdspath = pp.write_gds(c)
    layer2material = settings.pop("layer2material", ss.layer2material)
    layer2nm = settings.pop("layer2nm", ss.layer2nm)

    filepath = get_sparameters_path(
        component=component,
        dirpath=dirpath,
        layer2material=layer2material,
        layer2nm=layer2nm,
        **settings,
    )
    filepath_csv = filepath.with_suffix(".csv")
    filepath_sim_settings = filepath.with_suffix(".yml")
    filepath_fsp = filepath.with_suffix(".fsp")

    if run and filepath_csv.exists() and not overwrite:
        return pd.read_csv(filepath_csv)

    if not run and session is None:
        print(run_false_warning)

    pe = ss.port_extension_um * 1e-6 / 2
    x_min = c.xmin * 1e-6 + pe
    x_max = c.xmax * 1e-6 - pe

    y_min = c.ymin * 1e-6 - ss.ymargin
    y_max = c.ymax * 1e-6 + ss.ymargin

    port_orientations = [p.orientation for p in ports.values()]
    if 90 in port_orientations and len(ports) > 2:
        y_max = c.ymax * 1e-6 - pe
        x_max = c.xmax * 1e-6

    elif 90 in port_orientations:
        y_max = c.ymax * 1e-6 - pe
        x_max = c.xmax * 1e-6 + ss.ymargin

    z = 0
    z_span = 2 * ss.zmargin + max(ss.layer2nm.values()) * 1e-9

    layers = component.get_layers()
    sim_settings = dict(
        simulation_settings=clean_dict(sim_settings, layers),
        component=component.get_settings(),
        version=__version__,
    )

    # filepath_sim_settings.write_text(yaml.dump(sim_settings))
    # print(filepath_sim_settings)
    # return

    try:
        import lumapi
    except ModuleNotFoundError as e:
        print(
            "Cannot import lumapi (Python Lumerical API). "
            "You can add set the PYTHONPATH variable or add it with `sys.path.append()`"
        )
        raise e
    except OSError as e:
        raise e

    start = time.time()
    s = session or lumapi.FDTD(hide=False)
    s.newproject()
    s.selectall()
    s.deleteall()
    s.addrect(
        x_min=x_min,
        x_max=x_max,
        y_min=y_min,
        y_max=y_max,
        z=z,
        z_span=z_span,
        index=1.5,
        name="clad",
    )

    material = ss.background_material
    if material not in materials:
        raise ValueError(f"{material} not in {list(materials.keys())}")
    material = materials[material]
    s.setnamed("clad", "material", material)

    s.addfdtd(
        dimension="3D",
        x_min=x_min,
        x_max=x_max,
        y_min=y_min,
        y_max=y_max,
        z=z,
        z_span=z_span,
        mesh_accuracy=ss.mesh_accuracy,
        use_early_shutoff=True,
    )

    for layer, nm in ss.layer2nm.items():
        if layer not in layers:
            continue
        assert layer in ss.layer2material, f"{layer} not in {ss.layer2material.keys()}"

        material = ss.layer2material[layer]
        if material not in materials:
            raise ValueError(f"{material} not in {list(materials.keys())}")
        material = materials[material]

        s.gdsimport(str(gdspath), c.name, f"{layer[0]}:{layer[1]}")
        silicon = f"GDS_LAYER_{layer[0]}:{layer[1]}"
        s.setnamed(silicon, "z span", nm * 1e-9)
        s.setnamed(silicon, "material", material)

    for i, port in enumerate(ports.values()):
        s.addport()
        p = f"FDTD::ports::port {i+1}"
        s.setnamed(p, "x", port.x * 1e-6)
        s.setnamed(p, "y", port.y * 1e-6)
        s.setnamed(p, "z span", ss.port_height)

        deg = int(port.orientation)
        # assert port.orientation in [0, 90, 180, 270], f"{port.orientation} needs to be [0, 90, 180, 270]"
        if -45 <= deg <= 45:
            direction = "Backward"
            injection_axis = "x-axis"
            dxp = 0
            dyp = ss.port_width
        elif 45 < deg < 90 + 45:
            direction = "Backward"
            injection_axis = "y-axis"
            dxp = ss.port_width
            dyp = 0
        elif 90 + 45 < deg < 180 + 45:
            direction = "Forward"
            injection_axis = "x-axis"
            dxp = 0
            dyp = ss.port_width
        elif 180 + 45 < deg < -45:
            direction = "Forward"
            injection_axis = "y-axis"
            dxp = ss.port_width
            dyp = 0

        else:
            raise ValueError(
                f"port {port.name} with orientation {port.orientation} is not a valid"
                " number ")

        s.setnamed(p, "direction", direction)
        s.setnamed(p, "injection axis", injection_axis)
        s.setnamed(p, "y span", dyp)
        s.setnamed(p, "x span", dxp)
        # s.setnamed(p, "theta", deg)
        s.setnamed(p, "name", port.name)

    s.setglobalsource("wavelength start", ss.wavelength_start)
    s.setglobalsource("wavelength stop", ss.wavelength_stop)
    s.setnamed("FDTD::ports", "monitor frequency points", ss.wavelength_points)

    if run:
        s.save(str(filepath_fsp))
        s.deletesweep("s-parameter sweep")

        s.addsweep(3)
        s.setsweep("s-parameter sweep", "Excite all ports", 0)
        s.setsweep("S sweep", "auto symmetry", True)
        s.runsweep("s-parameter sweep")

        # collect results
        # S_matrix = s.getsweepresult("s-parameter sweep", "S matrix")
        sp = s.getsweepresult("s-parameter sweep", "S parameters")

        # export S-parameter data to file named s_params.dat to be loaded in
        # INTERCONNECT
        s.exportsweep("s-parameter sweep", str(filepath))
        print(f"wrote sparameters to {filepath}")

        keys = [key for key in sp.keys() if key.startswith("S")]
        ra = {
            f"{key}a": list(np.unwrap(np.angle(sp[key].flatten())))
            for key in keys
        }
        rm = {f"{key}m": list(np.abs(sp[key].flatten())) for key in keys}

        wavelength_nm = sp["lambda"].flatten() * 1e9

        results = {"wavelength_nm": wavelength_nm}
        results.update(ra)
        results.update(rm)
        df = pd.DataFrame(results, index=wavelength_nm)

        end = time.time()
        sim_settings.update(compute_time_seconds=end - start)
        df.to_csv(filepath_csv, index=False)
        filepath_sim_settings.write_text(yaml.dump(sim_settings))
        return df
Esempio n. 21
0
def test_type2():
    c = pp.c.coupler(gap=0.244, length=5.67)
    c.polarization = "tm"
    cc = add_io_optical(c, optical_routing_type=2)
    pp.write_gds(cc)
    return cc
Esempio n. 22
0
from pp.component import Component


@pp.autoname
def verniers(width_min: float = 0.1,
             width_max: float = 0.5,
             gap: float = 0.1,
             size_max: int = 11) -> Component:
    c = pp.Component()
    y = 0

    widths = np.linspace(width_min, width_max,
                         int(size_max / (width_max + gap)))

    for width in widths:
        w = c << pp.c.waveguide(
            width=width, length=size_max, layers_cladding=[])
        y += width / 2
        w.y = y
        c.add(pp.c.label(str(int(width * 1e3)), position=(0, y)))
        y += width / 2 + gap

    return c


if __name__ == "__main__":
    c = verniers()
    c.flatten()
    pp.write_gds(c, "verniers.gds")
    pp.show(c)
Esempio n. 23
0
def _demo_waveguide_heater():
    c = waveguide_heater(width=0.5)
    pp.write_gds(c)
def test_compute_area(x, y, layer):
    c = pp.c.rectangle(size=(x, y), layer=layer)
    pp.write_gds(c)
    area = pp.drc.compute_area(c, layer)
    assert np.isclose(area, x * y)
Esempio n. 25
0
def test_import_gds_hierarchy():
    c0 = pp.c.mzi2x2()
    gdspath = pp.write_gds(c0)
    c = import_gds(gdspath)
    assert len(c.get_dependencies()) == 3
Esempio n. 26
0
def test_type0():
    component = pp.c.coupler(gap=0.244, length=5.67)
    cc = add_fiber_array(component, optical_routing_type=0)
    pp.write_gds(cc)
    return cc
Esempio n. 27
0
def _demo():
    c = coupler_straight(gap=0.2)
    pp.write_gds(c)
    return c
Esempio n. 28
0
import pp

characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#()+,-./:;<=>?@[{|}~_"


@pp.autoname
def alphabet(dx=10):
    c = pp.Component()
    x = 0
    for s in characters:
        ci = pp.c.text(text=s)
        ci.name = s
        char = c << ci.flatten()
        char.x = x
        x += dx

    return c


if __name__ == "__main__":
    c = alphabet()
    pp.write_gds(c, "alphabet.gds")
    pp.show(c)
Esempio n. 29
0

@pp.autoname
def snapping_error(gap=1e-3):
    c = pp.Component()
    r1 = c << pp.c.rectangle(size=(1, 1), layer=layer)
    r2 = c << pp.c.rectangle(size=(1, 1), layer=layer)
    r1.xmax = 0
    r2.xmin = gap
    return c


@pp.autoname
def errors():
    D_list = [width_min(), gap_min()]
    c = pp.pack(D_list, spacing=1.5)
    return c[0]


if __name__ == "__main__":
    # c = width_min()
    # pp.write_gds(c, "wmin.gds")
    # c = gap_min()
    # pp.write_gds(c, "gmin.gds")
    # c = snapping_error()
    # pp.write_gds(c, "snap.gds")

    c = errors()
    pp.write_gds(c, "errors.gds")
    pp.show(c)
Esempio n. 30
0
def test_type1():
    component = pp.c.coupler(gap=0.2, length=5.0)
    cc = add_io_optical(component, optical_routing_type=1)
    pp.write_gds(cc)
    return cc