Skip to content

Commit

Permalink
checking for invalid masks and tested
Browse files Browse the repository at this point in the history
  • Loading branch information
atait committed Jun 21, 2019
1 parent 30c5902 commit 455ebea
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 35 deletions.
4 changes: 2 additions & 2 deletions lymask/invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
active_technology, set_active_technology, \
tech_layer_properties, \
lys, reload_lys
from lymask.steps import all_func_dict
from lymask.steps import all_func_dict, assert_valid_step_list


parser = argparse.ArgumentParser(description="Command line mask dataprep")
Expand All @@ -34,10 +34,10 @@ def cm_main():

def _main(layout, ymlfile, tech_obj=None):
# todo: figure out which technology we will be using and its layer properties
# todo: reload lys using technology
with open(ymlfile) as fx:
step_list = yaml.load(fx)
reload_lys(tech_obj, dataprep=True)
assert_valid_step_list(step_list)
for func_info in step_list:
func = all_func_dict[func_info[0]]
try:
Expand Down
70 changes: 45 additions & 25 deletions lymask/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,44 +180,47 @@ def precomp(cell, **kwargs):
def mask_map(cell, clear_others=False, **kwargs):
''' lyp_file is relative to the yml file. If it is None, the same layer properties will be used.
kwarg keys are destination layers and values are source layers, which can include "+"
There is a problem if you have 101 defined in your file and then another layer that is not defined.
'''
mask_layer_index = 101
assert_valid_mask_map(kwargs)
# merging and moving to new layers
for dest_layer, src_expression in kwargs.items():
new_layinfo = pya.LayerInfo(mask_layer_index, 0, dest_layer)
lys[dest_layer] = new_layinfo
cell.layout().layer(new_layinfo)
if not dest_layer in lys.keys():
new_layinfo = pya.LayerInfo(mask_layer_index, 0, dest_layer)
lys[dest_layer] = new_layinfo
cell.layout().layer(new_layinfo)

components = src_expression.split('+')
for comp in components:
try:
comp_lay_info = lys[comp.strip()]
except KeyError as err:
message_loud('Source layer [{}] not found in existing designer or dataprep layerset.'.format(comp))
raise
comp_lay_info = lys[comp.strip()]
cell.copy(comp_lay_info, lys[dest_layer])
mask_layer_index += 1
# if isGUI():
# try:
# lv = gui_view()
# add_tab = True
# except UserWarning:
# # No view is selected. We might be in batch mode
# add_tab = False
# if add_tab:
# insert_layer_tab(tab_name='Masks')
# for dest_layer in kwargs.keys():
# lay_prop = pya.LayerProperties()
# lay_prop.source_name = lys.get_as_LayerInfo(dest_layer).name
# lay_prop.source_layer = lys.get_as_LayerInfo(dest_layer).layer
# lay_prop.source_datatype = lys.get_as_LayerInfo(dest_layer).datatype
# lv.init_layer_properties(lay_prop)
# lv.insert_layer(lv.end_layers(), lay_prop)

if clear_others:
for any_layer in lys.keys():
if any_layer not in kwargs.keys() and any_layer != 'FLOORPLAN':
cell.clear(lys[any_layer])


def assert_valid_mask_map(mapping):
for dest_layer, src_expression in mapping.items():
try:
lys[dest_layer]
except KeyError as err:
message_loud('Warning: Destination layer [{}] not found in mask layerset. We will make it...'.format(dest_layer))
pass # This is allowed

components = src_expression.split('+')
for comp in components:
try:
comp_lay_info = lys[comp.strip()]
except KeyError as err:
message_loud('Error: Source layer [{}] not found in existing designer or dataprep layerset.'.format(comp))
raise


@dpStep
def clear_nonmask(cell):
''' Gets rid of everything except 101--199. That is what we have decided are mask layers.
Expand All @@ -230,7 +233,6 @@ def clear_nonmask(cell):
cell.clear(lys[any_layer])



@dpStep
def align_corners(cell):
''' Puts little boxes in the corners so lithography tools all see the same
Expand Down Expand Up @@ -261,3 +263,21 @@ def align_corners(cell):
mark = corner_mark.moved(east_west, north_south)
if not cell.shapes(ly.layer(marked_layer)).is_empty():
cell.shapes(ly.layer(marked_layer)).insert(mark)


def assert_valid_step_list(step_list):
''' This runs before starting calculations to make sure there aren't typos
that only show up after waiting for for all of the long steps
'''

# check function names
for func_info in step_list:
try:
func = all_func_dict[func_info[0]]
except KeyError as err:
message_loud('Function not supported. Available are {}'.format(all_func_dict.keys()))
raise

# check mask layers
if func is mask_map:
assert_valid_mask_map(func_info[1])
1 change: 0 additions & 1 deletion lymask/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,5 @@ def reload_lys(technology=None, clear=False, dataprep=False):
lv.transaction('Bump transaction')
lv.current_layer_list = 0


# reload_lys()

1 change: 1 addition & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
lytest
klayout
9 changes: 9 additions & 0 deletions tests/tech/example_tech/dataprep/bad_masks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# One of the source layers in mask map does not exist in the klayout_layers.lyp
# This means it should throw a KeyError before running nw_sleeve.
# The test will expect this KeyError, but not a TypeError
---
- - nw_sleeve
- Delta: 'not a float' # This will cause a TypeError if it runs, so the test will fail
- - mask_map
- mask_nw_ebeam: m2_nw_ebeam + not_in_lyp
...
24 changes: 17 additions & 7 deletions tests/test_example.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import os, sys
import subprocess
import pytest
import pya

os.environ['KLAYOUT_HOME'] = os.path.dirname(os.path.realpath(__file__))

import lymask
Expand All @@ -26,13 +29,20 @@ def test_from_technology():
run_xor(outfile, reffile)


# def test_cm():
# command = ['lymask']
# command += [layout_file]
# command += [dataprep_file]
# command += ['-o', outfile]
# subprocess.check_call(command)
# run_xor(outfile, reffile)
def test_lyp_loading():
from lymask.utilities import set_active_technology, reload_lys, lys
layout = pya.Layout()
layout.read(layout_file)
lys.active_layout = layout

lymask.set_active_technology('example_tech')
lymask.utilities.reload_lys()

assert lys['m5_wiring'] is lys('m5_wiring') is lys.m5_wiring

with pytest.raises(KeyError):
batch_main(layout_file, ymlspec='bad_masks', technology='example_tech')


def test_cm_from_tech():
# this also checks that it defaults to default.yml
Expand Down

0 comments on commit 455ebea

Please sign in to comment.