Note
Go to the end to download the full example code
Dummy Filling during Layout design
This sample illustrates how to perform dummy filling on a layout. Dummy filling is crucial for controlling the density of certain layers, which helps prevent issues during fabrication steps.
In IPKISS, dummy filling can be performed directly on your layout by using ipkiss3.all.dummy_fill_layout, or on a gds file
by using ipkiss3.all.dummy_fill_gdsii.
This example demonstrates how to:
Define a test structure and a design containing a routed splitter tree.
Add a frame to simulate a realistic design boundary.
Apply dummy filling to the layout using a specified fill cell, while ignoring certain layers (e.g., the documentation layer).
Disclaimer: Dummy filling here is done on the silicon layer only, since no metal was used in this device.

import pteam_library_si_fab.all as lib
import si_fab.all as pdk
import ipkiss3.all as i3
DESIGN_SIZE = (1000, 1000)
class TestStructure(i3.PCell):
total_length = i3.PositiveNumberProperty(
default=DESIGN_SIZE[0] - 100,
doc="Total length of the test structure",
)
class Layout(i3.LayoutView):
def generate(self, layout):
gc = pdk.GratingCoupler()
layout += i3.place_and_route(
insts={"gc_in": gc.Layout(), "gc_out": gc.Layout()},
specs=[
i3.Place("gc_in@CW", (0, 0)),
i3.Place("gc_out@CE", (self.total_length, 0), angle=180),
i3.ConnectManhattan("gc_in:out", "gc_out:out"),
],
)
return layout
class Design(i3.PCell):
class Layout(i3.LayoutView):
def generate(self, layout):
# We instantiate the splitter tree
splitter_tree = lib.SplitterTree(levels=5)
# We pass the splitter tree to the routed splitter tree
routed_splitter_tree = lib.RoutedSplitterTree(splitter_tree=splitter_tree, length_of_out_wg=120)
length = routed_splitter_tree.Layout().size_info().get_width()
layout += i3.place_and_route(
insts={
"DUT": routed_splitter_tree,
"test_structure": TestStructure(total_length=length),
},
specs=[
i3.Place.X("test_structure", x=50),
i3.Place.X("DUT@W", x=50),
i3.Place.Y("test_structure@S", y=50),
i3.Place.Y("DUT@S", y=50, relative_to="test_structure@N"),
],
)
# add a frame, such it replicates a realistic design
layout += i3.Box(
layer=pdk.TECH.PPLAYER.DOC, box_size=DESIGN_SIZE, center=(DESIGN_SIZE[0] / 2, DESIGN_SIZE[1] / 2)
)
# Now we want to perform dummy filling on the layout directly -> this makes it easier to iterate
# For this example, we don't have metal layers to fill, so we fill the silicon layers to control density
# and prevent problems during litho and wet etch.
# We create a square using i3.Box to serve as the dummy fill cell.
fill_cell = i3.Box(layer=pdk.TECH.PPLAYER.SI, box_size=(4, 4))
# Now we dummy fill our current layout, given the fill_cell
# Since the frame covers the design, we specify it in the ignore argument.
# Otherwise, the dummy fill will try to avoid overlapping it.
dummy_elements = i3.dummy_fill_layout(layout, fill_cell=fill_cell, ignore=[pdk.TECH.PPLAYER.DOC])
# if you want more control over the dummy filling you can specify more of the parameters
# dummy_elements = i3.dummy_fill_layout(
# layout,
# fill_cell=fill_cell,
# target=pdk.TECH.PPLAYER.DOC, # target is the layer which defines the area to do the dummy filling in
# ignore=[pdk.TECH.PPLAYER.DOC], # the frame is perfect target layer, but we want to ignore it here
# density=0.75,
# design_buffer=5,
# edge_buffer=20,
# )
#
layout += dummy_elements
return layout
Design().Layout().visualize()
# if you want to do dummy filling on a gds, that is also possible using the other function
# i3.dummy_fill_gdsii(filename, fill_cell, ...)