Source code for kqcircuits.simulations.epr.smooth_capacitor

# This code is part of KQCircuits
# Copyright (C) 2024 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.simulations.partition_region import PartitionRegion
from kqcircuits.simulations.epr.utils import in_gui, EPRTarget
from kqcircuits.elements.smooth_capacitor import SmoothCapacitor


# Partition region and correction cuts definitions for Swissmon qubit
vertical_dimension = 1.0
metal_edge_dimension = 2.0


[docs] def partition_regions(simulation: EPRTarget, prefix: str = "") -> list[PartitionRegion]: port_a_rf = simulation.refpoints["port_a"] port_b_rf = simulation.refpoints["port_b"] a2 = simulation.a if simulation.a2 < 0 else simulation.a2 b2 = simulation.b if simulation.b2 < 0 else simulation.b2 # Make a stub SmoothCapacitor instance, copy some attributes # then use some region generating functions to create a partition region shape overlapping finger edges s = SmoothCapacitor() s.n = simulation.n s.finger_width = simulation.finger_width s.finger_gap = simulation.finger_gap s.finger_control = simulation.finger_control s.ground_gap = simulation.ground_gap s.layout = simulation.layout right_fingers, left_fingers = s.get_finger_regions() region_ground = right_fingers + left_fingers region_ground += s.middle_gap_fill().sized(-simulation.ground_gap / simulation.layout.dbu, 5) fingers = ( s.super_smoothen_region(region_ground, simulation.finger_gap + simulation.ground_gap) .sized(-(simulation.finger_width / 2.0) / simulation.layout.dbu, 5) .transformed(pya.DTrans(0, False, simulation.refpoints["base"]).to_itype(simulation.layout.dbu)) ) result = [] if not in_gui(simulation): port_a_len = 11 + simulation.waveguide_length + metal_edge_dimension # 11 is the hardcoded port dimension port_a_width = simulation.a + 2 * simulation.b + 2 * metal_edge_dimension port_a_middle = port_a_rf - pya.DPoint(port_a_len / 2.0, 0) port_a_dp = pya.DPoint(port_a_len / 2.0, port_a_width / 2) port_b_len = 11 + simulation.waveguide_length + metal_edge_dimension # 11 is the hardcoded port dimension port_b_width = a2 + 2 * b2 + 2 * metal_edge_dimension port_b_middle = port_b_rf + pya.DPoint(port_b_len / 2.0, 0) port_b_dp = pya.DPoint(port_b_len / 2.0, port_b_width / 2) if simulation.use_internal_ports: port_a_region = pya.DBox(port_a_middle - port_a_dp, port_a_middle + port_a_dp) port_b_region = pya.DBox(port_b_middle - port_b_dp, port_b_middle + port_b_dp) else: port_a_dpx_edge = pya.DPoint(-simulation.box.width() / 2.0, 0.0) port_a_dpy = pya.DPoint(0.0, port_a_width / 2) port_a_middley = pya.DPoint(0, port_a_middle.y) port_a_region = pya.DBox(port_a_dpx_edge + port_a_middley - port_a_dpy, port_a_middle + port_a_dp) port_b_dpx_edge = pya.DPoint(simulation.box.width(), 0.0) port_b_dpy = pya.DPoint(0.0, port_b_width / 2) port_b_middley = pya.DPoint(0, port_b_middle.y) port_b_region = pya.DBox(port_b_middle - port_b_dp, port_b_dpx_edge + port_b_middley + port_b_dpy) result += [ PartitionRegion( name=f"{prefix}port_bmer", face=simulation.face_ids[0], metal_edge_dimensions=metal_edge_dimension, region=port_b_region, vertical_dimensions=vertical_dimension, visualise=True, ), PartitionRegion( name=f"{prefix}port_bbulk", face=simulation.face_ids[0], metal_edge_dimensions=None, region=port_b_region, vertical_dimensions=vertical_dimension, visualise=True, ), PartitionRegion( name=f"{prefix}port_amer", face=simulation.face_ids[0], metal_edge_dimensions=metal_edge_dimension, region=port_a_region, vertical_dimensions=vertical_dimension, visualise=True, ), PartitionRegion( name=f"{prefix}port_abulk", face=simulation.face_ids[0], metal_edge_dimensions=None, region=port_a_region, vertical_dimensions=vertical_dimension, visualise=True, ), ] result += [ PartitionRegion( name=f"{prefix}fingersmer", face=simulation.face_ids[0], metal_edge_dimensions=metal_edge_dimension, region=fingers, vertical_dimensions=vertical_dimension, visualise=True, ), PartitionRegion( name=f"{prefix}fingersbulk", face=simulation.face_ids[0], metal_edge_dimensions=None, region=fingers, vertical_dimensions=vertical_dimension, visualise=True, ), PartitionRegion( name=f"{prefix}bcomplementmer", face=simulation.face_ids[0], metal_edge_dimensions=metal_edge_dimension, region=None, vertical_dimensions=vertical_dimension, visualise=True, ), PartitionRegion( name=f"{prefix}bcomplementbulk", face=simulation.face_ids[0], region=None, vertical_dimensions=vertical_dimension, visualise=True, ), ] if in_gui(simulation): make_t_regions = True else: make_t_regions = len(simulation.face_stack) > 1 if make_t_regions: result += [ PartitionRegion( name=f"{prefix}tcomplementmer", face=simulation.face_ids[1], metal_edge_dimensions=metal_edge_dimension, region=None, vertical_dimensions=vertical_dimension, visualise=True, ), PartitionRegion( name=f"{prefix}tcomplementbulk", face=simulation.face_ids[1], region=None, vertical_dimensions=vertical_dimension, visualise=True, ), ] return result
[docs] def correction_cuts(simulation: EPRTarget, prefix: str = "") -> dict[str, dict]: base_rf = simulation.refpoints["base"] port_a_rf = simulation.refpoints["port_a"] port_b_rf = simulation.refpoints["port_b"] a2 = simulation.a if simulation.a2 < 0 else simulation.a2 b2 = simulation.b if simulation.b2 < 0 else simulation.b2 gaps = pya.Region(simulation.cell.begin_shapes_rec(simulation.get_layer("base_metal_gap_wo_grid"))) finger_top = None finger_center = None for polygon in gaps.each(): for edge in polygon.to_dtype(simulation.layout.dbu).each_edge(): # Hole edges are oriented counterclockwise while hull edges are oriented clockwise. # Rely on this orientation to get top point of fingers. if edge.d().x < 0.0 and (finger_top is None or edge.p1.y > finger_top.y): finger_top = edge.p1 k = edge.d().sprod(base_rf - edge.p1) / edge.d().sq_abs() nearest = (edge.p1 if k <= 0.0 else (edge.p2 if k >= 1.0 else edge.p1 + k * edge.d())) - base_rf if finger_center is None or nearest.abs() < finger_center.abs(): if simulation.finger_control > 1.0 or abs(nearest.y) < abs(nearest.x): finger_center = nearest z_me = 0 if not in_gui(simulation): port_a_len = 11 + simulation.waveguide_length + metal_edge_dimension # 11 is the hardcoded port dimension port_a_middle = port_a_rf - pya.DPoint(port_a_len / 2.0, 0) port_a_width = simulation.a + 2 * simulation.b + 2 * metal_edge_dimension port_b_len = 11 + simulation.waveguide_length + metal_edge_dimension # 11 is the hardcoded port dimension port_b_middle = port_b_rf + pya.DPoint(port_b_len / 2.0, 0) port_b_width = a2 + 2 * b2 + 2 * metal_edge_dimension if len(simulation.face_stack) > 1: z_me = -simulation.substrate_height[1] - simulation.chip_distance - 2 * simulation.metal_height fingersmer_end = finger_center * (1.0 + simulation.finger_width * 0.9 / finger_center.abs()) half_cut_len = 25.0 result = { f"{prefix}fingersmer": { "p1": base_rf + fingersmer_end, "p2": base_rf - fingersmer_end, "metal_edges": [ {"x": simulation.finger_width * 0.9, "z": z_me}, {"x": 2 * fingersmer_end.abs() - simulation.finger_width * 0.9, "z": z_me}, ], }, f"{prefix}bcomplementmer": { "p1": finger_top + pya.DVector(0, simulation.ground_gap + half_cut_len), "p2": finger_top - pya.DVector(0, simulation.finger_width * 0.9), "metal_edges": [ {"x": half_cut_len, "z": z_me}, {"x": half_cut_len + simulation.ground_gap, "z": z_me}, ], }, } if not in_gui(simulation): result[f"{prefix}port_amer"] = { "p1": port_a_middle - pya.DPoint(0, port_a_width), "p2": port_a_middle + pya.DPoint(0, port_a_width), "metal_edges": [ { "x": port_a_width - simulation.a / 2.0 - simulation.b, "z": z_me, }, { "x": port_a_width - simulation.a / 2.0, "z": z_me, }, { "x": port_a_width + simulation.a / 2.0, "z": z_me, }, { "x": port_a_width + simulation.a / 2.0 + simulation.b, "z": z_me, }, ], } result[f"{prefix}port_bmer"] = { "p1": port_b_middle - pya.DPoint(0, port_b_width), "p2": port_b_middle + pya.DPoint(0, port_b_width), "metal_edges": [ {"x": port_b_width - a2 / 2 - b2, "z": z_me}, {"x": port_b_width - a2 / 2, "z": z_me}, {"x": port_b_width + a2 / 2, "z": z_me}, {"x": port_b_width + a2 / 2 + b2, "z": z_me}, ], } return result