Dataprep#

When building a reticle sometimes you want to do boolean operations. This is usually known as dataprep.

You can do this at the component level or at the top reticle assembled level.

This tutorial is focusing on cleaning DRC on masks that have already been created.

import gdsfactory as gf
from gdsfactory.generic_tech.layer_map import LAYER

import gplugins.klayout.dataprep as dp

You can manipulate layers using the klayout LayerProcessor to create a RegionCollection to operate on different layers.

The advantage is that this can easily clean up routing, proximity effects, acute angles.

c = gf.Component()
ring = c << gf.components.coupler_ring(radius=20)
c.write_gds("input.gds")
d = dp.RegionCollection(gdspath="input.gds")
c.plot()
2024-05-10 10:17:36.217 | WARNING  | __main__:<module>:3 - UserWarning: Unnamed cells, 1 in 'Unnamed_22d399ec'
2024-05-10 10:17:36.219 | INFO     | gdsfactory.component:_write_library:2003 - Wrote to 'input.gds'
2024-05-10 10:17:36.222 | WARNING  | gdsfactory.component:plot_klayout:1645 - UserWarning: Unnamed cells, 1 in 'Unnamed_22d399ec'
../_images/4e0ab6786b5767aa9b69d4f7245ce9497bc010419125c1d76a750b2c37b9a091.png

Copy layers#

You can access each layer as a dict.

d[LAYER.N] = d[
    LAYER.WG
].copy()  # make sure you add the copy to create a copy of the layer
d.show()
d.plot()
2024-05-10 10:17:36.413 | WARNING  | gdsfactory.klive:show:49 - UserWarning: Could not connect to klive server. Is klayout open and klive plugin installed?
../_images/373da829d50ad968d026b926231b8b93bfdc01ef65f8c56ae6b495c4b8181306.png

Remove layers#

d[LAYER.N].clear()
d.show()
d.plot()
../_images/373da829d50ad968d026b926231b8b93bfdc01ef65f8c56ae6b495c4b8181306.png

Size#

You can size layers, positive numbers grow and negative shrink.

d[LAYER.SLAB90] = d[LAYER.WG] + 2  # size layer by 4 um
d.show()
d.plot()
../_images/373da829d50ad968d026b926231b8b93bfdc01ef65f8c56ae6b495c4b8181306.png

Over / Under#

To avoid acute angle DRC errors you can grow and shrink polygons. This will remove regions smaller

d[LAYER.SLAB90] += 2  # size layer by 4 um
d[LAYER.SLAB90] -= 2  # size layer by 2 um
d.plot()
../_images/373da829d50ad968d026b926231b8b93bfdc01ef65f8c56ae6b495c4b8181306.png

Smooth#

You can smooth using RDP

d[LAYER.SLAB90].smooth(
    1 * 1e3
)  # smooth by 1um, Notice that klayout units are in DBU (database units) in this case 1nm, so 1um = 1e3
d.plot()
../_images/373da829d50ad968d026b926231b8b93bfdc01ef65f8c56ae6b495c4b8181306.png

Booleans#

You can derive layers and do boolean operations.

d[LAYER.DEEP_ETCH] = d[LAYER.SLAB90] - d[LAYER.WG]
d.plot()
../_images/373da829d50ad968d026b926231b8b93bfdc01ef65f8c56ae6b495c4b8181306.png

Fill#

import gdsfactory as gf
import kfactory as kf
from kfactory.utils.fill import fill_tiled

c = kf.KCell("ToFill")
c.shapes(kf.kcl.layer(1, 0)).insert(
    kf.kdb.DPolygon.ellipse(kf.kdb.DBox(5000, 3000), 512)
)
c.shapes(kf.kcl.layer(10, 0)).insert(
    kf.kdb.DPolygon(
        [kf.kdb.DPoint(0, 0), kf.kdb.DPoint(5000, 0), kf.kdb.DPoint(5000, 3000)]
    )
)

fc = kf.KCell("fill")
fc.shapes(fc.kcl.layer(2, 0)).insert(kf.kdb.DBox(20, 40))
fc.shapes(fc.kcl.layer(3, 0)).insert(kf.kdb.DBox(30, 15))

# fill.fill_tiled(c, fc, [(kf.kcl.layer(1,0), 0)], exclude_layers = [(kf.kcl.layer(10,0), 100), (kf.kcl.layer(2,0), 0), (kf.kcl.layer(3,0),0)], x_space=5, y_space=5)
fill_tiled(
    c,
    fc,
    [(kf.kcl.layer(1, 0), 0)],
    exclude_layers=[
        (kf.kcl.layer(10, 0), 100),
        (kf.kcl.layer(2, 0), 0),
        (kf.kcl.layer(3, 0), 0),
    ],
    x_space=5,
    y_space=5,
)

gdspath = "mzi_fill.gds"
c.write(gdspath)
c.plot()
2024-05-10 10:17:36.642 | INFO     | kfactory.utils.fill:fill_tiled:204 - filling ToFill with fill
2024-05-10 10:17:36.705 | INFO     | kfactory.utils.fill:fill_tiled:207 - done with filling ToFill
../_images/23961cc9c091d3e7d683b4af03ffe89896adb3c6b8e00b0cbeb4955366c42485.png