Source code for gdsfactory.components.straight_heater_metal
from __future__ import annotations
from functools import partial
import gdsfactory as gf
from gdsfactory.cell import cell
from gdsfactory.component import Component
from gdsfactory.components.straight import straight as straight_function
from gdsfactory.typings import ComponentSpec, CrossSectionSpec
[docs]
@cell
def straight_heater_metal_undercut(
length: float = 320.0,
length_undercut_spacing: float = 6.0,
length_undercut: float = 30.0,
length_straight: float = 0.1,
length_straight_input: float = 15.0,
cross_section: CrossSectionSpec = "xs_sc",
cross_section_heater: CrossSectionSpec = "xs_heater_metal",
cross_section_waveguide_heater: CrossSectionSpec = "xs_sc_heater_metal",
cross_section_heater_undercut: CrossSectionSpec = "xs_sc_heater_metal_undercut",
with_undercut: bool = True,
via_stack: ComponentSpec | None = "via_stack_heater_mtop",
port_orientation1: int | None = None,
port_orientation2: int | None = None,
heater_taper_length: float | None = 5.0,
ohms_per_square: float | None = None,
straight: ComponentSpec = straight_function,
) -> Component:
"""Returns a thermal phase shifter.
dimensions from https://doi.org/10.1364/OE.27.010456
Args:
length: of the waveguide.
length_undercut_spacing: from undercut regions.
length_undercut: length of each undercut section.
length_straight: from where the trenches start to the via_stack.
length_straight_input: from input port to where trenches start.
cross_section: for waveguide ports.
cross_section_heater: for heated sections. heater metal only.
cross_section_waveguide_heater: for heated sections.
cross_section_heater_undercut: for heated sections with undercut.
with_undercut: isolation trenches for higher efficiency.
via_stack: via stack.
port_orientation1: left via stack port orientation.
port_orientation2: right via stack port orientation.
heater_taper_length: minimizes current concentrations from heater to via_stack.
ohms_per_square: to calculate resistance.
straight: straight component.
"""
period = length_undercut + length_undercut_spacing
n = int((length - 2 * length_straight_input) // period)
if n < 1:
raise ValueError("length is too short")
length_straight_input = (length - n * period) / 2
if length_straight > length_straight_input:
raise ValueError("length_straight_ must be smaller than length_straight_input")
length_straight_input -= length_straight
s_ports = gf.get_component(
straight,
cross_section=cross_section,
length=length_straight,
)
s_si = gf.get_component(
straight,
cross_section=cross_section_waveguide_heater,
length=length_straight_input,
)
cross_section_undercut = (
cross_section_heater_undercut
if with_undercut
else cross_section_waveguide_heater
)
s_uc = gf.get_component(
straight,
cross_section=cross_section_undercut,
length=length_undercut,
)
s_spacing = gf.get_component(
straight,
cross_section=cross_section_waveguide_heater,
length=length_undercut_spacing,
)
symbol_to_component = {
"_": (s_ports, "o1", "o2"),
"-": (s_si, "o1", "o2"),
"U": (s_uc, "o1", "o2"),
"H": (s_spacing, "o1", "o2"),
}
# Each character in the sequence represents a component
sequence = "_-" + n * "UH" + "-_"
c = Component()
sequence = gf.components.component_sequence(
sequence=sequence, symbol_to_component=symbol_to_component
)
c.add_ref(sequence)
c.add_ports(sequence.ports)
x = gf.get_cross_section(cross_section_heater)
heater_width = x.width
if via_stack:
via = via_stackw = via_stacke = gf.get_component(via_stack)
dx = via_stackw.get_ports_xsize() / 2 + heater_taper_length or 0
dx -= length_straight
via_stack_west = c << via_stackw
via_stack_east = c << via_stacke
via_stack_west.movex(-dx)
via_stack_east.movex(+dx + length)
valid_orientations = {p.orientation for p in via.ports.values()}
p1 = via_stack_west.get_ports_list(orientation=port_orientation1)
p2 = via_stack_east.get_ports_list(orientation=port_orientation2)
if not p1:
raise ValueError(
f"No ports for port_orientation1 {port_orientation1} in {valid_orientations}"
)
if not p2:
raise ValueError(
f"No ports for port_orientation2 {port_orientation2} in {valid_orientations}"
)
c.add_ports(p1, prefix="l_")
c.add_ports(p2, prefix="r_")
if heater_taper_length:
taper = gf.components.taper(
width1=via_stackw.ports["e1"].width,
width2=heater_width,
length=heater_taper_length,
cross_section=x,
port_types=("electrical", "electrical"),
)
taper1 = c << taper
taper2 = c << taper
taper1.connect("o1", via_stack_west.ports["e3"], allow_layer_mismatch=True)
taper2.connect("o1", via_stack_east.ports["e1"], allow_layer_mismatch=True)
c.info["resistance"] = (
ohms_per_square * heater_width * length if ohms_per_square else 0
)
return c
[docs]
@cell
def straight_heater_metal_simple(
length: float = 320.0,
cross_section_heater: CrossSectionSpec = "xs_heater_metal",
cross_section_waveguide_heater: CrossSectionSpec = "xs_sc_heater_metal",
via_stack: ComponentSpec | None = "via_stack_heater_mtop",
port_orientation1: int | None = None,
port_orientation2: int | None = None,
heater_taper_length: float | None = 5.0,
ohms_per_square: float | None = None,
straight: ComponentSpec = straight_function,
) -> Component:
"""Returns a thermal phase shifter that has properly fixed electrical connectivity to extract a suitable electrical netlist and models.
dimensions from https://doi.org/10.1364/OE.27.010456
Args:
length: of the waveguide.
cross_section_heater: for heated sections. heater metal only.
cross_section_waveguide_heater: for heated sections.
via_stack: via stack.
port_orientation1: left via stack port orientation.
port_orientation2: right via stack port orientation.
heater_taper_length: minimizes current concentrations from heater to via_stack.
ohms_per_square: to calculate resistance.
straight: straight component.
"""
c = Component()
straight_heater_section = gf.get_component(
straight,
cross_section=cross_section_waveguide_heater,
length=length,
)
c.add_ref(straight_heater_section)
c.add_ports(straight_heater_section.ports)
x = gf.get_cross_section(cross_section_heater)
heater_width = x.width
if via_stack:
via = via_stackw = via_stacke = gf.get_component(via_stack)
via_stack_west_center = straight_heater_section.size_info.cw
via_stack_east_center = straight_heater_section.size_info.ce
dx = via_stackw.get_ports_xsize() / 2 + heater_taper_length or 0
via_stack_west = c << via_stackw
via_stack_east = c << via_stacke
via_stack_west.move(via_stack_west_center - (dx, 0))
via_stack_east.move(via_stack_east_center + (dx, 0))
valid_orientations = {p.orientation for p in via.ports.values()}
p1 = via_stack_west.get_ports_list(orientation=port_orientation1)
p2 = via_stack_east.get_ports_list(orientation=port_orientation2)
if not p1:
raise ValueError(
f"No ports for port_orientation1 {port_orientation1} in {valid_orientations}"
)
if not p2:
raise ValueError(
f"No ports for port_orientation2 {port_orientation2} in {valid_orientations}"
)
# c.add_ports(p1, prefix="l_")
# c.add_ports(p2, prefix="r_")
if heater_taper_length:
taper = gf.components.taper(
width1=via_stackw.ports["e1"].width,
width2=heater_width,
length=heater_taper_length,
cross_section=x,
port_names=("e1", "e2"),
port_types=("electrical", "electrical"),
)
taper1 = c << taper
taper2 = c << taper
taper1.connect("e1", via_stack_west.ports["e3"], allow_layer_mismatch=True)
taper2.connect("e1", via_stack_east.ports["e1"], allow_layer_mismatch=True)
c.info["resistance"] = (
ohms_per_square * heater_width * length if ohms_per_square else 0
)
return c
straight_heater_metal = partial(
straight_heater_metal_undercut,
with_undercut=False,
length_straight_input=0.1,
length_undercut=5,
length_undercut_spacing=0,
)
straight_heater_metal_90_90 = partial(
straight_heater_metal,
with_undercut=False,
port_orientation1=90,
port_orientation2=90,
)
straight_heater_metal_undercut_90_90 = partial(
straight_heater_metal_undercut,
port_orientation1=90,
port_orientation2=90,
)
def test_ports() -> None:
c = straight_heater_metal(length=30.0)
assert c.ports["o2"].center[0] == 30.0, c.ports["o2"].center[0]
if __name__ == "__main__":
# test_ports()
# c = straight_heater_metal_undercut()
# print(c.ports['o2'].center[0])
# c.pprint_ports()
# c = straight_heater_metal(heater_width=5, length=50.0)
# c = straight_heater_metal_undercut(length=200, straight="straight")
# n = c.get_netlist()
c = straight_heater_metal(length=30)
# print(c.get_netlist(allow_multiple=True))
# c = straight_heater_metal_simple(length=20)
c.show(show_ports=False)
# scene = c.to_3d()
# scene.show()