Skip to content

Commit

Permalink
Add MaskLayout.chip_copies dictionary
Browse files Browse the repository at this point in the history
After the mask is built, the chip_copies dictionary holds locations of all 
the chips in the mask layout. It can be used for custom file exports
of the mask geometrical data.

This commit also removes existing CSV file export of the chip locations
  • Loading branch information
caspar-iqm committed Nov 7, 2023
1 parent 49b4513 commit b011b3c
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 38 deletions.
25 changes: 8 additions & 17 deletions klayout_package/python/kqcircuits/masks/mask_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import subprocess
from importlib import import_module
from math import pi
import csv

from autologging import logged

Expand Down Expand Up @@ -141,10 +140,10 @@ def export_masks_of_face(export_dir, mask_layout, mask_set):
mask_layout: MaskLayout object for the cell and face reference
mask_set: MaskSet object for the name and version attributes to be included in the filename
"""
subdir_name_for_face = _get_mask_layout_full_name(mask_set, mask_layout)
subdir_name_for_face = get_mask_layout_full_name(mask_set, mask_layout)
export_dir_for_face = _get_directory(export_dir / str(subdir_name_for_face))
# export .oas file with all layers
path = export_dir_for_face / f"{_get_mask_layout_full_name(mask_set, mask_layout)}.oas"
path = export_dir_for_face / f"{get_mask_layout_full_name(mask_set, mask_layout)}.oas"
_export_cell(path, mask_layout.top_cell, "all")
# export .oas files for individual optical lithography layers
for layer_name in mask_layout.mask_export_layers:
Expand Down Expand Up @@ -208,7 +207,7 @@ def export_mask(export_dir, layer_name, mask_layout, mask_set):
top_cell.shapes(layer).insert(wafer.transformed(pya.Trans(2, True, 0, 0)))

layers_to_export = {layer_info.name: layer}
path = export_dir / (_get_mask_layout_full_name(mask_set, mask_layout) + f"-{layer_info.name}.oas")
path = export_dir / (get_mask_layout_full_name(mask_set, mask_layout) + f"-{layer_info.name}.oas")
_export_cell(path, top_cell, layers_to_export)

if invert:
Expand All @@ -229,7 +228,7 @@ def export_docs(mask_set, filename="Mask_Documentation.md"):
for mask_layout in mask_set.mask_layouts:

f.write("## Mask Layout {}:\n".format(mask_layout.face_id + mask_layout.extra_id))
mask_layout_str = _get_mask_layout_full_name(mask_set, mask_layout)
mask_layout_str = get_mask_layout_full_name(mask_set, mask_layout)
f.write(f"![alt text]({mask_layout_str}/{mask_layout_str}-mask_graphical_rep.png)\n")

f.write("### Number of Chips in Mask Layout {}\n".format(mask_layout.face_id + mask_layout.extra_id))
Expand Down Expand Up @@ -307,7 +306,7 @@ def export_docs(mask_set, filename="Mask_Documentation.md"):

f.write("## Links\n")
for mask_layout in mask_set.mask_layouts:
mask_layout_str = _get_mask_layout_full_name(mask_set, mask_layout)
mask_layout_str = get_mask_layout_full_name(mask_set, mask_layout)
mask_layout_path = mask_set._mask_set_dir / mask_layout_str

f.write("### Mask Files:\n")
Expand All @@ -323,14 +322,6 @@ def export_docs(mask_set, filename="Mask_Documentation.md"):

f.close()

for mask_layout in mask_set.mask_layouts:
mask_layout_str = _get_mask_layout_full_name(mask_set, mask_layout)
chips_map_file_name = mask_set._mask_set_dir / mask_layout_str / f"{mask_layout_str}-chips_map.csv"
with open(chips_map_file_name, "w+", encoding="utf-8", newline="") as g:
writer = csv.writer(g)
writer.writerows(
[['x', 'y', 'Active/Inactive', 'pixel id', 'pixel type']] + mask_layout.chip_array_to_export)
g.close()

@logged
def export_bitmaps(mask_set, spec_layers=mask_bitmap_export_layers):
Expand All @@ -339,9 +330,9 @@ def export_bitmaps(mask_set, spec_layers=mask_bitmap_export_layers):

# export bitmaps for mask layouts
for mask_layout in mask_set.mask_layouts:
mask_layout_dir_name = _get_mask_layout_full_name(mask_set, mask_layout)
mask_layout_dir_name = get_mask_layout_full_name(mask_set, mask_layout)
mask_layout_dir = _get_directory(mask_set._mask_set_dir / str(mask_layout_dir_name))
filename = _get_mask_layout_full_name(mask_set, mask_layout)
filename = get_mask_layout_full_name(mask_set, mask_layout)
view = mask_set.view
if view:
view.focus(mask_layout.top_cell)
Expand Down Expand Up @@ -411,5 +402,5 @@ def _get_directory(directory):
return directory


def _get_mask_layout_full_name(mask_set, mask_layout):
def get_mask_layout_full_name(mask_set, mask_layout):
return f"{mask_set.name}_v{mask_set.version}-{mask_layout.face_id}{mask_layout.extra_id}"
40 changes: 19 additions & 21 deletions klayout_package/python/kqcircuits/masks/mask_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ class MaskLayout:
dice_width: Dicing width for this mask layout
text_margin: Text margin for this mask layout
chip_size: side width of the chips (for square chips), or tuple (width, height) for rectangular chips
chip_array_to_export: List of lists where for each chip in the array we have the following record - (row,
column, Active/inactive, chip ID, chip type). Gets exported as an external csv file
edge_clearance: minimum clearance of outer chips from the edge of the mask
remove_chips: if True (default), chips that violate edge_clearance or conflict with markers are removed from
chip maps. Note that ``extra_chips`` are never removed.
Expand All @@ -79,6 +77,8 @@ class MaskLayout:
top_cell: Top cell of this mask layout
added_chips: List of (chip name, chip position, chip bounding box, chip dtrans, position_label)
populated by chips added during build()
chip_copies: Dictionary of ``{name_copy: properties}`` where ``properties`` contains the name and location data
for each chip that was actually added to the mask.
mirror_labels: Boolean, if True mask and chip copy labels are mirrored. Default False.
bbox_face_ids: List of face_ids to consider when calcualting the bounding box of chips. Defaults to [face_id]
"""
Expand Down Expand Up @@ -137,6 +137,7 @@ def __init__(self, layout, name, version, with_grid, chips_map, face_id, **kwarg
self.chip_counts = {}
self.extra_chips_maps = []
self.chip_array_to_export = []
self.chip_copies = {}
# For mask name the letter I stats at x=750
self._mask_name_letter_I_offset = 750

Expand Down Expand Up @@ -298,11 +299,14 @@ def get_position_label(i, j):
used_position_labels = set()
for (x, y), (chip_name, _, bbox, dtrans, position_label, mask_layout) in chips_dict.items():
labels_cell_2 = labels_cells[mask_layout]
if not position_label:
if x not in xvals or y not in yvals:
raise ValueError("No position_label override yet label was not automatically generated")
if x not in xvals or y not in yvals:
i, j = None, None
else:
i = sorted(yvals, reverse=True).index(y)
j = sorted(xvals).index(x)
if not position_label:
if i is None or j is None:
raise ValueError("No position_label override yet label was not automatically generated")
position_label = get_position_label(i, j)
if position_label in used_position_labels:
raise ValueError(f"Duplicate use of chip position label {position_label}. "
Expand All @@ -317,22 +321,16 @@ def get_position_label(i, j):
mask_layout._add_chip_graphical_representation_layer(chip_name,
dtrans * (pya.DPoint(bbox_x2, bbox.bottom)),
position_label, bbox.width(), labels_cell_2)
self.chip_array_to_export.append([i, j, "Active", position_label, chip_name])

# Fill in gaps in the grid and mark them as inactive
for i in range(max([x[0] for x in self.chip_array_to_export]) + 1):
for j in range(max([x[1] for x in self.chip_array_to_export]) + 1):
entry_found = False
for chip_info in self.chip_array_to_export:
if chip_info[0] == i and chip_info[1] == j:
entry_found = True
break
if not entry_found:
self.chip_array_to_export.append([i, j, "Inactive", get_position_label(i, j), "---"])
# Sort entries primarily by row and secondarily by column
self.chip_array_to_export.sort(key=lambda x: x[1])
self.chip_array_to_export.sort(key=lambda x: x[0])

chip_box = pya.DBox(dtrans * bbox)
self.chip_copies[position_label] = {
'name_chip': chip_name,
'i': i,
'j': j,
'x': chip_box.left,
'y': chip_box.bottom,
'width': chip_box.width(),
'height': chip_box.height(),
}

def face(self):
"""Returns the face dictionary for this mask layout"""
Expand Down

0 comments on commit b011b3c

Please sign in to comment.