Lumerical INTERCONNECT#
The Lumerical INTERCONNECT plugin in gdsfactory can run circuit simulations in INTERCONNECT directly from gdsfactory components.
This is a work-in-progress and can’t handle hierarchical components yet.
This example also requires you to install the UBC PDK, pip install ubcpdk
.
In addition, access to the Lumerical Python api through lumapi
is required. Follow instructions in lumerical_1_fdtd_sparameters.py to this end.
from collections import OrderedDict
import gdsfactory as gf
import matplotlib.pyplot as plt
import numpy as np
import ubcpdk.components as pdk
from gdsfactory.get_netlist import get_instance_name_from_alias as get_instance_name
from gdsfactory.routing import route_single
from gplugins.lumerical.interconnect import plot_wavelength_sweep, run_wavelength_sweep
gf.config.rich_output()
import lumapi
session = lumapi.INTERCONNECT()
Currently, only simulations using CMLs (compact model libraries) are supported, so this tutorial will demonstrate using the SiEPIC EBeam PDK with the ubcpdk package.
circuit = gf.Component("Circuit")
gc1 = circuit << pdk.gc_te1550()
gc2 = circuit << pdk.gc_te1550()
gc3 = circuit << pdk.gc_te1550()
gc1.drotate(180)
gc2.drotate(180)
gc3.drotate(180)
gc2.dmovey(127)
gc3.dmovey(-127)
s = circuit << pdk.y_splitter()
s.dmovex(75)
circuit.show()
circuit
route_in = route_single(gc1.ports["opt1"], s.ports["opt1"])
route_out_top = route_single(s.ports["opt2"], gc2.ports["opt1"])
route_out_bot = route_single(
s.ports["opt3"], gc3.ports["opt1"], start_straight_length=1000
)
circuit.add(route_in.references)
circuit.add(route_out_top.references)
circuit.add(route_out_bot.references)
circuit.show()
netlist = circuit.get_netlist()
gc1_netlist_instance_name = get_instance_name(circuit, gc1)
gc2_netlist_instance_name = get_instance_name(circuit, gc2)
gc3_netlist_instance_name = get_instance_name(circuit, gc3)
ports_in = {gc1_netlist_instance_name: "opt_fiber"}
ports_out = {
gc2_netlist_instance_name: "opt_fiber",
gc3_netlist_instance_name: "opt_fiber",
}
simulation_settings = OrderedDict(
[
("MC_uniformity_thickness", np.array([200, 200])),
("MC_uniformity_width", np.array([200, 200])),
("MC_non_uniform", 0),
("MC_grid", 1e-5),
("MC_resolution_x", 200),
("MC_resolution_y", 0),
]
)
results = run_wavelength_sweep(
component=circuit,
session=session,
ports_in=ports_in,
ports_out=ports_out,
simulation_settings=simulation_settings,
results=("transmission",),
component_distance_scaling=10,
setup_mc=True,
)
plot_wavelength_sweep(ports_out=ports_out, results=results, show=True)
MZI Wavelength Sweep#
mzi = pdk.mzi()
mzi
# If the ports are in the top-level cell, use a dictionary like this and
# set is_top_level to True in the call to run_wavelength_sweep
ports_in = {"o1": "o1"}
ports_out = {"o2": "o2"}
simulation_settings = OrderedDict(
[
("MC_uniformity_thickness", np.array([200, 200])),
("MC_uniformity_width", np.array([200, 200])),
("MC_non_uniform", 0),
("MC_grid", 1e-5),
("MC_resolution_x", 200),
("MC_resolution_y", 0),
]
)
results = run_wavelength_sweep(
session=session,
component=mzi,
ports_in=ports_in,
ports_out=ports_out,
results=("transmission",),
component_distance_scaling=50,
simulation_settings=simulation_settings,
setup_mc=True,
is_top_level=True,
)
plot_wavelength_sweep(
ports_out=ports_out, results=results, result_name="'TE' transmission"
)
um = 1e-6
result_name = "'TE' transmission"
for port in ports_out:
wl = results["transmission"][port]["wavelength"] / um
T = 10 * np.log10(np.abs(results["transmission"][port][result_name]))
plt.plot(wl, T, label=str(port))
plt.legend()
plt.xlabel(r"Wavelength ($\mu$m)")
plt.ylabel(f"{result_name} (dB)")
plt.show()