Source code for gdsfactory.components.ring_crow_couplers
from __future__ import annotations
import numpy as np
import gdsfactory as gf
from gdsfactory.component import Component
from gdsfactory.components.bend_circular import bend_circular
from gdsfactory.components.coupler import coupler
from gdsfactory.cross_section import strip
from gdsfactory.typings import ComponentSpec, CrossSectionSpec
[docs]
@gf.cell
def ring_crow_couplers(
radius: list[float] = [10.0] * 3,
bends: list[ComponentSpec] = [bend_circular] * 3,
ring_cross_sections: list[CrossSectionSpec] = [strip] * 3,
couplers: list[ComponentSpec] = [coupler] * 4,
) -> Component:
"""Coupled ring resonators with coupler components between gaps.
Args:
gap: gap between for coupler.
radius: for the bend and coupler.
length_x: ring coupler length.
length_y: vertical straight length.
coupler: ring coupler spec.
straight: straight spec.
bend: bend spec.
cross_section: cross_section spec.
couplers: coupling component between rings and bus.
.. code::
--==ct==-- gap[N-1] <------- couplers[N-1]
| |
sl sr ring[N-1]
| |
--==cb==-- gap[N-2] <------- couplers[N-2]
.
.
.
--==ct==--
| |
sl sr lengths_y[1], ring[1]
| |
--==cb==-- gap[1]
<------- couplers[1]
--==ct==--
| |
sl sr lengths_y[0], ring[0]
| |
--==cb==-- gap[0] <------- couplers[0]
length_x
"""
c = Component()
couplers_refs = []
for _coupler in couplers:
coupler_ref = c.add_ref(gf.get_component(_coupler))
couplers_refs.append(coupler_ref)
# Input bus
c.add_port(name="o1", port=couplers_refs[0].ports["o1"])
c.add_port(name="o2", port=couplers_refs[0].ports["o4"])
# Cascade rings
for index, (r, bend, cross_section) in enumerate(
zip(radius, bends, ring_cross_sections)
):
# Add ring
bend_c = gf.get_component(bend, radius=r, cross_section=cross_section)
bend1 = c.add_ref(bend_c, alias=f"bot_right_bend_ring_{index}")
bend2 = c.add_ref(bend_c, alias=f"top_right_bend_ring_{index}")
bend3 = c.add_ref(bend_c, alias=f"top_left_bend_ring_{index}")
bend4 = c.add_ref(bend_c, alias=f"bot_left_bend_ring_{index}")
# We need to account for the chance that the top and bottom couplers
# have a different length --> In this case we need to add straights
coup1_extent = couplers_refs[index].xmax - couplers_refs[index].xmin
coup2_extent = couplers_refs[index + 1].xmax - couplers_refs[index + 1].xmin
if coup1_extent == coup2_extent:
# Length of the couplers is the same -- we are good
bend1.connect("o1", couplers_refs[index].ports["o3"])
bend2.connect("o1", bend1.ports["o2"])
couplers_refs[index + 1].connect("o4", bend2.ports["o2"])
bend3.connect("o1", couplers_refs[index + 1].ports["o1"])
bend4.connect("o1", bend3.ports["o2"])
else:
str_len = np.abs(coup1_extent - coup2_extent) / 2
str_sec = gf.components.straight(
cross_section=cross_section, length=str_len
)
str1 = c << str_sec
str2 = c << str_sec
if coup1_extent > coup2_extent:
# The straight are connected to coupler 2
bend1.connect("o1", couplers_refs[index].ports["o3"])
bend2.connect("o1", bend1.ports["o2"])
str1.connect("o1", bend2.ports["o2"])
couplers_refs[index + 1].connect("o4", str1.ports["o2"])
str2.connect("o1", couplers_refs[index + 1].ports["o1"])
bend3.connect("o1", str2.ports["o2"])
bend4.connect("o1", bend3.ports["o2"])
else:
# The straights are connected to coupler 1
str1.connect("o1", couplers_refs[index].ports["o3"])
str2.connect("o2", couplers_refs[index].ports["o2"])
bend1.connect("o1", str1.ports["o2"])
bend2.connect("o1", bend1.ports["o2"])
couplers_refs[index + 1].connect("o4", bend2.ports["o2"])
bend3.connect("o1", couplers_refs[index + 1].ports["o1"])
bend4.connect("o1", bend3.ports["o2"])
# Output bus
c.add_port(name="o3", port=couplers_refs[-1].ports["o2"])
c.add_port(name="o4", port=couplers_refs[-1].ports["o3"])
return c
if __name__ == "__main__":
c = ring_crow_couplers(
# couplers=[gf.components.coupler_full(coupling_length=0.01, dw=0)] * 4
)
c.show(show_ports=True, show_subports=False)
print(c.named_references["bot_right_bend_ring_0"].ports)