feature request pattern density and dummy optimization

edited March 2012 in General
Hello Matthias,

Thanks for all your hard work (and everyone else involved) to make such a useful, free tool.

I'm interested in RBA scripts for calculating and plotting effective local pattern density for a given layout and technology file. The technology file would specify the unit cell size for which to determine the local density and any models/filters for weighting the data within a cell.

The effective local pattern density information could then be used to help designers choose a better dummy fill density, or fed into an algorithm that optimizes their generation; all in order to improve process uniformity.

Perhaps something very basic could be put together using the clip tool, calc area tool, and tiling utility.

Any thoughts?



  • edited 2:54PM

    Hi JRO,

    actually that's possible. I have included a script below which demonstrates that. The parameters of the density map are coded into the script currently. The script can be extended to read those parameters from a file or compute them from the cell's bounding box.

    The script outputs the density as an image overlay. Black is for density 0 and white for density 100%. You can adjust the colors by double-clicking on the image and choosing other colors in the data mapping tab. It should be easy to extend the script to write some report file or similar.

    Please note that the performance is somewhat limited due to performance limitations of the scripting language and the flat merge operation. Commercial tools are faster by an order of magnitude. I was however able to derive the density map with the parameters shown from a metal layer of a 1.5G (50 square mm) test layout in approximately 5 minutes with a window size of 50x50 micron.

    Best regards,


    $multiclip = RBA::Action.new
    $multiclip.title = "Density Map"
    $multiclip.on_triggered do 
      # Obtain the parameters for the density map 
      # TODO: read them from some setup file or provide a UI for that (difficult) ...
      xmin = 0.0         # left coordinate of the mapping area
      xmax = 7000.0      # right coordinate of the mapping area
      ymin = 0.0         # bottom coordinate of the mapping area
      ymax = 7000.0      # top coordinate of the mapping area
      xw = 50.0          # horizontal window size
      yw = 50.0          # vertical window size
      layer = RBA::LayerInfo.new(17, 0)     # source layer (GDS: layer, datatype)
      # Let's start ...
      # Set up the environment:
      app = RBA::Application.instance
      mw = app.main_window
      lv = mw.current_view
      if !lv || !lv.active_cellview
        raise "Multiclip: No view or no layout active"
      # obtain the pointers to the layout and cell 
      lay = lv.active_cellview.layout
      top = lv.active_cellview.cell_index
      top_name = lay.cell_name(top)
      top_bbox = lay.cell(top).bbox
      dbu = lay.dbu
      # identify the layer to take the density from
      input_layer = nil
      lay.layer_indices.each do |li|
        if lay.get_info(li).is_equivalent?(layer)
          input_layer = li
      # no such layer -> error
      if !input_layer
        raise "Multiclip: input layer #{layer.to_s} not found in input layout"
      # Start to collect the data:
      data = []
      # proceed row by row
      # (for each row we use the multi_clip_into which is more efficient than single clips per window)
      nrows = 0
      y = ymin
      while y < ymax-1e-6
        # Prepare a new layout to receive the clips
        # Hint: we need to clip all layers (clip does not support clipping of one layer alone currently).
        cl = RBA::Layout.new
        cl.dbu = dbu
        lay.layer_indices.each do |li|
          cl.insert_layer_at(li, lay.get_info(li))
        # Prepare the clip boxes for this row.
        # Note: because clip only works with boxes that overlap the cell's bounding box currently, we
        # have to operate with a subset of fields to support the general case.
        boxes = []
        x = xmin
        ncolumns = 0
        colstart = nil
        while x < xmax-1e-6
          b = RBA::Box.new((0.5 + x / dbu).floor, (0.5 + y / dbu).floor, (0.5 + (x + xw) / dbu).floor, (0.5 + (y + yw) / dbu).floor);
          if b.overlaps?(top_bbox)
            colstart ||= ncolumns 
          x += xw
          ncolumns += 1
        columns = []
        ncolumns.times { columns.push(0.0) }
        $stdout.write "Running row y=#{y}..#{y+yw} "
        if colstart
          col = colstart
          # Actually do the clip
          cells = lay.multi_clip_into(top, cl, boxes)
          ep = RBA::ShapeProcessor.new
          merged = RBA::Shapes.new
          # Compute the area within area box
          cells.each do |c|
            # merge the shapes to polygons and compute the area
            ep.merge(cl, cl.cell(c), input_layer, merged, true, 0, false, false)
            a = 0
            merged.each do |m|
              a += m.polygon.area
            # compute and store the density
            a = a * dbu * dbu / (xw * xw)
            columns[col] = a
            col += 1
            $stdout.write (0.5 + a * 10).floor.to_i
        puts ""
        columns.each { |d| data.push(d) }
        y += yw
        nrows += 1
      if nrows * ncolumns > 0
        img = RBA::Image.new(ncolumns, nrows, data)
        img.pixel_width = xw
        img.pixel_height = yw
        img.trans = RBA::DCplxTrans.new(1.0, 0.0, false, RBA::DPoint.new(xmin, ymin))
        if $multiclip_image_id
          lv.replace_image($multiclip_image_id, img) 
          $multiclip_image_id = img.id
    app = RBA::Application.instance
    mw = app.main_window
    menu = mw.menu
    menu.insert_separator("@toolbar.end", "name")
    menu.insert_item("@toolbar.end", "multiclip", $multiclip)
Sign In or Register to comment.