Source code for kqcircuits.elements.markers.marker

# This code is part of KQCircuits
# Copyright (C) 2021 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/iqm-open-source-trademark-policy). IQM welcomes contributions to the code.
# Please see our contribution agreements for individuals (meetiqm.com/iqm-individual-contributor-license-agreement)
# and organizations (meetiqm.com/iqm-organization-contributor-license-agreement).


from kqcircuits.pya_resolver import pya
from kqcircuits.util.parameters import Param, pdt
from kqcircuits.elements.element import Element
from kqcircuits.defaults import default_marker_type
import numpy as np


[docs] class Marker(Element): """Base Class for Markers.""" default_type = default_marker_type diagonal_squares = Param(pdt.TypeInt, "Number of diagonal squares in the marker", 10) window = Param(pdt.TypeBoolean, "Window in airbridge flyover layer", False)
[docs] @classmethod def create(cls, layout, library=None, marker_type=None, **parameters): """Create a Marker cell in layout.""" return cls.create_subtype(layout, library, marker_type, **parameters)[0]
[docs] def produce_geometry(self): """Produce common marker geometry.""" layer_gap = self.get_layer("base_metal_gap_wo_grid") layer_pads = self.get_layer("airbridge_pads") layer_flyover = self.get_layer("airbridge_flyover") layer_gap_for_ebl = self.get_layer("base_metal_gap_for_EBL") layer_protection = self.get_layer("ground_grid_avoidance") def insert_to_main_layers(shape): self.cell.shapes(layer_gap).insert(shape) self.cell.shapes(layer_gap_for_ebl).insert(shape) if not self.window: self.cell.shapes(layer_flyover).insert(shape) # protection for the box protection_box = pya.DBox(pya.DPoint(220, 220), pya.DPoint(-220, -220)) self.cell.shapes(layer_protection).insert(protection_box) # make corners corner = pya.DPolygon( [ pya.DPoint(100, 100), pya.DPoint(10, 100), pya.DPoint(10, 80), pya.DPoint(80, 80), pya.DPoint(80, 10), pya.DPoint(100, 10), ] ) inner_corners = [pya.DTrans(a) * corner for a in [0, 1, 2, 3]] outer_corners = [pya.DCplxTrans(2, a * 90.0, False, pya.DVector()) * corner for a in [0, 1, 2, 3]] corners = pya.Region([s.to_itype(self.layout.dbu) for s in inner_corners + outer_corners]) insert_to_main_layers(corners) # center box sqr_uni = pya.DBox( pya.DPoint(10, 10), pya.DPoint(-10, -10), ) insert_to_main_layers(sqr_uni) self.inv_corners = pya.Region(protection_box.to_itype(self.layout.dbu)) self.inv_corners -= corners self.cell.shapes(layer_pads).insert(self.inv_corners - pya.Region(sqr_uni.to_itype(self.layout.dbu))) # window for airbridge flyover layer aflw = pya.DPolygon( [ pya.DPoint(800, 800), pya.DPoint(800, 10), pya.DPoint(80, 10), pya.DPoint(80, 2), pya.DPoint(2, 2), pya.DPoint(2, 80), pya.DPoint(10, 80), pya.DPoint(10, 800), ] ) if self.window: for alpha in [0, 1, 2, 3]: self.cell.shapes(layer_flyover).insert(pya.DTrans(alpha) * aflw) # marker diagonal sqr = pya.DBox( pya.DPoint(10, 10), pya.DPoint(2, 2), ) self.diagonals = pya.Region() for i in range(5, 5 + self.diagonal_squares): ds = pya.DCplxTrans(3, 0, False, pya.DVector(50 * i - 3 * 6, 50 * i - 3 * 6)) * sqr insert_to_main_layers(ds) self.cell.shapes(layer_pads).insert(ds) self.diagonals += ds.to_itype(self.layout.dbu) self.cell.shapes(layer_protection).insert( pya.DCplxTrans(20, 0, False, pya.DVector(50 * i - 20 * 6, 50 * i - 20 * 6)) * sqr )
[docs] @classmethod def get_marker_locations(cls, cell_marker, **kwargs): """Locations in the wafer for this marker type. By default, places four markers at the corners as close as possible to the edge clearance. Implement this method for your own Marker subclass if you wish to have customized placement for your specific marker type. Args: cls - class that houses this class method cell_marker - Marker Cell kwargs - keyword arguments needed to determine the mask locations Returns: A list of placement encoded as DTrans objects that will transform the marker cells at their preferred location """ wafer_center_x = kwargs.get("wafer_center_x", 0) wafer_center_y = kwargs.get("wafer_center_y", 0) wafer_rad = kwargs.get("wafer_rad", 75000) edge_clearance = kwargs.get("edge_clearance", 1000) margin = kwargs.get("box_margin", 1000) _h = cell_marker.dbbox().height() _w = cell_marker.dbbox().width() coordinate = (wafer_rad - edge_clearance) / np.sqrt(2) return [ pya.DTrans(wafer_center_x - (coordinate - _w / 2 - margin), wafer_center_y - (coordinate - _h / 2 - margin)) * pya.DTrans.R180, pya.DTrans(wafer_center_x + (coordinate - _w / 2 - margin), wafer_center_y - (coordinate - _h / 2 - margin)) * pya.DTrans.R270, pya.DTrans(wafer_center_x - (coordinate - _w / 2 - margin), wafer_center_y + (coordinate - _h / 2 - margin)) * pya.DTrans.R90, pya.DTrans(wafer_center_x + (coordinate - _w / 2 - margin), wafer_center_y + (coordinate - _h / 2 - margin)) * pya.DTrans.R0, ]
[docs] @classmethod def get_marker_region(cls, inst, **kwargs): """The Region covered by the marker and surrounding area to be removed from the ground plane. By default, a box around the marker extended by the parameter box_margin. Implement this method for your own Marker subclass if you wish to have a different Region for your specific marker type. Args: cls - class that houses this class method inst - instance of the marker kwargs - keyword arguments possibly needed for the region Returns: pya.Region that can be used to subtract from the ground plane """ margin = kwargs.get("box_margin", 1000) return pya.Region(inst.bbox()).extents(margin / inst.cell.layout().dbu)