Source code for gdsfactory.components.mzi

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.bend_euler import bend_euler
from gdsfactory.components.coupler import coupler
from gdsfactory.components.mmi1x2 import mmi1x2
from gdsfactory.components.mmi2x2 import mmi2x2
from gdsfactory.components.straight import straight as straight_function
from gdsfactory.routing.get_route import get_route
from gdsfactory.typings import ComponentSpec, CrossSectionSpec


[docs] @cell def mzi( delta_length: float = 10.0, length_y: float = 2.0, length_x: float | None = 0.1, bend: ComponentSpec = bend_euler, straight: ComponentSpec = straight_function, 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, port_e1_splitter: str = "o2", port_e0_splitter: str = "o3", port_e1_combiner: str = "o2", port_e0_combiner: str = "o3", nbends: int = 2, 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. Args: delta_length: bottom arm vertical extra length. length_y: vertical length for both and top arms. length_x: horizontal length. None uses to the straight_x_bot/top defaults. bend: 90 degrees bend library. straight: straight function. 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. port_e1_splitter: east top splitter port. port_e0_splitter: east bot splitter port. port_e1_combiner: east top combiner port. port_e0_combiner: east bot combiner port. nbends: from straight top/bot to combiner (at least 2). cross_section: for routing (sxtop/sxbot to combiner). cross_section_x_top: optional top cross_section (defaults to cross_section). cross_section_x_bot: optional bottom cross_section (defaults to cross_section). 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:: b2______b3 | sxtop | straight_y | | | b1 b4 splitter==| |==combiner b5 b8 | | straight_y | | | delta_length/2 | | | b6__sxbot__b7 Lx """ combiner = combiner or splitter straight_x_top = straight_x_top or straight straight_x_bot = straight_x_bot or straight straight_y = straight_y or straight cross_section_x_bot = cross_section_x_bot or cross_section cross_section_x_top = cross_section_x_top or cross_section bend_spec = bend bend = gf.get_component(bend, cross_section=cross_section) c = Component() cp1 = gf.get_component(splitter) cp2 = gf.get_component(combiner) if combiner else cp1 if with_splitter: cp1 = c << cp1 cp2 = c << cp2 b5 = c << bend 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 ) syl.connect("o1", b5.ports["o2"]) b6 = c << bend b6.connect("o1", syl.ports["o2"]) straight_x_bot = ( gf.get_component( straight_x_bot, length=length_x, cross_section=cross_section_x_bot ) 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() sxb.connect("o1", b6.ports["o2"]) b1 = c << bend b1.connect("o1", cp1.ports[port_e1_splitter]) sytl = c << gf.get_component( straight_y, length=length_y, cross_section=cross_section ) sytl.connect("o1", b1.ports["o2"]) b2 = c << bend b2.connect("o2", sytl.ports["o2"]) sxt = c << straight_x_top sxt.connect("o1", b2.ports["o1"]) cp2.mirror() cp2.xmin = sxt.ports["o2"].x + bend.info["radius"] * nbends + 2 * min_length route = get_route( sxt.ports["o2"], cp2.ports[port_e1_combiner], straight=straight, bend=bend_spec, cross_section=cross_section, with_sbend=False, ) c.add(route.references) route = get_route( sxb.ports["o2"], cp2.ports[port_e0_combiner], straight=straight, bend=bend_spec, cross_section=cross_section, with_sbend=False, ) c.add(route.references) sytl.name = "sytl" syl.name = "syl" sxt.name = "sxt" sxb.name = "sxb" cp1.name = "cp1" cp2.name = "cp2" if with_splitter: c.add_ports(cp1.get_ports_list(orientation=180), prefix="in_") else: c.add_port("o1", port=b1.ports["o1"]) c.add_port("o2", port=b5.ports["o1"]) 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(sxt.get_ports_list(port_type="placement"), prefix="top_") 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") if add_optical_ports_arms: c.add_ports(sxt.get_ports_list(port_type="optical"), prefix="top_") c.add_ports(sxb.get_ports_list(port_type="optical"), prefix="bot_") return c
mzi1x2 = partial(mzi, splitter=mmi1x2, combiner=mmi1x2) mzi2x2_2x2 = partial( mzi, splitter=mmi2x2, combiner=mmi2x2, port_e1_splitter="o3", port_e0_splitter="o4", port_e1_combiner="o3", port_e0_combiner="o4", ) mzi1x2_2x2 = partial( mzi, combiner=mmi2x2, port_e1_combiner="o3", port_e0_combiner="o4", ) mzi_coupler = partial( mzi2x2_2x2, splitter=coupler, combiner=coupler, ) mzi_phase_shifter = partial(mzi, straight_x_top="straight_heater_metal", length_x=200) mzi2x2_2x2_phase_shifter = partial( mzi2x2_2x2, straight_x_top="straight_heater_metal", length_x=200 ) if __name__ == "__main__": c = mzi() # 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="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_offgrid_references=True) # gf.show(gdspath) c.show(show_ports=True) # c1.write_gds("a.gds") # c2 = gf.read.import_gds("a.gds") # c2 = c2.flatten() # c3 = gf.grid([c2, c1]) # c3.show(show_ports=False)