From b011b3c1cf81b9ad962c31d816b0b0d91603f1cb Mon Sep 17 00:00:00 2001 From: Caspar Ockeloen-Korppi Date: Tue, 7 Nov 2023 07:07:32 +0000 Subject: [PATCH] Add MaskLayout.chip_copies dictionary 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 --- .../python/kqcircuits/masks/mask_export.py | 25 ++++-------- .../python/kqcircuits/masks/mask_layout.py | 40 +++++++++---------- 2 files changed, 27 insertions(+), 38 deletions(-) diff --git a/klayout_package/python/kqcircuits/masks/mask_export.py b/klayout_package/python/kqcircuits/masks/mask_export.py index ea7c102fc..9e9df6f11 100644 --- a/klayout_package/python/kqcircuits/masks/mask_export.py +++ b/klayout_package/python/kqcircuits/masks/mask_export.py @@ -21,7 +21,6 @@ import subprocess from importlib import import_module from math import pi -import csv from autologging import logged @@ -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: @@ -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: @@ -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)) @@ -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") @@ -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): @@ -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) @@ -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}" diff --git a/klayout_package/python/kqcircuits/masks/mask_layout.py b/klayout_package/python/kqcircuits/masks/mask_layout.py index 3bf1ea50a..7101df3c0 100644 --- a/klayout_package/python/kqcircuits/masks/mask_layout.py +++ b/klayout_package/python/kqcircuits/masks/mask_layout.py @@ -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. @@ -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] """ @@ -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 @@ -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}. " @@ -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"""