Using the fill tool

edited December 2014 in General
I have created a mask consisting of evenly spaced rectangles. These structures are to be fully exposed in e-beam lithography, so I need to fill them. I understand that using the layer toolbox to assign some "stipple" is only for visualization and does not actually do any filling?

Do I need to use the fill tool in Utilities? How do I use it? I keep getting an error message saying "no valid layer selected to get fill cell's bounding box from"

Please try to explain simply, as I've only recently started using Klayout :)


  • edited November -1


    are you familiar with mask layout procedures in general?

    Basically, every polygon (box, path ...) is "filled" on a mask. The stipple is only provided for visualization - if multiple layers are overlapping the stipple pattern helps to distinguish them.

    The "fill tool" has an entirely different scope. It is used to create dummy shapes (filled ones) in order to equalize the pattern density. The background is that certain processes (etching, CMP etc.) give better results if the average density of the pattern is similar on the mask. Hence the fill tool can be used to put dummy shapes into the empty regions so the density is increased there leading to a more uniform density pattern.


  • Is there a way to use threading with the fill tool?
    We have a relatively large design, and a relatively powerful PC with lots of cores that is taking a lot (more than a day) to compute the filling of a single chip of our design.
    I saw something similar in a post for the DRC, you mentioned a "tiles" command, and that indeed helped to speed up our DRC.
    Is there something similar for the fill tool?


  • edited February 2019

    Hi Doug,

    yes, tiling should help. But that's not available yet as an option in the fill dialog. You can however add it through scripting and embed the algorithm inside a tiling processor.

    That's not entirely trivial, specifically if you want to enable multiple cores. The fill algorithm itself isn't thread-safe yet, but you'll benefit from the tiling approach in other ways:

    • memory footprint is reduced to a single tile
    • any boolean and sizing operations required can happen on multiple cores

    This approach requires that you script all the details. Here is a starting point. I hope the comments explain the various steps:

    # Take the loaded layout and it's top cell to create the fill on
    ly = RBA::CellView::active.layout
    micron2dbu = RBA::CplxTrans::new(ly.dbu).inverted
    top_cell = ly.top_cell
    # This example assumes we want to fill everything not covered by ndiff|pdiff|ntie|ptie
    # with fill cell "DIFF_FILL" with a min distance of 3 µm.
    # The fill cell is created if required using a repetition box of -2,-2/2,2 and a single
    # patch with 2x2 µm centered in this box at layer 2.
    ndiff = ly.layer(3, 0)
    pdiff = ly.layer(4, 0)
    ntie = ly.layer(5, 0)
    ptie = ly.layer(6, 0)
    # chip's bbox (boundary to fill)
    chip = RBA::DBox::new(0, 0, 4500.0, 4500.0)
    # distance
    distance = 3.0  # micron
    # number of cores for the boolean operations
    ncpus = 4
    # tile size in micron
    tile_size = 1000.0
    # origin of the fill pattern
    # For "enhanced fill use":
    #   fc_origin = nil
    fc_origin = RBA::DPoint::new(0.0, 0.0)
    # creates a fill cell with a shape on 
    fc_name = "DIFF_FILL"
    fc_box = RBA::DBox::new(-2.0, -2.0, 2.0, 2.0)
    # define the fill cell's content
    fill_layer = ly.layer(2, 0)
    fill_shape = RBA::DBox::new(-1.0, -1.0, 1.0, 1.0)
    # ----------------------------
    # implementation
    fill_cell = ly.cell(fc_name)
    if ! fill_cell
      fill_cell = ly.create_cell(fc_name)
      fill_shape_in_dbu = micron2dbu * fill_shape
    fc_box_in_dbu = micron2dbu * fc_box
    fc_origin_in_dbu = fc_origin && (micron2dbu * fc_origin)
    # This is an object which will receive the regions to tile
    # It is driven single-threaded which is good since the tiling function
    # isn't multi-threading safe
    class TilingOperator < RBA::TileOutputReceiver
      def initialize(ly, top_cell, *fill_args)
        @ly = ly
        @top_cell = top_cell
        @fill_args = fill_args
      def put(ix, iy, tile, obj, dbu, clip)
        # This is the core function. It creates the fill.
        # For details see
        @top_cell.fill_region(obj, *@fill_args)
    # prepare a tiling processor to compute the parts to put into the tiling algorithm
    # this can be tiled
    tp = RBA::TilingProcessor::new
    tp.frame = chip
    tp.dbu = ly.dbu
    tp.threads = ncpus
    tp.tile_size(tile_size, tile_size)
    tp.input("ndiff", ly, top_cell.cell_index, ndiff)
    tp.input("pdiff", ly, top_cell.cell_index, pdiff)
    tp.input("ntie", ly, top_cell.cell_index, ntie)
    tp.input("ptie", ly, top_cell.cell_index, ptie)
    tp.var("dist", distance / ly.dbu)
    tp.output("to_fill", TilingOperator::new(ly, top_cell, fill_cell.cell_index, fc_box_in_dbu, fc_origin_in_dbu))
    # perform the computations inside the tiling processor through "expression" syntax
    # (see
    tp.queue("var exclude = ndiff + pdiff + ntie + ptie; var fill_region = _tile & _frame - exclude.sized(dist); _output(to_fill, fill_region)")
      ly.start_changes   # makes the layout handle many changes more efficiently
      tp.execute("Tiled fill")

    And this is the result on a sample of mine with enhanced mode (fc_origin = nil):

    The white shapes are the fill cell instances created.



  • You are incredible Matthias. And you have an incredible piece of software.
    It worked as a charm. Exactly what I needed.
    Thanks a bunch!


Sign In or Register to comment.