Source code for kqcircuits.simulations.epr.circular_transmon_single_island

# This code is part of KQCircuits
# Copyright (C) 2025 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).

import math
from kqcircuits.pya_resolver import pya
from kqcircuits.simulations.epr.util import create_bulk_and_mer_partition_regions


[docs] def partition_regions(simulation): """Returns list of PartitionRegion objects for Circular Transmon Single Island EPR simulation.""" regions = [] # Coupler partition regions - one for each coupler for i, (c_angle, c_arc_ampl) in enumerate(zip(simulation.couplers_angle, simulation.couplers_arc_amplitude)): # Create pizza slice shape for each coupler c_angle_rad = math.radians(float(c_angle)) c_arc_ampl_rad = math.radians(float(c_arc_ampl)) # Inner radius (closer to qubit center, with some margin) inner_radius = simulation.r_island - 10 # Outer radius (extends beyond coupler, with extra space) outer_radius = simulation.r_island + simulation.ground_gap + 20 # Angular extent with extra margin half_angle = c_arc_ampl_rad / 2 + math.radians(10) # Extra 10 degrees on each side # Create pizza slice polygon without center point to avoid zero width lines points = [] # Add arc points for outer edge n_points = 32 for j in range(n_points + 1): angle = c_angle_rad - half_angle + (2 * half_angle * j) / n_points x = outer_radius * math.cos(angle) y = outer_radius * math.sin(angle) points.append(pya.DPoint(x, y) + simulation.refpoints["base"]) # Add arc points for inner edge (reverse direction) for j in range(n_points, -1, -1): angle = c_angle_rad - half_angle + (2 * half_angle * j) / n_points x = inner_radius * math.cos(angle) y = inner_radius * math.sin(angle) points.append(pya.DPoint(x, y) + simulation.refpoints["base"]) coupler_region = pya.DPolygon(points) regions += create_bulk_and_mer_partition_regions( name=f"{i}cplr", face=simulation.face_ids[0], metal_edge_dimensions=2.0, region=coupler_region, vertical_dimensions=3.0, bulk=False, visualise=True, ) # Junction hall partition region squid_angle_rad = math.radians(simulation.squid_angle) hall_length = simulation.ground_gap + 10 # Extra space hall_width = 8 + 4 # Junction hall width + extra space # Create rotated rectangle for junction hall hall_rect = pya.DPolygon( [ pya.DPoint(-hall_width / 2, 0), pya.DPoint(hall_width / 2, 0), pya.DPoint(hall_width / 2, hall_length), pya.DPoint(-hall_width / 2, hall_length), ] ) # Position at island edge and rotate junction_pos = pya.DPoint( simulation.r_island * math.cos(squid_angle_rad), simulation.r_island * math.sin(squid_angle_rad) ) hall_transform = pya.DCplxTrans(1, simulation.squid_angle - 90, False, junction_pos + simulation.refpoints["base"]) hall_region = hall_transform * hall_rect regions += create_bulk_and_mer_partition_regions( name="leads", face=simulation.face_ids[0], metal_edge_dimensions=2.0, region=hall_region, vertical_dimensions=3.0, bulk=False, visualise=True, ) # Main island complement region regions += create_bulk_and_mer_partition_regions( name="bcomplement", face=simulation.face_ids[0], metal_edge_dimensions=2.0, region=None, vertical_dimensions=3.0, bulk=False, visualise=True, ) return regions
[docs] def correction_cuts(simulation): """Returns dictionary of correction cuts for Circular Transmon Single Island EPR simulation.""" cuts = {} # Coupler correction cuts for i, (c_angle, c_arc_ampl) in enumerate(zip(simulation.couplers_angle, simulation.couplers_arc_amplitude)): c_angle_rad = math.radians(float(c_angle)) c_arc_ampl_rad = math.radians(float(c_arc_ampl)) # Cut outside the hall and cross the coupler slightly on the side # mid angle between current cut position and coupler arc amplitude half_arc = c_arc_ampl_rad / 2 cut_angle_offset = half_arc / 2 # Halfway between center and arc edge cut_angle = c_angle_rad + cut_angle_offset # Offset to the side # Cut from outside qubit through coupler to island center # Start outside the qubit outer_point = pya.DPoint( (simulation.r_island + simulation.ground_gap + 15) * math.cos(cut_angle), (simulation.r_island + simulation.ground_gap + 15) * math.sin(cut_angle), ) # End at island edge inner_point = pya.DPoint( (simulation.r_island - 10) * math.cos(cut_angle), (simulation.r_island - 10) * math.sin(cut_angle) ) cuts[f"{i}cplrmer"] = { "p1": outer_point + simulation.refpoints["base"], "p2": inner_point + simulation.refpoints["base"], } # Junction hall correction cut squid_angle_rad = math.radians(simulation.squid_angle) # Cut across the width of junction hall hall_center = pya.DPoint( (simulation.r_island + simulation.ground_gap / 2) * math.cos(squid_angle_rad), (simulation.r_island + simulation.ground_gap / 2) * math.sin(squid_angle_rad), ) # Perpendicular direction to junction hall perp_angle = squid_angle_rad + math.pi / 2 cut_length = 15 p1 = pya.DPoint( hall_center.x + cut_length * math.cos(perp_angle), hall_center.y + cut_length * math.sin(perp_angle) ) p2 = pya.DPoint( hall_center.x - cut_length * math.cos(perp_angle), hall_center.y - cut_length * math.sin(perp_angle) ) cuts["leadsmer"] = { "p1": p1 + simulation.refpoints["base"], "p2": p2 + simulation.refpoints["base"], "boundary_conditions": {"xmin": {"potential": 0}, "xmax": {"potential": 0}}, } # Main island complement correction cut # direction that avoids couplers and junction # angle opposite to junction complement_angle = math.radians(simulation.squid_angle + 180) # Check if this angle conflicts with any coupler min_angular_distance = 360 for c_angle in simulation.couplers_angle: angular_dist = abs(float(c_angle) - (simulation.squid_angle + 180)) if angular_dist > 180: angular_dist = 360 - angular_dist min_angular_distance = min(min_angular_distance, angular_dist) # Close to the coupler if min_angular_distance < 30: # Less than 30 degrees separation complement_angle = math.radians(simulation.squid_angle + 150) # Cut from island to outside qubit # points equidistant from the gap region gap_distance = 10 # Same distance from gap as outer point inner_point = pya.DPoint( (simulation.r_island - gap_distance) * math.cos(complement_angle), (simulation.r_island - gap_distance) * math.sin(complement_angle), ) outer_point = pya.DPoint( (simulation.r_island + simulation.ground_gap + gap_distance) * math.cos(complement_angle), (simulation.r_island + simulation.ground_gap + gap_distance) * math.sin(complement_angle), ) cuts["bcomplementmer"] = { "p1": inner_point + simulation.refpoints["base"], "p2": outer_point + simulation.refpoints["base"], } return cuts