New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
complex circuit simulation #667
Comments
I am not completely sure what you mean @joamatab. But if your intention is to ignore some lower level components, this can be done by just adding a model for a subcircuit higher in the dependency tree. See for example the SAX Circuit documentation On the other hand, missing components can be stubbed by just adding a |
I added with passthrough, now I don't see any light coming out |
Because we use lossless couplers the sum of all powers should be T=100% |
The euler bends impart some loss to the system
Eliminating that source of loss does however only yield a factor of 10 more power out: |
So the problem seems to be with
the expected behavior is reached. As has been suggested by @flaport this leverages cutting the dependency tree by providing a model at a higher hierarchy.
However, I find the fact that the autogenerated hash has to be included in the model assignment rather uncomfortable (and probably less reliable/reproducible?). |
The changed code for reference """FIXME.
"""
import numpy as np
import matplotlib.pyplot as plt
import jax.numpy as jnp
import sax
import gdsfactory as gf
from sax.circuit import create_dag, draw_dag, _validate_net
def straight(wl=1.5, length=10.0, neff=2.4) -> sax.SDict:
return sax.reciprocal({("o1", "o2"): jnp.exp(2j * jnp.pi * neff * length / wl)})
def mmi1x2() -> sax.SDict:
"""Returns an ideal 1x2 splitter."""
return sax.reciprocal(
{
("o1", "o2"): 0.5**0.5,
("o1", "o3"): 0.5**0.5,
}
)
def mmi2x2(*, coupling: float = 0.5) -> sax.SDict:
"""Returns an ideal 2x2 splitter.
Args:
coupling: power coupling coefficient.
"""
kappa = coupling**0.5
tau = (1 - coupling) ** 0.5
return sax.reciprocal(
{
("o1", "o4"): tau,
("o1", "o3"): 1j * kappa,
("o2", "o4"): 1j * kappa,
("o2", "o3"): tau,
}
)
def bend_euler(wl: float = 1.5, length: float = 20.0, loss: float = 50e-3) -> sax.SDict:
"""Returns bend Sparameters."""
loss = 0
amplitude = jnp.asarray(10 ** (-loss * length / 20), dtype=complex)
return {k: amplitude * v for k, v in straight(wl=wl, length=length).items()}
def phase_shifter(
wl: float = 1.55,
neff: float = 2.34,
voltage: float = 0,
length: float = 10,
loss: float = 0.0,
) -> sax.SDict:
"""Returns simple phase shifter model.
Args:
wl: wavelength in um.
neff: effective index.
voltage: voltage per PI phase shift.
length: in um.
loss: in dB.
"""
deltaphi = voltage * jnp.pi
phase = 2 * jnp.pi * neff * length / wl + deltaphi
amplitude = jnp.asarray(10 ** (-loss * length / 20), dtype=complex)
transmission = amplitude * jnp.exp(1j * phase)
return sax.reciprocal(
{
("o1", "o2"): transmission,
}
)
models = {
"bend_euler": bend_euler,
"mmi1x2": mmi1x2,
"mmi2x2": mmi2x2,
"straight": straight,
"taper": straight,
"straight_heater_metal_u_5d466884": phase_shifter,
"compass": sax.models.passthru(10),
"via": sax.models.passthru(10),
}
if __name__ == "__main__":
print("starting test")
c = gf.components.switch_tree(bend_s=None, noutputs=4)
# c = gf.components.mzi1x2_2x2(combiner=gf.components.mmi2x2,
# delta_length=0,
# straight_x_top=gf.components.straight_heater_metal,
# length_x=None)
# c = gf.components.mzi1x2_2x2(combiner=gf.components.mmi2x2, straight_x_top=gf.components.straight_heater_metal)
# #c = gf.components.straight_heater_metal()
c.show(show_ports=True)
n = netlist = c.get_netlist_recursive(
exclude_port_types=("electrical", "placement")
)
# netlist.pop(list(n.keys())[0])
# c.plot_netlist()
# print(netlist)
mzi_circuit, _ = sax.circuit(netlist=netlist, models=models)
dag = create_dag(netlist=_validate_net(netlist), models=models)
draw_dag(dag)
wl = np.linspace(1.5, 1.6, 256)
S = mzi_circuit(wl=wl)
plt.figure(figsize=(14, 4))
plt.title("MZI")
print(S.keys())
# plt.plot(1e3 * wl, jnp.abs(S["o1", "o1"]) ** 2)
# plt.plot(1e3 * wl, jnp.abs(S["o1", "o2"]) ** 2)
# plt.plot(1e3 * wl, jnp.abs(S["o1", "o3"]) ** 2)
plt.plot(1e3 * wl, jnp.abs(S["o1_0_0", "o2_1_9"]) ** 2)
plt.plot(1e3 * wl, jnp.abs(S["o1_0_0", "o3_1_6"]) ** 2, "--")
plt.plot(1e3 * wl, jnp.abs(S["o1_0_0", "o2_1_5"]) ** 2)
plt.plot(1e3 * wl, jnp.abs(S["o1_0_0", "o3_1_10"]) ** 2, "--")
#plt.plot(1e3 * wl, jnp.abs(S["o1_0_0", "o3_2_10"]) ** 2)
plt.xlabel("λ [nm]")
plt.ylabel("T")
plt.grid(True)
plt.show() |
Definitely a good question. The lower graph is the dependency graph and not the netlist, correct? I think the way the netlist is displayed is quite good with |
About the original error: I suspect it is caused by sax handling components starting with a |
|
Concluding that we should try to avoid |
@flaport Would it be thinkable to give a warning in cases the naming scheme is violated? |
I've open a SAX issue above. I'll try to implement something like this asap. |
I think this issue has been solved, let us know if there is something that needs to be done on the gdsfactory side |
The text was updated successfully, but these errors were encountered: