PlaceAndAutoRoute

class picazzo3.routing.place_route.cell.PlaceAndAutoRoute(*args, **kwargs)

Parametric Cell for manual placement and Automatic Routing.

The PCells objects that need to be placed as instances are specified through the property child_cells. This dictionary maps the instance names to the PCell objects. The same PCell object can be used for multiple instances.

child_cells={ "ring1"  : my_ring1,
              "ring2"  : my_ring2,
              "spl"    : my_splitter,
              "com"    : my_splitter # the same cell is used both for splitting and combining
              }

The connectivity between the instances of the child cells is set by a list of tuples containing pairs of instance terms/port names. This list links is of the form instname:portname

links=[ ("spl:arm1",   "arm1:in1"),
        ("arm1:out1", "com:arm1"),
        ("spl:arm2",   "arm2:in1"),
        ("arm2:out1", "com:arm2")
        ]

Based on this connectivity list, the PCell will generate waveguides for all links, using the trace_template property. This requires that all ports have a compatible trace template.

The instances’ terms/ports that are not specified in the links parameter will be considered to be external ports. You can override the default external term/port names using the external_port_names property, and specify the individual names of the external terms. If no name is specified, the default pattern of ‘instname_portname’ will be used.

external_port_names={ "spl:in1"  : "input",
                      "com:out1" : "output"
                      }

In the layout, the placement is specified manually using the child_transformations property, which defines a transformation for each instance. If no transformation if supplied for an instance, no transformation will be applied. It is also possible to supply a coordinate (Coord2) or tuple, which will be interpreted as a position for placement.

child_transformations={"arm1": (50, -50),
                       "arm2": (50,50),
                       "com": i3.HMirror(0.0)+i3.Translation((100,0))}

Of course, this smart place and route cell will only work with PCells which are well constructed: an important requirement is that the Terms in the netlist match the Ports in the layout: the same number, as well as the same names. The same for the instances. The generation of links and waveguides is done based on the instance and port names.

By default, the routes of the waveguides are automatically generated using RouteManhattan. It is possible to override one or more specific routes manually by adjusting the waveguide_shapes parameters (see example).

All connecting waveguides will use the same trace definition. Tapers will automatically be added for those ports of child cells which have a different trace template.

When traces or waveguides cross, these crossings can be visually marked in the layout view by flagging highlight_waveguide_crossings=True.

Parameters:

trace_template: PCell and _TraceTemplate, optional

Trace template used to connect the instances

child_cells: optional

dict to create the instances of the child cells. Format is {‘inst_name1’: PCell}

links: list and List with type restriction, allowed types: [<class ‘_abcoll.Sequence’>], optional

list of tuples connecting the instances. Format is [(‘inst1:term1’,’inst2:term2’), …]

external_port_names: optional

Map of the free instance terms/ports to the names of external terms/ports. Format is a dict {‘inst:term’ : ‘new_term_name’}.If a term/port is not listed, the format instname_portname will be used

cell_instances: _PCellInstanceDict, optional

name: optional

The unique name of the pcell

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

list of waveguides created based on the links property

Views

Layout
Parameters:

angle_step: float and number > 0, optional

angle step for rounding

grid: float and number > 0, optional

design grid. Extracted by default from TECH.METRICS.GRID

grids_per_unit: optional

Number of grid cells per design unit

highlight_waveguide_crossings: optional

If True, waveguide crossings will be indicated on a seperate layer

manhattan: optional

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

rounding_algorithm: optional

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

unit: float and number > 0, optional

design unit. Extracted by default from TECH.METRICS.UNIT

units_per_grid: optional

Ratio of grid cell and design unit

view_name: str, optional

The name of the view

waveguide_crossing_layer: __Layer__, optional

Layer on which crossings between the autorouted waveguides are indicated in the layout.

waveguide_shapes: optional

List of shapes/routes for the waveguides. The order is the same as in ‘links’. If you want a waveguide to be autorouted, fill in None for that shape.

flyline_layer: optional

layer to draw flylines of physically unconnected links

flyline_width: float and number > 0, optional

line width of the flylines

child_transformations: optional

dictionary with the transformation of each child instance.

netlist_view: NetlistView, optional

Netlist view in the same cell on which this Layout is based. Normally no need to manually override.

end_straight: float and Real, number and number >= 0, optional

The length of the straight end section of the route

min_straight: float and Real, number and number >= 0, optional

The minimum length of any straight sections in the route

start_straight: float and Real, number and number >= 0, optional

The length of the straight start section of the route

bend_radius: float and number > 0, optional

bend radius for the auto-generated bends

Examples

