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"""