# 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.simulation import Simulation
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: Simulation, 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
rr = simulation.finger_width / 2 + simulation.ground_gap
rr /= simulation.layout.dbu
# Use modified SmoothCapacitor geometry to obtain partition regions on fingers
trans = pya.DTrans(0, False, simulation.box.center()).to_itype(simulation.layout.dbu)
tmp_layout = pya.Layout()
tmp_cell = SmoothCapacitor.create(
tmp_layout,
margin=-simulation.ground_gap - simulation.finger_width / 2,
fixed_length=0,
finger_control=simulation.finger_control,
)
box_rounded = pya.Region(tmp_cell.begin_shapes_rec(simulation.get_layer("ground_grid_avoidance"))).transformed(
trans
)
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_a_region = pya.DBox(port_a_middle - port_a_dp, port_a_middle + port_a_dp)
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)
port_b_region = pya.DBox(port_b_middle - port_b_dp, port_b_middle + port_b_dp)
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,
),
PartitionRegion(
name=f"{prefix}fingersmer",
face=simulation.face_ids[0],
metal_edge_dimensions=metal_edge_dimension,
region=box_rounded,
vertical_dimensions=vertical_dimension,
visualise=True,
),
PartitionRegion(
name=f"{prefix}fingersbulk",
face=simulation.face_ids[0],
metal_edge_dimensions=None,
region=box_rounded,
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 len(simulation.face_stack) > 1:
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: Simulation, 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
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 = 0
else:
z_me = -simulation.substrate_height[1] - simulation.chip_distance - 2 * simulation.metal_height
scale = simulation.finger_width + simulation.finger_gap
half_cut_len = 25.0
result = {
f"{prefix}fingersmer": {
"p1": base_rf + pya.DPoint(0, -scale / 2),
"p2": base_rf + pya.DPoint(0, scale / 2),
"metal_edges": [
{"x": (scale - simulation.finger_gap) / 2, "z": z_me},
{"x": (scale + simulation.finger_gap) / 2, "z": z_me},
],
},
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,
},
],
},
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},
],
},
f"{prefix}bcomplementmer": {
"p1": port_a_rf + pya.DPoint(-half_cut_len, simulation.a + simulation.b),
"p2": port_a_rf + pya.DPoint(half_cut_len, simulation.a + simulation.b),
"metal_edges": [
{"x": half_cut_len, "z": z_me},
],
},
}
return result