""" This example shows how to indicate crossings between the routed waveguides,
using the `highlight_waveguide_crossings=True` flag.
This is especially useful to identify errors in the circuit topology."""
from technologies import silicon_photonics
from ipkiss3 import all as i3

from picazzo3.filters.ring import RingRect180DropFilter, RingRectNotchFilter
from picazzo3.wg.splitters import WgY90Splitter
from picazzo3.routing.place_route import PlaceAndAutoRoute

ring = RingRectNotchFilter()
ring.Layout(bend_radius=20.0)
splitter = WgY90Splitter()

pr = PlaceAndAutoRoute(child_cells={"spl": splitter,
                                    "com": splitter,
                                    "arm1": ring},
                       links=[("spl:arm1", "arm1:in"),
                              ("arm1:out", "com:arm2"),
                              ("spl:arm2", "com:arm1")]
                       )

layout = pr.Layout(child_transformations={"arm1": (60, -40),
                                          "com": i3.HMirror(0.0)+i3.Rotation(rotation=90.0)+i3.Translation((200, 100))},
                   bend_radius=10.0,
                   highlight_waveguide_crossings=True
                   )

layout.visualize()
../../../../_images/picazzo3-routing-place_route-cell-PlaceAndAutoRoute-1.png
""" This example shows how to detect crossings between the routed waveguides and manually correct
for them, using the `highlight_waveguide_crossings=True` flag."""
from technologies import silicon_photonics
from ipkiss3 import all as i3

from picazzo3.filters.ring import RingRect180DropFilter, RingRectNotchFilter
from picazzo3.wg.splitters import WgY90Splitter
from picazzo3.routing.place_route import PlaceAndAutoRoute

ring = RingRectNotchFilter()
ring.Layout(bend_radius=20.0)
splitter = WgY90Splitter()

pr = PlaceAndAutoRoute(child_cells={"spl": splitter,
                                    "com": splitter,
                                    "arm1": ring},
                       links=[("spl:arm1", "arm1:in"),
                              ("arm1:out", "com:arm2"),
                              ("spl:arm2", "com:arm1")]
                       )

layout = pr.Layout(child_transformations={"arm1": (60, -40),
                                          "com": i3.HMirror(0.0)+i3.Rotation(rotation=90.0)+i3.Translation((200, 100))},
                   bend_radius=10.0,
                   highlight_waveguide_crossings=True
                   )

# print the coordinates of the crossings
print layout.get_waveguide_crossing_points()

# Remove the crossing by manually overriding the shape of the final waveguide.
s = layout.get_waveguide_shapes()[2]
new_shape_wg2 = i3.Shape([s[0],
                          (s[0].x, 200.0),
                          (250.0, 200.0),
                          (250.0, s[-1].y),
                          s[-1]])
# re-initialize the layout with the new waveguide shape
layout = pr.Layout(child_transformations={"arm1": (60, -40),
                                          "com": i3.HMirror(0.0)+i3.Rotation(rotation=90.0)+i3.Translation((200, 100))},
                   bend_radius=10.0,
                   highlight_waveguide_crossings=True,
                   waveguide_shapes = [None, None, new_shape_wg2]
                   )
layout.visualize()
../../../../_images/picazzo3-routing-place_route-cell-PlaceAndAutoRoute-2.png
""" In this example we arrange 4 identical rings in a loop and connect them back-to-back."""
from technologies import silicon_photonics
from ipkiss3 import all as i3

from picazzo3.filters.ring import RingRect180DropFilter

from picazzo3.routing.place_route import PlaceAndAutoRoute

ring = RingRect180DropFilter()

pr = PlaceAndAutoRoute(child_cells={"ring1": ring,
                                    "ring2": ring,
                                    "ring3": ring,
                                    "ring4": ring},
                       links=[("ring1:out1", "ring2:in1"),
                              ("ring1:in2", "ring2:out2"),
                              ("ring2:out1", "ring3:in1"),
                              ("ring2:in2", "ring3:out2"),
                              ("ring3:out1", "ring4:in1"),
                              ("ring3:in2", "ring4:out2"),
                              ("ring4:in2", "ring1:out2"),
                              ]
                       )

layout = pr.Layout(child_transformations={"ring1": (0, 0),
                                          "ring2": i3.Rotation(rotation=90) + i3.Translation((25.0, 25.0)),
                                          "ring3": i3.Rotation(rotation=180) + i3.Translation((0.0, 50.0)),
                                          "ring4": i3.Rotation(rotation=-90) + i3.Translation((-25.0, 25.0))
                                          }
                   )

