Skip to content

Commit

Permalink
new: SiEPIC.scripts.layout_diff
Browse files Browse the repository at this point in the history
Compare the difference between layouts.
Useful for blackbox replacement double-checking.
  • Loading branch information
lukasc-ubc committed Nov 4, 2024
1 parent 3c4a4f6 commit f70e85c
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 2 deletions.
57 changes: 55 additions & 2 deletions klayout_dot_config/python/SiEPIC/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
fetch_measurement_data_from_github
measurement_vs_simulation
resize waveguide
layout_diff
replace_cell
svg_from_cell
zoom_out: When running in the GUI, Zoom out and show full hierarchy
Expand Down Expand Up @@ -3074,7 +3075,52 @@ def button(self):
wdg.show()


def replace_cell(layout, cell_x_name, cell_y_name, cell_y_file=None, cell_y_library=None, Exact = True, RequiredCharacter = '$', debug = False):
def layout_diff(cell1, cell2, tol = 1, verbose=True):
'''
Check two cells to make sure they are identical, within a tolerance.
Arguments:
cell1, cell2: pya.Cell()
tol = 1 nm
Returns:
Number of differences
Limitations:
Both cells should be part of the same layout.
Based on https://github.com/atait/lytest
'''

if not cell1.layout() == cell2.layout():
raise Exception ('SiEPIC.scripts.layout_diff is only implement for cells in the same layout.')

# Count the differences
diff_count = 0

# Get a list of the layers
layers = []
layout = cell1.layout()
for li in layout.layer_indices():
layers.append ( li )

# Do geometry checks on each layer
for li in layers:
r1 = pya.Region(cell1.begin_shapes_rec(li))
r2 = pya.Region(cell2.begin_shapes_rec(li))

rxor = r1 ^ r2

if tol > 0:
rxor.size(-tol)

if not rxor.is_empty():
diff_count += rxor.size()
if verbose:
print(
f" - SiEPIC.scripts.layout_diff: {rxor.size()} differences found in {cell1.name} on layer {layout.get_info(li)}."
)
return diff_count


def replace_cell(layout, cell_x_name, cell_y_name, cell_y_file=None, cell_y_library=None, Exact = True, RequiredCharacter = '$', run_layout_diff = True, debug = False):
'''
SiEPIC-Tools: scripts.replace_cell
Search and replace: cell_x with cell_y
Expand Down Expand Up @@ -3175,10 +3221,17 @@ def replace_cell(layout, cell_x_name, cell_y_name, cell_y_file=None, cell_y_libr
print(' - looking for cell. %s, %s, %s' % (cell_y_name, cell_y, layout.cell(cell_y_name)))
log += ' - Warning: cell destroyed, skipping replacement\n'
break # skip this cell
# Check if the BB cells are the same, by doing an XOR operation
# from . import layout_diff
if run_layout_diff:
if layout_diff(inst.cell, cell_x, tol=0):
if debug:
print(" - black box cells are different: %s vs %s" % (inst.cell.name, cell_x.name))
break;
# replace with CELL_Y
if inst.is_regular_array():
if debug:
print(" - replacing %s in %s, with cell array: %s" % (cell_x.name, cc.name, cell_y.name))
print(" - checked, and replaced %s in %s, with cell array: %s" % (cell_x.name, cc.name, cell_y.name))
ci = inst.cell_inst
cc.replace(inst, pya.CellInstArray(cell_y.cell_index(),inst.trans, ci.a, ci.b, ci.na, ci.nb))
else:
Expand Down
3 changes: 3 additions & 0 deletions klayout_dot_config/python/SiEPIC/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def registerKeyBindings():
# turn the hash back into a config string
config = ''.join('{}:{};'.format(key, val) for key, val in sorted(mapping.items()))[:-1]
pya.Application.instance().set_config('key-bindings', config)

pya.Application.instance().set_config('edit-connect-angle-mode', 'ortho')
pya.Application.instance().set_config('edit-inst-angle', '0')
pya.Application.instance().set_config('edit-move-angle-mode', 'diagonal')
Expand All @@ -160,6 +161,8 @@ def registerKeyBindings():
pya.Application.instance().set_config('guiding-shape-line-width', '0')
pya.Application.instance().set_config('rdb-marker-color', '#ff0000')
pya.Application.instance().set_config('rdb-marker-line-width', '8')
# pya.Application.instance().set_config('compression-level', '10')
# pya.Application.instance().set_config('write-cblocks', 'true')
# pya.Application.instance().set_config('default-layer-properties', os.path.join(os.path.realpath(__file__), os.pardir, os.pardir, os.pardir, 'libraries', 'klayout_Layers_EBeam.lyp'))

if pya.Application.instance().get_config('edit-mode') == 'false':
Expand Down
63 changes: 63 additions & 0 deletions klayout_dot_config/python/SiEPIC/tests/test_scripts_layout_diff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
Test for SiEPIC.scripts.layout_diff
by Lukas Chrostowski 2024
"""

def test_layout_diff():
'''
'''

import pya

import SiEPIC
from SiEPIC._globals import Python_Env
from SiEPIC.utils.layout import new_layout

import os

if Python_Env == 'Script':
# For external Python mode, when installed using pip install siepic_ebeam_pdk
import GSiP

tech_name = 'GSiP'

from packaging import version
if version.parse(SiEPIC.__version__) < version.parse("0.5.4"):
raise Exception("Errors", "This example requires SiEPIC-Tools version 0.5.4 or greater.")

'''
Create a new layout using the EBeam technology,
with a top cell
'''
cell, ly = new_layout(tech_name, 'top', GUI=True, overwrite = True)

waveguide_type_delay='SiN routing TE 1550 nm (compound waveguide)'

# Load cells from library
cell1 = ly.create_cell('Ring_Modulator_DB', 'GSiP',
{'r':10,
})
cell2 = ly.create_cell('Ring_Modulator_DB', 'GSiP',
{'r':11,
})

from SiEPIC.scripts import layout_diff

num_diff = layout_diff(cell1, cell2)
print(num_diff)
assert num_diff == 123


cell3 = cell1.dup()
num_diff = layout_diff(cell1, cell3)
print(num_diff)
assert num_diff == 0




if __name__ == "__main__":
test_layout_diff()

0 comments on commit f70e85c

Please sign in to comment.