RoutePortsAroundCorner

class picazzo3.container.route_ports.RoutePortsAroundCorner

Routes ports around a corner of the component in a given direction.

Parameters:
trace_template: ( PCell and _WaveguideTemplate ), *None allowed*

Template for all ports, defaults to TECH.PCELLS.WG.DEFAULT.When set to None, the waveguide templates of the ports will be used.

auto_transition: ( bool, bool_ or int )

If True, automatically transition all ports of contents to the given trace template. If False, no transitions are applied, which might lead to a discontinuity in the waveguide. Also, if trace_template is None, no transitions are applied.

port_labels: ( List with type restriction, allowed types: <class ‘str’> ), *None allowed*

Labels of the ports to be processed. Set to None to process all ports.

external_port_names: str

Dictionary for remapping of the port names of the contents to the external ports

contents: PCell

the contents of the container: the child cell

name: String that contains only ISO/IEC 8859-1 (extended ASCII py3) or pure ASCII (py2) characters

The unique name of the pcell

Other Parameters:
bundle: ( PCell ), locked, *None allowed*

bundle of waveguides added to the contents, generated based on the supplied waveguides list

waveguides: List with type restriction, allowed types: <class ‘ipkiss3.pcell.cell.pcell.PCell’>, locked
trace_templates: List with type restriction, allowed types: <class ‘ipkiss3.pcell.cell.pcell.PCell’>, locked

list of templates to apply to all ports

Views

class Layout
Parameters:
first_step_spacing: float and number > 0

The spacing between the routes ( in the section after the first bend )

reference_coordinate_first_step: float

The minimum 1D coordinate of the first bend of the routes

first_step_direction: List with value restriction, allowed values: [C2(0.000000, 1.000000), C2(0.000000, -1.000000), C2(1.000000, 0.000000), C2(-1.000000, 0.000000)]

The direction to take when rounding the corner. By default it is 90 degrees off the output direction

target_coordinate: ( float ), *None allowed*

The coordinate where the endpoints of the waveguides are aligned. An x-coordinate when routing toEAST or WEST, a y-coordinate when routing to NORTH or SOUTH. When the waveguides extend beyond thetarget coordinate, the value is ignored.

max_s_bend_angle: float and ]0.0,90.0]
spacing: float

spacing between adjacent output waveguides

align_outputs: ( bool, bool_ or int )

If True, all outputs will be aligned to the outermost waveguide end, even if it extends beyond its target coordinate.

reference_coordinate: ( float ), *None allowed*

The coordinate where the first waveguide will be aligned. An x-coordinate if routed towards NORTH or SOUTH,a y-coordinate when routed towards EAST or WEST. If not specified, the x or y coordinate of the first port is taken.

output_direction: List with value restriction, allowed values: [C2(1.000000, 0.000000), C2(-1.000000, 0.000000), C2(0.000000, 1.000000), C2(0.000000, -1.000000)]

direction of the output waveguides. Should be EAST, WEST, NORTH or SOUTH

area_layer_on: ( bool, bool_ or int )

When True, the waveguide area will be covered by i3.Rectangles on all cover layers.

routes:

routes along which the waveguides will be generated

contents_transformation: GenericNoDistortTransform

transformation to apply to the contents

flatten_contents: ( bool, bool_ or int )

if True, it will insert the contents as elements in the layout, rather than as an Instance

view_name: String that contains only alphanumeric characters from the ASCII set or contains _$. ASCII set is extended on PY3.

The name of the view

manhattan: ( bool, bool_ or int )

Adds rectangular blocks in the bends to avoid as much as possible non-manhattan angles.

angle_step: float and number > 0

Angle step for rounding.

rounding_algorithm:

Rounding algorithm used to generate the bends. Can be circular, spline, ….

bend_radius: float and number > 0

Bend radius for the auto-generated bends.

Other Parameters:
target_coordinates: locked
max_s_bend_angles: locked
spacings_from_reference: locked

Examples

import si_fab.all as pdk  # noqa: F401
import ipkiss3.all as i3
from picazzo3.filters.ring import RingRect180DropFilter
from picazzo3.container.route_ports import RoutePortsAroundCorner

def annotate_label(ax, text, pos, **kwargs):
    ax.annotate(
        text, xy=pos, horizontalalignment="center", verticalalignment="center", xytext=pos, **kwargs
    )

def annotate_direction(ax, text, direction=i3.DIRECTION.NORTH, pos=(0.0, 0.0), **kwargs):
    kws = {
        "ha": "center",
        "va": "center",
        "rotation": i3.angle_deg(direction),
        "bbox": {
            "boxstyle": "rarrow,pad=0.3",
            "fc": "white",
        },
        "size": 15,
    }

    kws.update(kwargs)
    return ax.text(pos[0], pos[1], text, **kws)

