# 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)