from __future__ import annotations
from functools import partial
import gdsfactory as gf
from gdsfactory.component import Component
from gdsfactory.components.bend_euler import bend_euler
from gdsfactory.components.coupler_ring import coupler_ring
from gdsfactory.components.straight import straight
from gdsfactory.components.via_stack import via_stack_heater_m3
from gdsfactory.typings import ComponentFactory, ComponentSpec, CrossSectionSpec, Float2
via_stack_heater_m3_mini = partial(via_stack_heater_m3, size=(4, 4))
[docs]
@gf.cell
def ring_double_heater(
gap: float = 0.2,
gap_top: float | None = None,
radius: float = 10.0,
length_x: float = 1.0,
length_y: float = 0.01,
coupler_ring: ComponentFactory = coupler_ring,
coupler_ring_top: ComponentFactory | None = None,
straight: ComponentFactory = straight,
straight_heater: ComponentFactory = straight,
bend: ComponentFactory = bend_euler,
cross_section_heater: CrossSectionSpec = "xs_heater_metal",
cross_section_waveguide_heater: CrossSectionSpec = "xs_sc_heater_metal",
cross_section: CrossSectionSpec = "xs_sc",
via_stack: ComponentSpec = via_stack_heater_m3_mini,
port_orientation: float | Float2 | None = None,
via_stack_offset: Float2 = (1, 0),
) -> Component:
"""Returns a double bus ring with heater on top.
two couplers (ct: top, cb: bottom)
connected with two vertical straights (sl: left, sr: right)
Args:
gap: gap between bottom coupler waveguides.
gap_top: optional gap between top waveguides. Defaults to gap.
radius: for the bend and coupler.
length_x: ring coupler length.
length_y: vertical straight length.
coupler_ring: ring coupler spec.
coupler_ring_top: ring coupler spec for coupler away from vias (defaults to coupler_ring)
straight: straight spec.
bend: bend spec.
cross_section_heater: for heater.
cross_section_waveguide_heater: for waveguide with heater.
cross_section: for regular waveguide.
via_stack: for heater to routing metal.
port_orientation: for electrical ports to promote from via_stack. Tuple allows the left and right contacts to be defined differently.
via_stack_offset: x,y offset for via_stack.
.. code::
o2──────▲─────────o3
│gap_top
xx──────▼─────────xxx
xxx xxx
xxx xxx
xx xxx
x xxx
xx xx▲
xx xx│length_y
xx xx▼
xx xx
xx length_x x
xx ◄───────────────► x
xx xxx
xx xxx
xxx──────▲─────────xxx
│gap
o1──────▼─────────o4
"""
gap_top = gap_top or gap
gap = gf.snap.snap_to_grid(gap, grid_factor=2)
gap_top = gf.snap.snap_to_grid(gap_top, grid_factor=2)
coupler_ring_top = coupler_ring_top or coupler_ring
coupler_component = coupler_ring(
gap=gap,
radius=radius,
length_x=length_x,
bend=bend,
cross_section=cross_section,
cross_section_bend=cross_section_waveguide_heater,
)
coupler_component_top = gf.get_component(
coupler_ring_top,
gap=gap_top,
radius=radius,
length_x=length_x,
bend=bend,
cross_section=cross_section,
cross_section_bend=cross_section_waveguide_heater,
)
straight_component = straight(
length=length_y,
cross_section=cross_section_waveguide_heater,
)
c = Component()
cb = c.add_ref(coupler_component)
ct = c.add_ref(coupler_component_top)
sl = c.add_ref(straight_component)
sr = c.add_ref(straight_component)
sl.connect(port="o1", destination=cb.ports["o2"])
ct.connect(port="o3", destination=sl.ports["o2"])
sr.connect(port="o2", destination=ct.ports["o2"])
c.add_port("o1", port=cb.ports["o1"])
c.add_port("o2", port=cb.ports["o4"])
c.add_port("o3", port=ct.ports["o4"])
c.add_port("o4", port=ct.ports["o1"])
via = gf.get_component(via_stack)
c1 = c << via
c2 = c << via
c1.xmax = -length_x / 2 + cb.x - via_stack_offset[0]
c2.xmin = +length_x / 2 + cb.x + via_stack_offset[0]
c1.movey(via_stack_offset[1])
c2.movey(via_stack_offset[1])
if isinstance(port_orientation, float) or port_orientation is None:
port_orientation = [port_orientation, port_orientation]
p1 = c1.get_ports_list(orientation=port_orientation[0])
p2 = c2.get_ports_list(orientation=port_orientation[1])
valid_orientations = {p.orientation for p in via.ports.values()}
if not p1:
raise ValueError(
f"No ports found for port_orientation {port_orientation[0]} in {valid_orientations}"
)
if not p2:
raise ValueError(
f"No ports found for port_orientation {port_orientation[1]} in {valid_orientations}"
)
c.add_ports(p1, prefix="l_")
c.add_ports(p2, prefix="r_")
heater_top = c << straight_heater(
length=length_x,
cross_section=cross_section_heater,
)
heater_top.connect("e1", ct["e1"])
return c
if __name__ == "__main__":
c = ring_double_heater(
radius=10, length_x=1, length_y=10, gap=0.2, port_orientation=(180, 0)
)
c.show(show_subports=True, show_ports=True)
c.show()