def annotate_distance(
    ax, text, start=(0.0, 0.0), end=(0.0, 10.0), offset=0.0, offset_direction=i3.DIRECTION.EAST, **kwargs
):
    start = (offset_direction * offset) + start
    end = (offset_direction * offset) + end
    ax.annotate(
        "",
        xy=tuple(start),
        xycoords="data",
        xytext=tuple(end),
        textcoords="data",
        arrowprops={"arrowstyle": "<->"},
    )

    text_pos = tuple((e + s) / 2.0 for e, s in zip(start, end))

    if len(text) > 0:
        ax.annotate(text, xy=text_pos, xytext=text_pos, xycoords="data", textcoords="data")

def annotate_y(ax, y, label="", **kwargs):
    return ax.axhline(y, linestyle="dashed", label=label, **kwargs)

def annotate_x(ax, x, label="", **kwargs):
    return ax.axvline(x, linestyle="dashed", label=label, **kwargs)

def annotate(
    ax,
    output_direction=None,
    size_info=None,
    first_step_direction=None,
    first_step_spacing=None,
    reference_coordinate=None,
    reference_coordinate_first_step=None,
    target_coordinate=None,
    spacing=None,
    ports=None,
):
    annotate_label(ax, "contents", (0.0, 0.0), bbox={"fc": "white", "boxstyle": "round", "ec": "black"})

    legend_handles = []
    legend_labels = []
    if first_step_direction is not None:
        pos = (size_info.west - 10.0, (size_info.south + size_info.north) / 2.0)
        annotate_direction(ax, "first_step_direction", direction=first_step_direction, pos=pos)

    if output_direction is not None:
        pos = ((size_info.west + size_info.east) / 2.0, size_info.south - 5.0)
        annotate_direction(ax, "output_direction", direction=output_direction, pos=pos)

    if reference_coordinate is not None:
        legend_handles.append(annotate_y(ax, reference_coordinate, label="reference_coordinate", c="r"))
        legend_labels.append("reference_coordinate")

    if reference_coordinate_first_step is not None:
        legend_handles.append(
            annotate_x(
                ax, reference_coordinate_first_step, label="reference_coordinate_first_step", c="black"
            )
        )
        legend_labels.append("reference_coordinate_first_step")

    if target_coordinate is not None:
        legend_handles.append(annotate_x(ax, target_coordinate, label="target_coordinate"))
        legend_labels.append("target_coordinate")

    if spacing is not None:
        end = tuple(ports.east_ports[0].position)
        start = tuple(ports.east_ports[1].position)
        annotate_distance(ax, f"spacing = {spacing}", start=start, end=end, offset=1.0)

    ax.legend(legend_handles, legend_labels)

def visualize_routearoundports(layout):
    size_info = layout.size_info()
    margin = 15.0
    west_margin, east_margin, south_margin, north_margin = [margin] * 4
    box = (
        size_info.west - west_margin,
        size_info.east + east_margin,
        size_info.south - south_margin,
        size_info.north + north_margin,
    )

    fig = layout.visualize(show=False, box=box, canvas_size=(1000.0, 1000.0))
    ax = fig.get_axes()[-1]
    ax.set_aspect("equal", "datalim")

    annotate(
        ax,
        reference_coordinate=layout.reference_coordinate,
        reference_coordinate_first_step=layout.reference_coordinate_first_step,
        first_step_spacing=layout.first_step_spacing,
        target_coordinate=layout.target_coordinate,
        first_step_direction=layout.first_step_direction,
        spacing=layout.spacing,
        output_direction=layout.output_direction,
        ports=layout.ports,
        size_info=size_info,
    )

    from matplotlib.pyplot import show

    show()

my_ring = RingRect180DropFilter()

my_ring_routed = RoutePortsAroundCorner(contents=my_ring, port_labels=["W1", "W0"])  # ports to be routed

layout = my_ring_routed.Layout(
    first_step_direction=i3.DIRECTION.SOUTH,  # when rounding corner, go this direction first
    output_direction=i3.DIRECTION.EAST,  # final output direction
    target_coordinate=30.0,
    reference_coordinate_first_step=-20.0,
    first_step_spacing=15.0,  # Spacing between the waveguides.
)

visualize_routearoundports(layout)
../../../../../_images/picazzo3-container-route_ports-RoutePortsAroundCorner-1.png
import si_fab.all as pdk  # noqa: F401
import ipkiss3.all as i3
from picazzo3.filters.ring import RingRect180DropFilter
from picazzo3.container.route_ports import RoutePortsAroundCorner

my_ring = RingRect180DropFilter()

my_ring_routed = RoutePortsAroundCorner(contents=my_ring, port_labels=["W1", "W0"])  # ports to be routed

layout = my_ring_routed.Layout(
    first_step_direction=i3.DIRECTION.SOUTH,  # when rounding corner, go this direction first
    output_direction=i3.DIRECTION.EAST,  # final output direction
    first_step_spacing=8.0,  # Spacing between the waveguides.
)
layout.visualize(annotate=True)
../../../../../_images/picazzo3-container-route_ports-RoutePortsAroundCorner-2.png
"""By default, the area between the routes is drawn,
you can override this using the area_layer_on parameter"""
import si_fab.all as pdk  # noqa: F401
import ipkiss3.all as i3
from picazzo3.filters.ring import RingRect180DropFilter
from picazzo3.container.route_ports import RoutePortsAroundCorner