layout.visualize()
../../../../_images/picazzo3-routing-place_route-cell-PlaceAndAutoRoute-3.png
""" Here we connect together 2 splitters and two rings to form a Ring-loaded
    Mach-Zehnder. We use the splitter twice (as splitter and combiner) but use
    two different rings.
    """
from technologies import silicon_photonics
from ipkiss3 import all as i3

from picazzo3.filters.ring import RingRect180DropFilter, RingRectNotchFilter
from picazzo3.wg.splitters import WgY90Splitter

from picazzo3.routing.place_route import PlaceAndAutoRoute

ring1 = RingRectNotchFilter()
ring2 = RingRect180DropFilter()
splitter = WgY90Splitter()

pr = PlaceAndAutoRoute(child_cells={"spl": splitter,
                                    "com": splitter,
                                    "arm1": ring1,
                                    "arm2": ring2},
                       links=[("spl:arm1", "arm1:in"),
                              ("arm1:out", "com:arm1"),
                              ("spl:arm2", "arm2:in1"),
                              ("arm2:out1", "com:arm2")]
                       )

layout = pr.Layout(child_transformations={"arm1": (30, -30),
                                          "arm2": (30, 30),
                                          "com": i3.HMirror(0.0)+i3.Translation((60, 0))},
                   bend_radius=10.0,
                   manhattan=True
                   )

layout.visualize()
../../../../_images/picazzo3-routing-place_route-cell-PlaceAndAutoRoute-4.png
""" Here we show how you can influence the internal routing of the
PlaceAndAutoRoute, by setting the min_straight parameter to 0.0.
This way we can create a more compact component.
"""
from technologies import silicon_photonics
from ipkiss3 import all as i3

from picazzo3.filters.ring import RingRect180DropFilter, RingRectNotchFilter
from picazzo3.wg.splitters import WgY90Splitter

from picazzo3.routing.place_route import PlaceAndAutoRoute

ring1 = RingRectNotchFilter()
ring2 = RingRect180DropFilter()
splitter = WgY90Splitter()

pr = PlaceAndAutoRoute(child_cells={"spl": splitter,
                                    "com": splitter,
                                    "arm1": ring1,
                                    "arm2": ring2},
                       links=[("spl:arm1", "arm1:in"),
                              ("arm1:out", "com:arm1"),
                              ("spl:arm2", "arm2:in1"),
                              ("arm2:out1", "com:arm2")]
                       )

layout = pr.Layout(child_transformations={"arm1": (20, -30),
                                          "arm2": (20, 30),
                                          "com": i3.HMirror(0.0)+i3.Translation((40, 0))},
                   bend_radius=5.0,
                   manhattan=True,
                   min_straight=0.0  # we set min_straight to 0.0
                   )

layout.visualize()
../../../../_images/picazzo3-routing-place_route-cell-PlaceAndAutoRoute-5.png
# This example illustrates how the necessary transitions
# are automatically added...
from technologies import silicon_photonics
from ipkiss3 import all as i3

from picazzo3.traces.wire_wg import WireWaveguideTemplate
from picazzo3.traces.rib_wg import RibWaveguideTemplate, RibWireWaveguideTemplate
from picazzo3.traces.slot_wg import SlotWaveguideTemplate

# making 4 very different waveguides
wg1_t = WireWaveguideTemplate()
wg1_t.Layout(core_width=0.8)
wg1 = wg1_t()
wg1.Layout(shape=[(-40, -60), (-60, -40)])

wg2_t = RibWaveguideTemplate()
wg2_t.Layout(core_width=0.8)
wg2 = wg2_t()
wg2.Layout(shape=[(-60, 40), (-40, 60)])
wg3_t = RibWireWaveguideTemplate()
wg3_t.Layout(core_width=0.8)
wg3 = wg3_t()
wg3.Layout(shape=[(40, 60), (60, 40)])

wg4_t = SlotWaveguideTemplate()
wg4_t.Layout(core_width=0.6)
wg4 = wg4_t()
wg4.Layout(shape=[(60, -40), (40, -60)])

from picazzo3.routing.place_route import PlaceAndAutoRoute

pr = PlaceAndAutoRoute(child_cells={"wg1": wg1,
                                    "wg2": wg2,
                                    "wg3": wg3,
                                    "wg4": wg4},
                       links=[("wg1:out", "wg2:in"),
                              ("wg2:out", "wg3:in"),
                              ("wg3:out", "wg4:in"),
                              ("wg4:out", "wg1:in")
                              ]
                       )
layout = pr.Layout()
layout.visualize()
../../../../_images/picazzo3-routing-place_route-cell-PlaceAndAutoRoute-6.png