From 6a634e4328f8f5f5c6a788aebd2abd42167ea5ae Mon Sep 17 00:00:00 2001 From: daquintero Date: Mon, 20 May 2024 18:25:19 +0200 Subject: [PATCH] wrong netlisting --- piel/models/physical/photonic/mzi.py | 84 ++- .../photonic/straight_heater_metal.py | 535 +++++++++++++++--- 2 files changed, 496 insertions(+), 123 deletions(-) diff --git a/piel/models/physical/photonic/mzi.py b/piel/models/physical/photonic/mzi.py index 6adcbd15..745d17b9 100644 --- a/piel/models/physical/photonic/mzi.py +++ b/piel/models/physical/photonic/mzi.py @@ -25,6 +25,7 @@ def mzi( straight_y: ComponentSpec | None = None, straight_x_top: ComponentSpec | None = None, straight_x_bot: ComponentSpec | None = None, + extend_ports_straight_x: float | None = None, splitter: ComponentSpec = "mmi1x2", combiner: ComponentSpec | None = None, with_splitter: bool = True, @@ -33,11 +34,13 @@ def mzi( port_e1_combiner: str = "o2", port_e0_combiner: str = "o3", nbends: int = 2, - cross_section: CrossSectionSpec = "strip", + cross_section: CrossSectionSpec = "xs_sc", cross_section_x_top: CrossSectionSpec | None = None, cross_section_x_bot: CrossSectionSpec | None = None, mirror_bot: bool = False, add_optical_ports_arms: bool = False, + add_electrical_ports_bot: bool = True, + min_length: float = 0.01, ) -> Component: """Mzi. @@ -50,6 +53,7 @@ def mzi( straight_y: straight for length_y and delta_length. straight_x_top: top straight for length_x. straight_x_bot: bottom straight for length_x. + extend_ports_straight_x: optional extend ports for straight_x_bot/top. splitter: splitter function. combiner: combiner function. with_splitter: if False removes splitter. @@ -64,6 +68,8 @@ def mzi( mirror_bot: if true, mirrors the bottom arm. add_optical_ports_arms: add all other optical ports in the arms with top_ and bot_ prefix. + add_electrical_ports_bot: add electrical ports to the bottom arm. + min_length: minimum length for the straight_x_bot/top. .. code:: @@ -106,6 +112,21 @@ def mzi( b5.mirror() b5.connect("o1", cp1.ports[port_e0_splitter]) + straight_x_top = ( + gf.get_component( + straight_x_top, length=length_x, cross_section=cross_section_x_top + ) + if length_x + else gf.get_component(straight_x_top) + ) + + if extend_ports_straight_x: + straight_x_top = gf.c.extend_ports( + straight_x_top, length=extend_ports_straight_x + ) + + length_x = length_x or straight_x_top.get_ports_xsize() + syl = c << gf.get_component( straight_y, length=delta_length / 2 + length_y, cross_section=cross_section ) @@ -120,6 +141,10 @@ def mzi( if length_x else gf.get_component(straight_x_bot) ) + if extend_ports_straight_x: + straight_x_bot = gf.c.extend_ports( + straight_x_bot, length=extend_ports_straight_x + ) sxb = c << straight_x_bot if mirror_bot: sxb.mirror() @@ -135,19 +160,11 @@ def mzi( b2 = c << bend b2.connect("o2", sytl.ports["o2"]) - straight_x_top = ( - gf.get_component( - straight_x_top, length=length_x, cross_section=cross_section_x_top - ) - if length_x - else gf.get_component(straight_x_top) - ) sxt = c << straight_x_top sxt.connect("o1", b2.ports["o1"]) cp2.mirror() - xs = gf.get_cross_section(cross_section) - cp2.xmin = sxt.ports["o2"].x + bend.info["radius"] * nbends + 2 * xs.min_length + cp2.xmin = sxt.ports["o2"].x + bend.info["radius"] * nbends + 2 * min_length route = get_route( sxt.ports["o2"], @@ -183,9 +200,11 @@ def mzi( c.add_ports(cp2.get_ports_list(orientation=0), prefix="ou_") c.add_ports(sxt.get_ports_list(port_type="electrical"), prefix="top_") - c.add_ports(sxb.get_ports_list(port_type="electrical"), prefix="bot_") c.add_ports(sxt.get_ports_list(port_type="placement"), prefix="top_") - c.add_ports(sxb.get_ports_list(port_type="placement"), prefix="bot_") + + if add_electrical_ports_bot: + c.add_ports(sxb.get_ports_list(port_type="electrical"), prefix="bot_") + c.add_ports(sxb.get_ports_list(port_type="placement"), prefix="bot_") c.auto_rename_ports(port_type="optical", prefix="o") @@ -225,54 +244,29 @@ def mzi( ) mzi2x2_2x2_phase_shifter = partial( - mzi2x2_2x2, straight_x_top=straight_heater_metal_simple, length_x=200 -) - -mzi_phase_shifter_top_heater_metal = partial( - mzi_phase_shifter, straight_x_top=straight_heater_metal_simple + mzi2x2_2x2, + straight_x_top=straight_heater_metal_simple, + length_x=200, ) -if __name__ == "__main__": - # c = mzi_phase_shifter(splitter="mmi2x2") - # c = mzi_phase_shifter_top_heater_metal(splitter="mmi2x2") - # c = mzi_phase_shifter(splitter='mmi2x2') - # c = mzi_phase_shifter( - # straight_x_top=gf.components.straight_pin, straight_x_bot=gf.components.straight_pin - # ) - # c = mzi_phase_shifter( - # # straight_x_top=gf.components.straight_heater_doped_rib, - # straight_x_bot=gf.components.straight_heater_doped_rib, - # delta_length=20, - # length_x=600, - # ) - # c = mzi_phase_shifter() - - # c = mzi_phase_shifter() - c = mzi_phase_shifter() - c.show(show_ports=True) - print(c.name) - - c1 = mzi2x2_2x2_phase_shifter() - c1.show(show_ports=True) - print(c1.name) if __name__ == "__main__": c = mzi() - print(sorted([i.name for i in c.get_dependencies()])) + # print(sorted([i.name for i in c.get_dependencies()])) # from gdsfactory import get_generic_pdk # pdk = get_generic_pdk() # pdk.activate() - # c = mzi(cross_section="strip") + # c = mzi(cross_section="xs_sc") # c = gf.components.mzi2x2_2x2(straight_x_top="straight_heater_metal") # c.show(show_ports=True) # c = gf.components.mzi2x2_2x2(straight_x_top="straight_heater_metal") - c = gf.routing.add_fiber_array(c) - # gdspath = c.write_gds(flatten_invalid_refs=True) + # c = gf.routing.add_fiber_array(c) + # gdspath = c.write_gds(flatten_offgrid_references=True) # gf.show(gdspath) - c.show() + c.show(show_ports=True) # c1.write_gds("a.gds") diff --git a/piel/models/physical/photonic/straight_heater_metal.py b/piel/models/physical/photonic/straight_heater_metal.py index 12ced677..d1dce310 100644 --- a/piel/models/physical/photonic/straight_heater_metal.py +++ b/piel/models/physical/photonic/straight_heater_metal.py @@ -5,6 +5,7 @@ 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 @@ -13,18 +14,19 @@ 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, - heater_width: float = 2.5, - cross_section_heater: CrossSectionSpec = "heater_metal", - cross_section_waveguide_heater: CrossSectionSpec = "strip_heater_metal", - cross_section_heater_undercut: CrossSectionSpec = "strip_heater_metal_undercut", + 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, - **kwargs, + straight: ComponentSpec = straight_function, ) -> Component: """Returns a thermal phase shifter. @@ -34,8 +36,9 @@ def straight_heater_metal_undercut( 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. - heater_width: in um. + 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. @@ -45,46 +48,56 @@ def straight_heater_metal_undercut( port_orientation2: right via stack port orientation. heater_taper_length: minimizes current concentrations from heater to via_stack. ohms_per_square: to calculate resistance. - cross_section: for waveguide ports. - kwargs: cross_section common settings. + straight: straight component. """ period = length_undercut + length_undercut_spacing n = int((length - 2 * length_straight_input) // period) - kwargs.pop("cross_section", "") + + if n < 1: + raise ValueError("length is too short") length_straight_input = (length - n * period) / 2 - s_si = gf.components.straight( + 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, - heater_width=heater_width, - **kwargs, ) cross_section_undercut = ( cross_section_heater_undercut if with_undercut else cross_section_waveguide_heater ) - s_uc = gf.components.straight( + s_uc = gf.get_component( + straight, cross_section=cross_section_undercut, length=length_undercut, - heater_width=heater_width, - **kwargs, ) - s_spacing = gf.components.straight( + s_spacing = gf.get_component( + straight, cross_section=cross_section_waveguide_heater, length=length_undercut_spacing, - heater_width=heater_width, - **kwargs, ) 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" + "-" + sequence = "_-" + n * "UH" + "-_" c = Component() sequence = gf.components.component_sequence( @@ -93,17 +106,19 @@ def straight_heater_metal_undercut( c.add_ref(sequence) c.add_ports(sequence.ports) + x = gf.get_cross_section(cross_section_heater) + heater_width = x.width + if via_stack: - refs = list(sequence.named_references.keys()) via = via_stackw = via_stacke = gf.get_component(via_stack) - via_stack_west_center = sequence.named_references[refs[0]].size_info.cw - via_stack_east_center = sequence.named_references[refs[-1]].size_info.ce 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.move(via_stack_west_center - (dx, 0)) - via_stack_east.move(via_stack_east_center + (dx, 0)) + + 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) @@ -120,80 +135,101 @@ def straight_heater_metal_undercut( c.add_ports(p1, prefix="l_") c.add_ports(p2, prefix="r_") + if heater_taper_length: - x = gf.get_cross_section(cross_section_heater, width=heater_width) 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"]) - taper2.connect("o1", via_stack_east.ports["e1"]) + 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 None + ohms_per_square * heater_width * length if ohms_per_square else 0 ) return c -@cell def straight_heater_metal_simple( length: float = 320.0, - length_straight_input: float = 15.0, - heater_width: float = 2.5, - cross_section_heater: CrossSectionSpec = "heater_metal", - cross_section_waveguide_heater: CrossSectionSpec = "strip_heater_metal", + length_straight: float = 0.1, + cross_section: CrossSectionSpec = "xs_sc", + 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, - **kwargs, + straight: ComponentSpec = straight_function, ) -> Component: - """Returns a thermal phase shifter that has properly fixed electrical connectivity to extract a suitable electrical netlist and models. + """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_input: from input port to where trenches start. - heater_width: in um. + length_straight: from where the trenches start to the via_stack. + 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. - cross_section: for waveguide ports. - kwargs: cross_section common settings. + straight: straight component. """ - c = Component() - straight_heater_section = gf.components.straight( + + length_straight_input = (length) / 2 + length_straight_input -= length_straight + + s_ports = gf.get_component( + straight, + cross_section=cross_section, + length=length_straight_input, + ) + + s_si = gf.get_component( + straight, cross_section=cross_section_waveguide_heater, length=length, - heater_width=heater_width, - # **kwargs # Note cross section is set from the provided, no more settings should be set ) - c.add_ref(straight_heater_section) - c.add_ports(straight_heater_section.ports) + symbol_to_component = { + "_": (s_ports, "o1", "o2"), + "-": (s_si, "o1", "o2"), + } + + # Each character in the sequence represents a component + # sequence = "_-" + n * "UH" + "-_" + sequence = "_-_" + + 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) - 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 + dx -= length_straight 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)) + + 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) @@ -208,60 +244,403 @@ def straight_heater_metal_simple( f"No ports for port_orientation2 {port_orientation2} in {valid_orientations}" ) - # c.add_ports(p1, prefix="l_") - # c.add_ports(p2, prefix="r_") + c.add_ports(p1, prefix="l_") + c.add_ports(p2, prefix="r_") + if heater_taper_length: - x = gf.get_cross_section(cross_section_heater, width=heater_width) taper = gf.components.taper( width1=via_stackw.ports["e1"].width, width2=heater_width, length=heater_taper_length, cross_section=x, - port_order_name=("e1", "e2"), - port_order_types=("electrical", "electrical"), + port_types=("electrical", "electrical"), ) taper1 = c << taper taper2 = c << taper - taper1.connect("e1", via_stack_west.ports["e3"]) - taper2.connect("e1", via_stack_east.ports["e1"]) + 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 None + ohms_per_square * heater_width * length if ohms_per_square else 0 ) return c +# @cell +# def straight_heater_metal_simple( +# length: float = 320.0, +# cross_section: CrossSectionSpec = "xs_sc", +# 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_undercut, + straight_heater_metal, with_undercut=False, port_orientation1=90, port_orientation2=90, ) straight_heater_metal_undercut_90_90 = partial( straight_heater_metal_undercut, - with_undercut=False, port_orientation1=90, port_orientation2=90, ) def test_ports() -> None: - c = straight_heater_metal(length=50.0) - assert c.ports["o2"].center[0] == 50.0, c.ports["o2"].center[0] - - -if __name__ == "__main__": - # 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(length=40) - # n = c.get_netlist() - c.show(show_ports=True) - # scene = c.to_3d() - # scene.show() + c = straight_heater_metal(length=30.0) + assert c.ports["o2"].center[0] == 30.0, c.ports["o2"].center[0] + + +# from __future__ import annotations +# +# from functools import partial +# +# import gdsfactory as gf +# from gdsfactory.cell import cell +# from gdsfactory.component import Component +# from gdsfactory.typings import ComponentSpec, CrossSectionSpec +# +# +# @cell +# def straight_heater_metal_undercut( +# length: float = 320.0, +# length_undercut_spacing: float = 6.0, +# length_undercut: float = 30.0, +# length_straight_input: float = 15.0, +# heater_width: float = 2.5, +# cross_section_heater: CrossSectionSpec = "heater_metal", +# cross_section_waveguide_heater: CrossSectionSpec = "strip_heater_metal", +# cross_section_heater_undercut: CrossSectionSpec = "strip_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, +# **kwargs, +# ) -> 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_input: from input port to where trenches start. +# heater_width: in um. +# 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. +# cross_section: for waveguide ports. +# kwargs: cross_section common settings. +# """ +# period = length_undercut + length_undercut_spacing +# n = int((length - 2 * length_straight_input) // period) +# kwargs.pop("cross_section", "") +# +# length_straight_input = (length - n * period) / 2 +# +# s_si = gf.components.straight( +# cross_section=cross_section_waveguide_heater, +# length=length_straight_input, +# heater_width=heater_width, +# **kwargs, +# ) +# cross_section_undercut = ( +# cross_section_heater_undercut +# if with_undercut +# else cross_section_waveguide_heater +# ) +# s_uc = gf.components.straight( +# cross_section=cross_section_undercut, +# length=length_undercut, +# heater_width=heater_width, +# **kwargs, +# ) +# s_spacing = gf.components.straight( +# cross_section=cross_section_waveguide_heater, +# length=length_undercut_spacing, +# heater_width=heater_width, +# **kwargs, +# ) +# symbol_to_component = { +# "-": (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) +# +# if via_stack: +# refs = list(sequence.named_references.keys()) +# via = via_stackw = via_stacke = gf.get_component(via_stack) +# via_stack_west_center = sequence.named_references[refs[0]].size_info.cw +# via_stack_east_center = sequence.named_references[refs[-1]].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: +# x = gf.get_cross_section(cross_section_heater, width=heater_width) +# taper = gf.components.taper( +# width1=via_stackw.ports["e1"].width, +# width2=heater_width, +# length=heater_taper_length, +# cross_section=x, +# ) +# taper1 = c << taper +# taper2 = c << taper +# taper1.connect("o1", via_stack_west.ports["e3"]) +# taper2.connect("o1", via_stack_east.ports["e1"]) +# +# c.info["resistance"] = ( +# ohms_per_square * heater_width * length if ohms_per_square else None +# ) +# return c +# +# +# @cell +# def straight_heater_metal_simple( +# length: float = 320.0, +# length_straight_input: float = 15.0, +# heater_width: float = 2.5, +# cross_section_heater: CrossSectionSpec = "heater_metal", +# cross_section_waveguide_heater: CrossSectionSpec = "strip_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, +# **kwargs, +# ) -> 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. +# length_undercut_spacing: from undercut regions. +# length_undercut: length of each undercut section. +# length_straight_input: from input port to where trenches start. +# heater_width: in um. +# 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. +# cross_section: for waveguide ports. +# kwargs: cross_section common settings. +# """ +# c = Component() +# straight_heater_section = gf.components.straight( +# cross_section=cross_section_waveguide_heater, +# length=length, +# heater_width=heater_width, +# # **kwargs # Note cross section is set from the provided, no more settings should be set +# ) +# +# c.add_ref(straight_heater_section) +# c.add_ports(straight_heater_section.ports) +# +# 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: +# x = gf.get_cross_section(cross_section_heater, width=heater_width) +# taper = gf.components.taper( +# width1=via_stackw.ports["e1"].width, +# width2=heater_width, +# length=heater_taper_length, +# cross_section=x, +# port_order_name=("e1", "e2"), +# port_order_types=("electrical", "electrical"), +# ) +# taper1 = c << taper +# taper2 = c << taper +# taper1.connect("e1", via_stack_west.ports["e3"]) +# taper2.connect("e1", via_stack_east.ports["e1"]) +# +# c.info["resistance"] = ( +# ohms_per_square * heater_width * length if ohms_per_square else None +# ) +# return c +# +# +# straight_heater_metal = partial( +# straight_heater_metal_undercut, +# with_undercut=False, +# ) +# straight_heater_metal_90_90 = partial( +# straight_heater_metal_undercut, +# with_undercut=False, +# port_orientation1=90, +# port_orientation2=90, +# ) +# straight_heater_metal_undercut_90_90 = partial( +# straight_heater_metal_undercut, +# with_undercut=False, +# port_orientation1=90, +# port_orientation2=90, +# ) +# +# +# def test_ports() -> None: +# c = straight_heater_metal(length=50.0) +# assert c.ports["o2"].center[0] == 50.0, c.ports["o2"].center[0] +# +# +# if __name__ == "__main__": +# # 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(length=40) +# # n = c.get_netlist() +# c.show(show_ports=True) +# # scene = c.to_3d() +# # scene.show()