my_ring = RingRect180DropFilter()

my_ring_routed = RoutePortsAroundCorner(contents=my_ring, port_labels=["W1", "W0"])  # ports to be routed

layout = my_ring_routed.Layout(
    first_step_direction=i3.DIRECTION.SOUTH,  # when rounding corner, go this direction first
    output_direction=i3.DIRECTION.EAST,  # final output direction
    area_layer_on=False,
    first_step_spacing=8.0,  # Spacing between the waveguides.
)
layout.visualize(annotate=True)
../../../../../_images/picazzo3-container-route_ports-RoutePortsAroundCorner-3.png
"""Instead of E0, W0, E1, (east 0, west 0 ) ...
we can also use the actual port names as port labels"""
import si_fab.all as pdk  # noqa: F401
import ipkiss3.all as i3
from picazzo3.filters.ring import RingRect180DropFilter
from picazzo3.container.route_ports import RoutePortsAroundCorner

my_ring = RingRect180DropFilter()

my_ring_routed = RoutePortsAroundCorner(contents=my_ring, port_labels=["in1", "out2"])  # ports to be routed

layout = my_ring_routed.Layout(
    first_step_direction=i3.DIRECTION.SOUTH,  # when rounding corner, go this direction first
    output_direction=i3.DIRECTION.EAST,  # final output direction
    first_step_spacing=8.0,  # Spacing between the waveguides.
)
layout.visualize(annotate=True)
../../../../../_images/picazzo3-container-route_ports-RoutePortsAroundCorner-4.png
"""Be aware that the order of the port_labels is used to determine to the order of the created routes.
If you encounter crossing routes, you might want to change the order of the labels"""
import si_fab.all as pdk  # noqa: F401
import ipkiss3.all as i3
from picazzo3.filters.ring import RingRect180DropFilter
from picazzo3.container.route_ports import RoutePortsAroundCorner

my_ring = RingRect180DropFilter()
layout = my_ring.Layout()

# We first route the E0 (east0 ) port, if we had chosen
# ['W1', 'W0', 'E0'] this would have resulted in crossing waveguides
my_ring = RoutePortsAroundCorner(contents=layout, port_labels=["E0", "W1", "W0"])

layout = my_ring.Layout(
    first_step_direction=i3.DIRECTION.SOUTH,  # when rounding corner, go this direction first
    output_direction=i3.DIRECTION.EAST,  # final output direction
    reference_coordinate_first_step=-20.0,
    first_step_spacing=8.0,  # Spacing between the waveguides.
)
layout.visualize(annotate=True)
../../../../../_images/picazzo3-container-route_ports-RoutePortsAroundCorner-5.png
"""As most containers, RoutePortsAroundCorner supports auto transitions.
This means that you can choose a trace template for the routes that's different
from the one used in the contents.
"""
import si_fab.all as pdk  # noqa: F401
import ipkiss3.all as i3
from picazzo3.filters.ring import RingRect180DropFilter
from picazzo3.container.route_ports import RoutePortsAroundCorner
from picazzo3.traces.wire_wg import WireWaveguideTemplate

my_ring = RingRect180DropFilter()
my_ring.Layout()

wtpl = WireWaveguideTemplate()
wtpl.Layout(core_width=0.7)

my_ring = RoutePortsAroundCorner(
    trace_template=wtpl, auto_transition=True, contents=my_ring, port_labels=["E0", "W1", "W0"]
)

layout = my_ring.Layout(
    first_step_direction=i3.DIRECTION.SOUTH,  # when rounding corner, go this direction first
    output_direction=i3.DIRECTION.EAST,  # final output direction
    reference_coordinate_first_step=-20.0,
    target_coordinate=40.0,
    first_step_spacing=8.0,  # Spacing between the waveguides.
)
layout.visualize(annotate=True)
../../../../../_images/picazzo3-container-route_ports-RoutePortsAroundCorner-6.png
"""The target_coordinate parameter can be used to specify
the 'target coordinate' of the routes. This is illustrated in this example"""

import si_fab.all as pdk  # noqa: F401
import ipkiss3.all as i3
from picazzo3.filters.ring import RingRect180DropFilter
from picazzo3.container.route_ports import RoutePortsAroundCorner

my_ring = RingRect180DropFilter()
layout = my_ring.Layout()

# We first route the E0 (east0 ) port, if we had chosen
# ['W1', 'W0', 'E0'] this would have resulted in crossing waveguides
my_ring = RoutePortsAroundCorner(contents=layout, port_labels=["E0", "W1", "W0"])

layout = my_ring.Layout(
    first_step_direction=i3.DIRECTION.SOUTH,  # when rounding corner, go this direction first
    output_direction=i3.DIRECTION.EAST,  # final output direction
    reference_coordinate_first_step=-20.0,
    target_coordinate=40.0,
    first_step_spacing=8.0,  # Spacing between the waveguides.
)
layout.visualize(annotate=True)
../../../../../_images/picazzo3-container-route_ports-RoutePortsAroundCorner-7.png