Grid snapping#

GDS represents points as integers where each point corresponds to a database unit (DBU). Typically, in most foundries, the default DBU is set to 1 nanometer (1nm).

gdsfactory snaps ports to the grid by default to avoid grid snapping errors which are common in layout designs.

Example of grid snapping errors.

import gdsfactory as gf

nm = 1e-3

wg1 = gf.Component()
wg1.add_polygon(
    [(0, 0), (1.4 * nm, 0), (1.4 * nm, 1 * nm), (0, 1 * nm)], layer=(1, 0)
)  # rounds to 1 nm

wg1.add_polygon(
    [(0, 3 * nm), (1.6 * nm, 3 * nm), (1.6 * nm, 4 * nm), (0, 4 * nm)], layer=(1, 0)
)  # rounds to 2 nm

wg1.plot()
../_images/ac7925e8f7bce5bf52c8295a1b62b295db6dc1d5fd4a22858d05c3df963b0970.png

⚠️ Warning: Manhattan Orientations#

It’s crucial to always maintain ports with Manhattan orientations (0, 90, 180, 270 degrees). Non-Manhattan ports can lead to ports snapping off the grid, resulting in 1nm gaps in your layouts, which can be detrimental to the design’s integrity.

Although gdsfactory provides functions to connect and route component ports that are off-grid or have non-Manhattan orientations, this feature is disabled by default for safety reasons.

Note: If you intend to create off-grid ports and non-Manhattan connections, you must enable this feature manually. This should be done with caution and a thorough understanding of the potential implications on your design.

c = gf.Component()
w1 = c << gf.c.straight(length=4 * nm, width=4 * nm)
w1.drotate(45)

w2 = c << gf.c.straight(length=4 * nm, width=4 * nm)
w2.connect("o1", w1["o2"])
c  # in this case ports overlap by an extra nm because of the rotation, instead of connecting them with no overlap
../_images/a8f603533c864767919c0ba36d82adde9ceebea9dc3fe25ce508230fa4fc05d4.png
c = gf.Component()
w1 = c << gf.components.straight(length=4 * nm, width=4 * nm)
w1.drotate(30)

w2 = c << gf.components.straight(length=4 * nm, width=4 * nm)
w2.connect("o1", w1["o2"])
c  # in this case ports have a 1nm gap error because of the rotation
../_images/043f408f4f022763e97dc53dfcf650f044b69eb3dd82d85a673e0b319b01b617.png

Fix Non manhattan connections#

The GDS format often has issues with non-manhattan shapes, due to the rounding of vertices to a unit grid and to downstream tools (i.e. DRC) which often tend to assume cell references only have rotations at 90 degree intervals.

To fix it, you can insert them as virtual instances.

For example:

import gdsfactory as gf

nm = 1e-3
c = gf.Component()
w = gf.components.straight(length=4 * nm, width=4 * nm)
w1 = c.create_vinst(w)
w1.rotate(30)

w2 = c.create_vinst(w)
w2.connect("o1", w1["o2"])
c
../_images/4c3ceea2510db464875137608f20621ed8394fdb89a1fe6c90023c536a57dbc3.png
import gdsfactory as gf


@gf.cell(check_instances="none")
def demo_non_manhattan():
    c = gf.Component("bend")
    b = c << gf.components.bend_circular(angle=30)
    s = c << gf.components.straight(length=5)
    s.connect("o1", b.ports["o2"])
    return c


c1 = demo_non_manhattan()
c1
../_images/900709bc74a1826a61754894285e94b8acb0342ab4f837a70c562486a1fa3507.png

if you zoom in between the bends you will see a notch between waveguides due to non-manhattan connection between the bends.

gap

Solution#

import gdsfactory as gf


@gf.vcell
def snap_bends() -> gf.ComponentAllAngle:
    c = gf.ComponentAllAngle()
    b = gf.c.bend_euler_all_angle(angle=37)
    b1 = c << b
    b2 = c << b
    b2.connect("o1", b1.ports["o2"])
    c.add_port("o1", port=b1.ports["o1"])
    c.add_port("o2", port=b2.ports["o2"])
    return c


c = snap_bends()
c
../_images/c5ed0882f158b6120fbe1ad84f03c38dac2251aa674aeeebcc0cb0cebb6a45bf.png
c.show()

If you zoom in the connection you will see now a perfect connection.

no gap