How to compare two cells objects (if they contain the exact same geometries) in python

Hello @Matthias, Thank you for you work on this great project.

I searched the documentation for a standard way to compare two cells geometries, to check if they are equivalent. I have not found such a way. But klayout is huge, perhaps you have a more standardized and robust way to compare two cells.

Here is my way.

#!/bin/python3.8
import klayout.db as pya
import klayout.rdb as rdb

def cell_layers(cell_obj):
    layers = {}
    for layer_idx in range(255):
        layers[layer_idx] = cell_obj.shapes(layer_idx)
    return layers

def cell_eq(cella, cellb):
    cella_layers = cell_layers(cella)
    cellb_layers = cell_layers(cellb)
    xor_result_regions = []
    failed = False
    for layer_idx in range(255):
        xor_result_regions.append(pya.Region(cella_layers[layer_idx]) ^ pya.Region(cellb_layers[layer_idx]))
    for aregion in xor_result_regions:
        if not aregion.is_empty():
            failed = True
            break
    return not failed

# Same GDS used for both Layout objects
layout_path = '/path/to/gds/file'
layout_1 = pya.Layout()
layout_2 = pya.Layout()

layout_1.read(str(layout_path))
layout_2.read(str(layout_path))

layout_1_cells = {layout_1_cell.name: layout_1_cell for layout_1_cell in layout_1_cells.each_cell()}
layout_2_cells = {layout_2_cell.name: layout_2_cell for layout_2_cell in layout_2_cells.each_cell()}
for cell_layout1_name in layout_1_cells.keys():
    print(cell_eq(layout_1_cells[cell_layout1_name], layout_2_cell[cell_layout1_name]))

So far this has produced wrong results; two equivalent cells are not equivalent according to this test.

(verified that the two cells are equivalent via loading same gds in klayout and using the xor tool on the top_cell() in both layouts in the same panel -which is manually set- from the GUI and producing zero differences)

Thank you for taking the time.

Comments

  • @nofal There are a couple of problems in that code.

    First of all, the layer index is not the GDS layer number (that's why it's called "index", not "number). So you cannot simply iterator from 0 to 255 and then compare 1 with 1 and 2 with 2 etc.

    The layer index is the internal designation of the layer. Each layout stores a number of layers as layer #0, #1, etc. These numbers are not necessarily in a specific order. You have to use "Layout#get_info(layer_index)" to find what GDS layer/datatype the specific layer index is for. So when you want to find the layers you need to compare, you can use a code similar to this one:

    ly1 = ... # first layout
    ly2 = ... # second layout
    
    layer_map = {}
    
    for li in ly1.layer_indexes():
      info = ly1.get_info(li)
      layer_map[info] = [ li, None ]
    
    for li in ly2.layer_indexes():
      info = ly2.get_info(li)
      if info in layer_map:
        layer_map[info][1] = li
      else:
        layer_map[info] = ( None, li )
    
    for info in layer_map.keys():
      (li1, li2) = layer_map[info]
      if li1 is None:
        print(str(info) + " is present only in layout 2")
      elif li2 is None:
        print(str(info) + " is present only in layout 1")
      else:
        print(str(info) + " is present in both layouts")
        # Do XOR between li1 and li2
    

    Next, you are not comparing child cells - so if a cell references other cells and does it differently in both layouts, you will not notice that there is a problem.

    The region approach is also quite simplistic - for larger layouts this will give you some pain with respect to run times and memory consumption. That's why the XOR and the DRC feature offer tiling or hierarchical mode. Implementing these modes in a script requires a lot more code.

    The code is also not very efficient. Instead of first computing (and storing) all the XOR results and later checking whether they are empty, you should compute the XOR, check if it is empty and return True from "cell_eq" immediately. No need for keeping the XOR regions and for going further.

    Matthias

Sign In or Register to comment.