Fixing sharp angles in the layout of a directional coupler

This example shows how to use layout operations to stub acute angles of a directional coupler. Stubbing of acute angles is an important step in the design process that makes sure your device passes the design rule checks (DRCs).

First we import a directional coupler from picazzo:

from technologies import silicon_photonics
import ipkiss3.all as i3
from picazzo3.wg.dircoup.cell import BendDirectionalCoupler

dc = BendDirectionalCoupler(name="myDC")
dc_lay = dc.Layout(manhattan=False,
                   straight_after_bend=5.0,
                   bend_angle=30)
dc_lay.visualize()
plot stubDC
<Figure size 640x480 with 1 Axes>

The layout can be checked on acute angles using get_acute_angle_points:

acute_points = i3.get_acute_angle_points(dc_lay)
for layer in acute_points:
    for point_data in acute_points[layer]:
        point, _, angle = point_data
        print("Acute point ({:.2f}, {:.2f}) with {:.2f} degrees angle found in layer {}"
              .format(point[0], point[1], angle, layer))
Acute point (7.72, -3.68) with 89.98 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (7.95, -3.29) with 89.99 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (-7.95, -3.29) with 89.99 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (-7.72, -3.68) with 89.98 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (7.95, 3.29) with 89.99 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (7.72, 3.68) with 89.98 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (-7.72, 3.68) with 89.98 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (-7.95, 3.29) with 89.99 degrees angle found in layer PPLAYER WG-LFLIN
Acute point (8.95, -1.56) with 89.94 degrees angle found in layer PPLAYER WG-LFAREA
Acute point (6.24, 0.00) with 300.06 degrees angle found in layer PPLAYER WG-LFAREA
Acute point (8.95, 1.56) with 89.94 degrees angle found in layer PPLAYER WG-LFAREA
Acute point (-8.95, 1.56) with 89.94 degrees angle found in layer PPLAYER WG-LFAREA
Acute point (-6.24, 0.00) with 300.06 degrees angle found in layer PPLAYER WG-LFAREA
Acute point (-8.95, -1.56) with 89.94 degrees angle found in layer PPLAYER WG-LFAREA

Rounding errors and grid snapping have caused some 90-degree angles to be slightly acute. Since these are not angles that need to be stubbed, the angle_treshold argument can be used to avoid this.

acute_points = i3.get_acute_angle_points(dc_lay, angle_threshold=0.1)
for layer in acute_points:
    for point_data in acute_points[layer]:
        point, _, angle = point_data
        print("Acute point ({:.2f}, {:.2f}) with {:.2f} degrees angle found in layer {}"
              .format(point[0], point[1], angle, layer))
Acute point (6.24, 0.00) with 300.06 degrees angle found in layer PPLAYER WG-LFAREA
Acute point (-6.24, 0.00) with 300.06 degrees angle found in layer PPLAYER WG-LFAREA

The stub elements can be inspected using get_stub_elements:

elems_add, elems_subt = i3.get_stub_elements(dc_lay,
                                             angle_threshold=0.1,
                                             stub_width=0.5)

stubs_lay = i3.LayoutCell().Layout(elements=elems_add + elems_subt)
stubs_lay.visualize()
plot stubDC
<Figure size 640x480 with 1 Axes>

In some cases the stub elements turn out to be too small due to grid snapping. Therefore it is also possible to specify the grow_amount argument:

elems_add, elems_subt = i3.get_stub_elements(dc_lay,
                                             angle_threshold=0.1,
                                             stub_width=0.5,
                                             grow_amount=0.5)

stubs_lay = i3.LayoutCell().Layout(elements=elems_add + elems_subt)
stubs_lay.visualize()
plot stubDC
<Figure size 640x480 with 1 Axes>

To stub the acute angles and create the new layout we can use stub_acute_angles. There are several ways to do this:

  • By default, all acute angles on all layers are stubbed.

elems = i3.stub_acute_angles(dc_lay,
                             angle_threshold=0.1,
                             stub_width=0.5)
stubbed_layout = i3.LayoutCell().Layout(elements=elems, ports=dc_lay.ports)
  • Specify which stub elements to add and subtract using the stub_elements argument.

elems = i3.stub_acute_angles(dc_lay,
                             stub_elements=[elems_add, elems_subt])
stubbed_layout = i3.LayoutCell().Layout(elements=elems, ports=dc_lay.ports)
  • Specify the layer(s) on which to stub the acute angles.

elems = i3.stub_acute_angles(dc_lay,
                             angle_threshold=0.1,
                             stub_width=0.5,
                             layers=[i3.TECH.PPLAYER.WG.CLADDING])
stubbed_layout = i3.LayoutCell().Layout(elements=elems, ports=dc_lay.ports)

In certain situations a combination of the previous two methods might be useful. The three examples above give the same result.

stubbed_layout.visualize()
plot stubDC
<Figure size 640x480 with 1 Axes>

It is important to note that stub_acute_angles does a flatten + merge operation on the full layout. Hence it is not recommended to perform this function on a large design. For large designs, other approaches can be taken, such as splitting up the design into smaller pieces, or, in case you only want to add elements (not substract), performing a flat_copy and add the stub elements manually.