def add_padding_container( component: Component, layers: Tuple[Layer, ...] = (LAYER.PADDING, ), **kwargs, ) -> Component: """Returns new component with padding added. Args: component layers: list of layers default: default padding top: north padding bottom: south padding right: east padding left: west padding """ c = Component() c.component = component cref = c << component points = get_padding_points(component, **kwargs) for layer in layers: c.add_polygon(points, layer=layer) c.ports = cref.ports c.copy_child_info(component) return c
def add_text( component: ComponentOrFactory, text: str = "", text_offset: Float2 = (0, 0), text_anchor: Anchor = "cc", text_factory: ComponentFactory = text_rectangular_multi_layer, ) -> Component: """Returns component inside a new component with text geometry. Args: component: text: text string. text_offset: relative to component anchor. Defaults to center (cc). text_anchor: relative to component (ce cw nc ne nw sc se sw center cc). text_factory: function to add text labels. """ component = component() if callable(component) else component component_new = Component() component_new.component = component ref = component_new.add_ref(component) t = component_new << text_factory(text) t.move((np.array(text_offset) + getattr(ref.size_info, text_anchor))) component_new.add_ports(ref.ports) component_new.copy_child_info(component) return component_new
def add_electrical_pads_shortest( component: Component, pad: ComponentOrFactory = pad_function, pad_port_spacing: float = 50.0, select_ports=select_ports_electrical, port_orientation: int = 90, layer: gf.types.Layer = (31, 0), **kwargs, ) -> Component: """Add pad to each closest electrical port. Args: component: pad: pad element or function pad_port_spacing: between pad and port select_ports: function port_orientation layer: for the routing **kwargs: pad_settings """ c = Component() c.component = component ref = c << component ports = select_ports(ref.ports) ports = list(ports.values()) pad = pad(**kwargs) if callable(pad) else pad pad_port_spacing += pad.info_child.full["size"][0] / 2 for port in ports: p = c << pad if port_orientation == 0: p.x = port.x + pad_port_spacing p.y = port.y c.add(route_quad(port, p.ports["e1"], layer=layer)) elif port_orientation == 180: p.x = port.x - pad_port_spacing p.y = port.y c.add(route_quad(port, p.ports["e3"], layer=layer)) elif port_orientation == 90: p.y = port.y + pad_port_spacing p.x = port.x c.add(route_quad(port, p.ports["e4"], layer=layer)) elif port_orientation == 270: p.y = port.y - pad_port_spacing p.x = port.x c.add(route_quad(port, p.ports["e2"], layer=layer)) c.add_ports(ref.ports) for port in ports: c.ports.pop(port.name) c.copy_child_info(component) return c
def move( component: Component, origin=(0, 0), destination=None, axis: Optional[str] = None, ) -> Component: """Return container that contains a reference to the original component.""" component_new = Component() component_new.component = component ref = component_new.add_ref(component) ref.move(origin=origin, destination=destination, axis=axis) component_new.add_ports(ref.ports) component_new.copy_child_info(component) return component_new
def mirror(component: Component, p1: Float2 = (0, 1), p2: Float2 = (0, 0)) -> Component: """Returns mirrored component inside a new component. Args: p1: first point to define mirror axis p2: second point to define mirror axis """ component_new = Component() component_new.component = component ref = component_new.add_ref(component) ref.mirror(p1=p1, p2=p2) component_new.add_ports(ref.ports) component_new.copy_child_info(component) return component_new
def add_grating_couplers( component: Component, grating_coupler: ComponentFactory = grating_coupler_te, layer_label: Tuple[int, int] = (200, 0), gc_port_name: str = "o1", get_input_labels_function: Callable[..., List[Label]] = get_input_labels, select_ports: Callable = select_ports_optical, component_name: Optional[str] = None, ) -> Component: """Returns new component with grating couplers and labels. Args: component: to add grating_couplers grating_coupler: grating_coupler function layer_label: for label gc_port_name: where to add label get_input_labels_function: function to get label select_ports: for selecting optical_ports """ c = Component() c.component = component component_name = component_name or component.info_child.name c.add_ref(component) grating_coupler = ( grating_coupler() if callable(grating_coupler) else grating_coupler ) io_gratings = [] optical_ports = select_ports(component.ports) optical_ports = list(optical_ports.values()) for port in optical_ports: gc_ref = grating_coupler.ref() gc_port = gc_ref.ports[gc_port_name] gc_ref.connect(gc_port, port) io_gratings.append(gc_ref) c.add(gc_ref) labels = get_input_labels_function( io_gratings, list(component.ports.values()), component_name=component_name, layer_label=layer_label, gc_port_name=gc_port_name, ) c.add(labels) c.copy_child_info(component) return c
def rotate( component: ComponentOrFactory, angle: int = 90, ) -> Component: """Returns rotated component inside a new component. Most times you just need to place a reference and rotate it. This rotate function just encapsulates the rotated reference into a new component. Args: component: angle: in degrees """ component = component() if callable(component) else component component_new = Component() component_new.component = component ref = component_new.add_ref(component) ref.rotate(angle) component_new.add_ports(ref.ports) component_new.copy_child_info(component) return component_new
def add_electrical_pads_top( component: Component, spacing: Float2 = (0.0, 100.0), pad_array: ComponentFactory = pad_array_function, select_ports=select_ports_electrical, **kwargs, ) -> Component: """Returns new component with electrical ports connected to top pad array Args: component: spacing: component to pad spacing select_ports: function to select electrical ports kwargs: pad settings pad: pad element pitch: x spacing n: number of pads **port_settings """ c = Component() c.component = component ref = c << component ports = select_ports(ref.ports) ports = list(ports.values()) pads = c << pad_array_function( columns=len(ports), orientation=270, **kwargs) pads.x = ref.x + spacing[0] pads.ymin = ref.ymax + spacing[1] ports_pads = list(pads.ports.values()) ports_pads = gf.routing.sort_ports.sort_ports_x(ports_pads) ports_component = gf.routing.sort_ports.sort_ports_x(ports) for p1, p2 in zip(ports_component, ports_pads): c.add(get_route_electrical_shortest_path(p1, p2)) c.add_ports(ref.ports) for port in ports: c.ports.pop(port.name) return c
def add_electrical_pads_top( component: Component, spacing: Float2 = (0.0, 100.0), pad_array: ComponentFactory = pad_array_function, select_ports=select_ports_electrical, layer: gf.types.Layer = (31, 0), ) -> Component: """Returns new component with electrical ports connected to top pad array Args: component: spacing: component to pad spacing pad_array: function for pad_array select_ports: function to select electrical ports layer: for the routes """ c = Component() c.component = component ref = c << component ports = select_ports(ref.ports) ports = list(ports.values()) pads = c << pad_array(columns=len(ports), orientation=270) pads.x = ref.x + spacing[0] pads.ymin = ref.ymax + spacing[1] ports_pads = list(pads.ports.values()) ports_pads = gf.routing.sort_ports.sort_ports_x(ports_pads) ports_component = gf.routing.sort_ports.sort_ports_x(ports) for p1, p2 in zip(ports_component, ports_pads): c.add(route_quad(p1, p2, layer=layer)) c.add_ports(ref.ports) for port in ports: c.ports.pop(port.name) c.copy_child_info(component) return c
def add_termination( component: Component, ports: Optional[List[Port]] = None, terminator: ComponentFactory = terminator_function, port_name: Optional[str] = None, port_type: str = "optical", **kwargs ) -> Component: """Returns component with all or some ports terminated Args: component: ports: optional list of ports to terminate (defaults to all) terminator: factory for the terminator port_name: for the terminator to connect to the component ports port_type: of the ports that you want to terminate **kwargs: for the ports you want to terminate (orientation, width) """ terminator = terminator() if callable(terminator) else terminator port_name = port_name or terminator.get_ports_list()[0].name c = Component() c.add_ref(component) c.component = component ports_all = component.get_ports_list() ports = ports or component.get_ports_list(port_type=port_type, **kwargs) for port in ports_all: if port in ports: t_ref = c.add_ref(terminator) t_ref.connect(port_name, port) else: c.add_port(port.name, port=port) c.copy_child_info(component) return c
def ring_single_dut(component=taper2, wg_width=0.5, gap=0.2, length_x=4, radius=5, length_y=0, coupler=coupler_ring, straight=straight_function, bend=bend_euler, with_component=True, **kwargs): """Single bus ring made of two couplers (ct: top, cb: bottom) connected with two vertical straights (wyl: left, wyr: right) (Device Under Test) in the middle to extract loss from quality factor Args: with_component: if False changes component for just a straight .. code:: bl-wt-br | | length_y wl component | | --==cb==-- gap length_x """ component = call_if_func(component) assert_on_2nm_grid(gap) coupler = call_if_func(coupler, gap=gap, radius=radius, length_x=length_x, **kwargs) straight_side = call_if_func(straight, width=wg_width, length=length_y + component.xsize, **kwargs) straight_top = call_if_func(straight, width=wg_width, length=length_x, **kwargs) bend = call_if_func(bend, width=wg_width, radius=radius, **kwargs) c = Component() c.component = component cb = c << coupler wl = c << straight_side if with_component: d = c << component else: d = c << straight_side bl = c << bend br = c << bend wt = c << straight_top wl.connect(port="o2", destination=cb.ports["o2"]) bl.connect(port="o2", destination=wl.ports["o1"]) wt.connect(port="o1", destination=bl.ports["o1"]) br.connect(port="o2", destination=wt.ports["o2"]) d.connect(port="o1", destination=br.ports["o1"]) c.add_port("o2", port=cb.ports["o4"]) c.add_port("o1", port=cb.ports["o1"]) c.copy_child_info(component) return c
def add_grating_couplers_with_loopback_fiber_single( component: Component, grating_coupler: ComponentFactory = grating_coupler_te, layer_label: Tuple[int, int] = (200, 0), gc_port_name: str = "o1", get_input_labels_function: Callable[..., List[Label]] = get_input_labels, get_input_label_text_loopback_function: Callable = get_input_label_text_loopback, select_ports: Callable = select_ports_optical, with_loopback: bool = True, cross_section: CrossSectionFactory = strip, component_name: Optional[str] = None, fiber_spacing: float = 50.0, loopback_xspacing: float = 5.0, straight: ComponentFactory = straight_function, rotation: int = 90, ) -> Component: """ Returns component with all ports terminated with grating couplers Args: component: grating_coupler: layer_label: gc_port_name: get_input_label_text_loopback_function: with_loopback: adds a reference loopback rotation: 90 for North South devices, 0 for East-West """ c = Component() c.component = component c.add_ref(component) grating_coupler = ( grating_coupler() if callable(grating_coupler) else grating_coupler ) component_name = component_name or component.info_child.name io_gratings = [] optical_ports = select_ports(component.ports) optical_ports = list(optical_ports.values()) for port in optical_ports: gc_ref = grating_coupler.ref() gc_port = gc_ref.ports[gc_port_name] gc_ref.connect(gc_port, port) io_gratings.append(gc_ref) c.add(gc_ref) labels = get_input_labels_function( io_gratings, list(component.ports.values()), component_name=component_name, layer_label=layer_label, gc_port_name=gc_port_name, ) c.add(labels) p2 = optical_ports[0] p1 = optical_ports[-1] if with_loopback: if rotation in [0, 180]: length = abs(p2.x - p1.x) wg = c << straight(length=length, cross_section=cross_section) wg.rotate(rotation) wg.xmin = p2.x wg.ymin = c.ymax + grating_coupler.ysize / 2 + loopback_xspacing else: length = abs(p2.y - p1.y) wg = c << straight(length=length, cross_section=cross_section) wg.rotate(rotation) wg.ymin = p1.y wg.xmin = c.xmax + grating_coupler.ysize / 2 + loopback_xspacing gci = c << grating_coupler gco = c << grating_coupler gci.connect(gc_port_name, wg.ports["o1"]) gco.connect(gc_port_name, wg.ports["o2"]) port = wg.ports["o2"] text = get_input_label_text_loopback_function( port=port, gc=grating_coupler, gc_index=0, component_name=component_name ) c.add_label( text=text, position=port.midpoint, anchor="o", layer=layer_label, ) port = wg.ports["o1"] text = get_input_label_text_loopback_function( port=port, gc=grating_coupler, gc_index=1, component_name=component_name ) c.add_label( text=text, position=port.midpoint, anchor="o", layer=layer_label, ) c.copy_child_info(component) return c
def add_grating_couplers_with_loopback_fiber_array( component: Component, grating_coupler: ComponentFactory = grating_coupler_te, excluded_ports: None = None, grating_separation: float = 127.0, bend_radius_loopback: Optional[float] = None, gc_port_name: str = "o1", gc_rotation: int = -90, straight_separation: float = 5.0, bend: ComponentFactory = bend_euler, straight: ComponentFactory = straight_function, layer_label: Tuple[int, int] = (200, 0), layer_label_loopback: Optional[Tuple[int, int]] = None, component_name: Optional[str] = None, with_loopback: bool = True, nlabels_loopback: int = 2, get_input_labels_function: Callable = get_input_labels, cross_section: CrossSectionFactory = strip, select_ports: Callable = select_ports_optical, **kwargs, ) -> Component: """Returns a component with grating_couplers and loopback. Args: component: grating_coupler: excluded_ports: grating_separation: bend_radius_loopback: gc_port_name: gc_rotation: straight_separation: bend: straight: layer_label: component_name: with_loopback: If True, add compact loopback alignment ports nlabels_loopback: number of ports to label (0: no labels, 1: first port, 2: both ports) cross_section: **kwargs: cross_section settings """ x = cross_section(**kwargs) bend_radius_loopback = bend_radius_loopback or x.info["radius"] excluded_ports = excluded_ports or [] gc = grating_coupler() if callable(grating_coupler) else grating_coupler direction = "S" component_name = component_name or component.info_child.name c = Component() c.component = component c.add_ref(component) # Find grating port name if not specified if gc_port_name is None: gc_port_name = list(gc.ports.values())[0].name # List the optical ports to connect optical_ports = select_ports(component.ports) optical_ports = list(optical_ports.values()) optical_ports = [p for p in optical_ports if p.name not in excluded_ports] optical_ports = direction_ports_from_list_ports(optical_ports)[direction] # Check if the ports are equally spaced grating_separation_extracted = check_ports_have_equal_spacing(optical_ports) if grating_separation_extracted != grating_separation: raise ValueError( "Grating separation must be {}. Got {}".format( grating_separation, grating_separation_extracted ) ) # Add grating references references = [] for port in optical_ports: gc_ref = c.add_ref(gc) gc_ref.connect(gc.ports[gc_port_name].name, port) references += [gc_ref] labels = get_input_labels_function( io_gratings=references, ordered_ports=optical_ports, component_name=component_name, layer_label=layer_label, gc_port_name=gc_port_name, ) c.add(labels) if with_loopback: y0 = references[0].ports[gc_port_name].y xs = [p.x for p in optical_ports] x0 = min(xs) - grating_separation x1 = max(xs) + grating_separation gca1, gca2 = [ gc.ref(position=(x, y0), rotation=gc_rotation, port_id=gc_port_name) for x in [x0, x1] ] gsi = gc.size_info port0 = gca1.ports[gc_port_name] port1 = gca2.ports[gc_port_name] p0 = port0.position p1 = port1.position a = bend_radius_loopback + 0.5 b = max(2 * a, grating_separation / 2) y_bot_align_route = -gsi.width - straight_separation points = np.array( [ p0, p0 + (0, a), p0 + (b, a), p0 + (b, y_bot_align_route), p1 + (-b, y_bot_align_route), p1 + (-b, a), p1 + (0, a), p1, ] ) bend90 = bend( radius=bend_radius_loopback, cross_section=cross_section, **kwargs ) loopback_route = round_corners( points=points, bend=bend90, straight=straight, cross_section=cross_section, **kwargs, ) c.add([gca1, gca2]) c.add(loopback_route.references) component_name_loopback = f"loopback_{component_name}" if nlabels_loopback == 1: io_gratings_loopback = [gca1] ordered_ports_loopback = [port0] if nlabels_loopback == 2: io_gratings_loopback = [gca1, gca2] ordered_ports_loopback = [port0, port1] if nlabels_loopback == 0: pass elif 0 < nlabels_loopback <= 2: c.add( get_input_labels_function( io_gratings=io_gratings_loopback, ordered_ports=ordered_ports_loopback, component_name=component_name_loopback, layer_label=layer_label_loopback or layer_label, gc_port_name=gc_port_name, ) ) else: raise ValueError( f"Invalid nlabels_loopback = {nlabels_loopback}, " "valid (0: no labels, 1: first port, 2: both ports2)" ) c.copy_child_info(component) return c
def add_fiber_array( component: Component, grating_coupler: Component = grating_coupler_te, straight: ComponentFactory = straight, bend: ComponentFactory = bend_euler, gc_port_name: str = "o1", gc_port_labels: Optional[Tuple[str, ...]] = None, component_name: Optional[str] = None, select_ports: Callable = select_ports_optical, cross_section: CrossSectionFactory = strip, get_input_labels_function: Optional[Callable] = get_input_labels, layer_label: Optional[Tuple[int, int]] = (66, 0), **kwargs, ) -> Component: """Returns component with optical IO (tapers, south routes and grating_couplers). Args: component: to connect grating_coupler: grating coupler instance, function or list of functions bend: bend_circular gc_port_name: grating coupler input port name 'W0' component_name: for the label taper: taper function name or dict get_input_labels_function: function to get input labels for grating couplers get_input_label_text_loopback_function: function to get input label test get_input_label_text_function straight: straight fanout_length: None # if None, automatic calculation of fanout length max_y0_optical: None with_loopback: True, adds loopback structures straight_separation: 4.0 list_port_labels: None, adds TM labels to port indices in this list connected_port_list_ids: None # only for type 0 optical routing nb_optical_ports_lines: 1 force_manhattan: False excluded_ports: grating_indices: None routing_straight: None routing_method: get_route optical_routing_type: None: auto, 0: no extension, 1: standard, 2: check gc_rotation: -90 layer_label: LAYER.LABEL input_port_indexes: [0] .. plot:: :include-source: import gdsfactory as gf gf.config.set_plot_options(show_subports=False) c = gf.components.crossing() cc = gf.routing.add_fiber_array( component=c, optical_routing_type=2, grating_coupler=gf.components.grating_coupler_elliptical_te, with_loopback=False ) cc.plot() """ get_input_labels_function = None if gc_port_labels else get_input_labels_function component = gf.call_if_func(component) grating_coupler = (grating_coupler() if callable(grating_coupler) else grating_coupler) if not component.ports: return component if isinstance(grating_coupler, list): gc = grating_coupler[0] else: gc = grating_coupler gc = gf.call_if_func(gc) if gc_port_name not in gc.ports: raise ValueError( f"gc_port_name={gc_port_name} not in {gc.ports.keys()}") component_name = component_name or component.get_parent_name() component_new = Component() component_new.component = component optical_ports = select_ports(component.ports) optical_ports_names = list(optical_ports.keys()) if not optical_ports: return component elements, io_gratings_lines, ports = route_fiber_array( component=component, grating_coupler=grating_coupler, bend=bend, straight=straight, gc_port_name=gc_port_name, component_name=component_name, cross_section=cross_section, select_ports=select_ports, get_input_labels_function=get_input_labels_function, layer_label=layer_label, **kwargs, ) if len(elements) == 0: return component for e in elements: component_new.add(e) for io_gratings in io_gratings_lines: component_new.add(io_gratings) component_new.add_ref(component) for pname, p in component.ports.items(): if p.name not in optical_ports_names: component_new.add_port(pname, port=p) ports = sort_ports_x(ports) if gc_port_labels: for gc_port_label, port in zip(gc_port_labels, ports): component_new.add_label(text=gc_port_label, layer=layer_label, position=port.midpoint) for i, io_row in enumerate(io_gratings_lines): for j, io in enumerate(io_row): ports = io.get_ports_list(prefix="vertical") if ports: port = ports[0] component_new.add_port(f"{port.name}_{i}{j}", port=port) component_new.copy_child_info(component) return component_new
def add_fiber_single( component: ComponentOrFactory, grating_coupler: ComponentFactory = grating_coupler_te, layer_label: Tuple[int, int] = TECH.layer_label, fiber_spacing: float = TECH.fiber_spacing, bend: ComponentFactory = bend_circular, straight: ComponentFactory = straight, route_filter: Callable = get_route_from_waypoints, min_input_to_output_spacing: float = 200.0, optical_routing_type: int = 2, with_loopback: bool = True, component_name: Optional[str] = None, gc_port_name: str = "o1", get_input_label_text_loopback_function: Callable = get_input_label_text_loopback, get_input_label_text_function: Callable = get_input_label_text, select_ports: Callable = select_ports_optical, cross_section: CrossSectionFactory = strip, **kwargs, ) -> Component: r"""Returns component with grating ports and labels on each port. Can add loopback reference structure next to it. Args: component: to connect grating_coupler: grating coupler instance, function or list of functions layer_label: for test and measurement label fiber_spacing: between outputs bend: bend_circular straight: straight route_filter: max_y0_optical: None with_loopback: True, adds loopback structures straight_separation: 4.0 list_port_labels: None, adds TM labels to port indices in this list connected_port_list_ids: None # only for type 0 optical routing nb_optical_ports_lines: 1 force_manhattan: False excluded_ports: grating_indices: None routing_method: get_route gc_port_name: W0 get_input_labels_function: function to get input labels for grating couplers optical_routing_type: None: autoselection, 0: no extension gc_rotation: -90 component_name: name of component cross_section: **kwargs: cross_section settings .. code:: fiber ______ /| | | / | | | W0| | | | \ | | | | \|_|_|_ | xmin = 0 .. plot:: :include-source: import gdsfactory as gf c = gf.components.crossing() cc = gf.routing.add_fiber_single( component=c, optical_routing_type=0, grating_coupler=gf.components.grating_coupler_elliptical_te, ) cc.plot() """ component = component() if callable(component) else component optical_ports = select_ports(component.ports) optical_ports = list(optical_ports.values()) optical_port_names = [p.name for p in optical_ports] if not optical_ports: raise ValueError(f"No ports for {component.name}") component = component() if callable(component) else component component_name = component_name or component.get_parent_name() gc = grating_coupler = (grating_coupler() if callable(grating_coupler) else grating_coupler) if gc_port_name not in gc.ports: raise ValueError(f"{gc_port_name} not in {list(gc.ports.keys())}") gc_port_to_edge = abs(gc.xmax - gc.ports[gc_port_name].midpoint[0]) c = Component() c.component = component cr = c << component cr.rotate(90) for port in cr.ports.values(): if port.name not in optical_port_names: c.add_port(name=port.name, port=port) if (len(optical_ports) == 2 and abs(optical_ports[0].x - optical_ports[1].x) > min_input_to_output_spacing): grating_coupler = call_if_func(grating_coupler) grating_couplers = [] for port in cr.ports.values(): if port.name in optical_port_names: gc_ref = grating_coupler.ref() gc_ref.connect(gc_port_name, port) grating_couplers.append(gc_ref) elements = get_input_labels( io_gratings=grating_couplers, ordered_ports=list(cr.ports.values()), component_name=component_name, layer_label=layer_label, gc_port_name=gc_port_name, get_input_label_text_function=get_input_label_text_function, ) else: elements, grating_couplers = route_fiber_single( component, fiber_spacing=fiber_spacing, bend=bend, straight=straight, route_filter=route_filter, grating_coupler=grating_coupler, layer_label=layer_label, optical_routing_type=optical_routing_type, min_input_to_output_spacing=min_input_to_output_spacing, gc_port_name=gc_port_name, component_name=component_name, cross_section=cross_section, select_ports=select_ports, **kwargs, ) for e in elements: c.add(e) for gc in grating_couplers: c.add(gc) for i, io_row in enumerate(grating_couplers): if isinstance(io_row, list): for j, io in enumerate(io_row): ports = io.get_ports_list(prefix="vertical") if ports: port = ports[0] c.add_port(f"{port.name}_{i}{j}", port=port) else: ports = io_row.get_ports_list(prefix="vertical") if ports: port = ports[0] c.add_port(f"{port.name}_{i}", port=port) if isinstance(grating_coupler, list): grating_couplers = [call_if_func(g) for g in grating_coupler] grating_coupler = grating_couplers[0] else: grating_coupler = call_if_func(grating_coupler) grating_couplers = [grating_coupler] if with_loopback: length = c.ysize - 2 * gc_port_to_edge wg = c << straight( length=length, cross_section=cross_section, **kwargs) wg.rotate(90) wg.xmax = (c.xmin - fiber_spacing if abs(c.xmin) > abs(fiber_spacing) else c.xmin - fiber_spacing) wg.ymin = c.ymin + gc_port_to_edge gci = c << grating_coupler gco = c << grating_coupler gci.connect(gc_port_name, wg.ports["o1"]) gco.connect(gc_port_name, wg.ports["o2"]) port = wg.ports["o2"] text = get_input_label_text_loopback_function( port=port, gc=grating_coupler, gc_index=0, component_name=component_name) c.add_label( text=text, position=port.midpoint, anchor="o", layer=layer_label, ) port = wg.ports["o1"] text = get_input_label_text_loopback_function( port=port, gc=grating_coupler, gc_index=1, component_name=component_name) c.add_label( text=text, position=port.midpoint, anchor="o", layer=layer_label, ) c.copy_child_info(component) return c
def fanout2x2( component: Component, port_spacing: float = 20.0, bend_length: Optional[float] = None, npoints: int = 101, select_ports: Callable = select_ports_optical, ) -> Component: """returns component with port_spacing. Args: component: to package port_spacing: for the returned component bend_length: length of the bend (defaults to port_spacing) npoints: for sbend select_ports: function to select optical_ports ports """ c = gf.Component() component = component() if callable(component) else component component.component = component ref = c << component ref.movey(-ref.y) if bend_length is None: bend_length = port_spacing dx = bend_length y = port_spacing / 2.0 p_w0 = ref.ports["o1"].midpoint p_w1 = ref.ports["o2"].midpoint p_e1 = ref.ports["o3"].midpoint p_e0 = ref.ports["o4"].midpoint y0 = p_e1[1] dy = y - y0 control_points = [(0, 0), (dx / 2, 0), (dx / 2, dy), (dx, dy)] bezier_bend_t = bezier(control_points=control_points, npoints=npoints, start_angle=0, end_angle=0) b_tr = bezier_bend_t.ref(port_id="o1", position=p_e1) b_br = bezier_bend_t.ref(port_id="o1", position=p_e0, v_mirror=True) b_tl = bezier_bend_t.ref(port_id="o1", position=p_w1, h_mirror=True) b_bl = bezier_bend_t.ref(port_id="o1", position=p_w0, rotation=180) c.add([b_tr, b_br, b_tl, b_bl]) c.add_port("o1", port=b_bl.ports["o2"]) c.add_port("o2", port=b_tl.ports["o2"]) c.add_port("o3", port=b_tr.ports["o2"]) c.add_port("o4", port=b_br.ports["o2"]) c.min_bend_radius = bezier_bend_t.info["min_bend_radius"] optical_ports = select_ports(ref.ports) for port_name in ref.ports.keys(): if port_name not in optical_ports: c.add_port(port_name, port=ref.ports[port_name]) c.copy_child_info(component) return c