Source code for kqcircuits.chips.xmons_direct_coupling

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


import math

from kqcircuits.chips.chip import Chip
from kqcircuits.qubits.qubit import Qubit
from kqcircuits.qubits.swissmon import Swissmon
from kqcircuits.elements.waveguide_composite import WaveguideComposite, Node
from kqcircuits.elements.waveguide_coplanar_taper import WaveguideCoplanarTaper
from kqcircuits.elements.waveguide_coplanar_splitter import WaveguideCoplanarSplitter, t_cross_parameters
from kqcircuits.pya_resolver import pya
from kqcircuits.util.coupler_lib import cap_params
from kqcircuits.util.parameters import Param, pdt, add_parameters_from


[docs] @add_parameters_from(Qubit, "junction_type", "fluxline_type") class XMonsDirectCoupling(Chip): """The PCell declaration for an XMonsDirectCoupling chip.""" qubit_spacing = Param(pdt.TypeDouble, "Qubit spacing", 10, unit="μm") arm_width_a = Param(pdt.TypeDouble, "Qubit 1 and 3 arm width", 24, unit="μm") arm_width_b = Param(pdt.TypeDouble, "Qubit 2 arm width", 24, unit="μm") rr_cpl_width = Param(pdt.TypeList, "RR to QB coupler width (um for each RR)", [24, 24, 24])
[docs] def produce_readout_resonator(self, pos_start, end_y, length, name, c_kappa_l_fingers): # 86 ohms ro_a = 5 ro_b = 20 taper_length = 100 # T to PL _, pl_cross_ref = self.insert_cell( WaveguideCoplanarSplitter, pya.DTrans(pos_start.x, end_y), inst_name=(f"PL{name}" if name else None), label_trans=pya.DTrans.R90, **t_cross_parameters(a=self.a, b=self.b, a2=self.a, b2=self.b, length_extra_side=20, length_extra=0), ) # Finger cap cplr_cell = self.add_element(**cap_params(4, c_kappa_l_fingers, "interdigital")) cplr_ref_rel = self.get_refpoints(cplr_cell, pya.DTrans.R90) _, cplr_ref = self.insert_cell( cplr_cell, pya.DTrans(pl_cross_ref["port_bottom"] - cplr_ref_rel["port_b"]) * pya.DTrans.R90 ) # Taper to T taper_cell, taper_ref_rel = WaveguideCoplanarTaper.create_with_refpoints( self.layout, self.LIBRARY_NAME, pya.DTrans.R90, a=ro_a, b=ro_b, a2=self.a, b2=self.b, taper_length=taper_length, ) _, taper_ref = self.insert_cell( taper_cell, pya.DTrans(cplr_ref["port_a"] - taper_ref_rel["port_b"]) * pya.DTrans.R90 ) # T to tail and straight rr_cross_cell = self.add_element( WaveguideCoplanarSplitter, **t_cross_parameters( length_extra_side=40, length_extra=0, a=ro_a, b=ro_b, a2=ro_a, b2=ro_b, ), ) rr_cross_ref_rel = self.get_refpoints(rr_cross_cell, pya.DTrans.R90) _, rr_cross_ref = self.insert_cell( rr_cross_cell, pya.DTrans(taper_ref["port_a"] - rr_cross_ref_rel["port_right"]) * pya.DTrans.R90 ) # straight self.insert_cell( WaveguideComposite, nodes=[ Node(rr_cross_ref["port_left"]), Node(pos_start, n_bridges=10), ], a=ro_a, b=ro_b, ) # tail non_tail_length = (rr_cross_ref["base"] - pos_start).length() tail_r = 100 tail_v = pya.DVector( 0, -( length - non_tail_length # straight down - (rr_cross_ref["base"] - rr_cross_ref["port_bottom"]).length() # t-piece - math.pi / 2 * tail_r # curve + tail_r # vertical offset for the straight part with fixed length ), ) self.insert_cell( WaveguideComposite, nodes=[ Node(rr_cross_ref["port_bottom"]), Node(rr_cross_ref["port_bottom_corner"]), Node(rr_cross_ref["port_bottom_corner"] + tail_v, n_bridges=5), ], a=ro_a, b=ro_b, r=tail_r, )
[docs] def produce_qubits(self): """A dedicated function to be used also by the corresponding simulation object. Assumes following attributes: * arm_width_a * arm_width_b * qubit_spacing * fluxline_type * rr_cpl_width * junction_type * layout * insert_cell """ # Finnmon arm_length = 146 qubit_props_common = { "arm_length": [arm_length] * 4, "island_r": 2, "port_width": [10, 5, 10], } arm_width_a = self.arm_width_a arm_width_b = self.arm_width_b full_gap_width = 72 qb1_coupler_width, qb2_coupler_width, qb3_coupler_width = [float(param) for param in self.rr_cpl_width] finnmon_1 = self.add_element( Swissmon, arm_width=[arm_width_a] * 4, gap_width=[(full_gap_width - arm_width_a) / 2] * 4, cpl_gap=[110, 90, 110], cpl_length=[0, 134 + qb1_coupler_width, 0], cpl_width=[60, qb1_coupler_width, 60], cl_offset=[150, -150], **qubit_props_common, ) finnmon_2 = self.add_element( Swissmon, arm_width=[arm_width_b] * 4, gap_width=[(full_gap_width - arm_width_b) / 2] * 4, cpl_gap=[110, 102, 110], cpl_length=[0, 116 + qb2_coupler_width, 0], cpl_width=[60, qb2_coupler_width, 60], cl_offset=[150, 150], **qubit_props_common, ) finnmon_3 = self.add_element( Swissmon, arm_width=[arm_width_a] * 4, gap_width=[(full_gap_width - arm_width_a) / 2] * 4, cpl_gap=[110, 90, 110], cpl_length=[0, 134 + qb3_coupler_width, 0], cpl_width=[60, qb3_coupler_width, 60], cl_offset=[-150, -150], **qubit_props_common, ) qubit_y = 5e3 qubit_step = ((full_gap_width - arm_width_a) / 2 + (full_gap_width - arm_width_b) / 2) + 2 * arm_length self.insert_cell( finnmon_1, trans=pya.DTrans(5e3 - qubit_step - self.qubit_spacing, qubit_y), inst_name="QB1", label_trans=pya.DTrans.R90, rec_levels=None, ) self.insert_cell( finnmon_2, trans=pya.DTrans(5e3, qubit_y), inst_name="QB2", label_trans=pya.DTrans.R90, rec_levels=None ) self.insert_cell( finnmon_3, trans=pya.DTrans(5e3 + qubit_step + self.qubit_spacing, qubit_y), inst_name="QB3", label_trans=pya.DTrans.R90, rec_levels=None, )
[docs] def build(self): self.produce_launchers("SMA8") self.produce_junction_tests(junction_type=self.junction_type) self.produce_qubits() # Readout resonators height_rr_feedline = 7.9e3 # target parameters V2 self.produce_readout_resonator( self.refpoints["QB1_port_cplr1"], height_rr_feedline, 2421.5 + 2447.1, name="1", c_kappa_l_fingers=60.8 ) self.produce_readout_resonator( self.refpoints["QB2_port_cplr1"], height_rr_feedline, 2436 + 2246.3, name="2", c_kappa_l_fingers=61.55 ) self.produce_readout_resonator( self.refpoints["QB3_port_cplr1"], height_rr_feedline, 2438.5 + 2248.2, name="3", c_kappa_l_fingers=58.1 ) # PL input cap pl_in_cap_cell = self.add_element(**cap_params(8, 55.4)) # 35 fF pl_in_cap_ref_rel = self.get_refpoints(pl_in_cap_cell) pl_in_cap_trans = pya.DTrans( pya.DPoint(self.refpoints["QB1_port_cplr1"].x - 300, height_rr_feedline) - pl_in_cap_ref_rel["port_b"] ) self.insert_cell(pl_in_cap_cell, pl_in_cap_trans, inst_name="IN") # Transmission lines tl_gap = 300 # RR feedline self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["NW_port"]), Node((self.refpoints["NW_port"].x, height_rr_feedline)), Node(self.refpoints["IN_port_a"], n_bridges=3), ], ) self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["IN_port_b"]), Node(self.refpoints["PL1_port_left"], n_bridges=1), ], ) self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["PL1_port_right"]), Node(self.refpoints["PL2_port_left"], n_bridges=1), ], ) self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["PL2_port_right"]), Node(self.refpoints["PL3_port_left"], n_bridges=1), ], ) self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["PL3_port_right"]), Node((self.refpoints["NE_port"].x, height_rr_feedline), n_bridges=4), Node(self.refpoints["NE_port"]), ], ) # Qb1 driveline self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["WN_port"]), Node((self.refpoints["NW_port"].x - tl_gap, self.refpoints["WN_port"].y)), Node(self.refpoints["QB1_port_drive"], n_bridges=25), ], term2=self.b, ) # Qb1 fluxline self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["WS_port"]), Node(self.refpoints["WS_port_corner"]), Node(self.refpoints["QB1_port_flux_corner"], n_bridges=30), Node(self.refpoints["QB1_port_flux"]), ], ) # Qb2 driveline self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["SW_port"]), Node((self.refpoints["SW_port"].x, self.refpoints["WS_port"].y - tl_gap)), Node(self.refpoints["QB2_port_drive"] + pya.DPoint(0, -3 * self.r), n_bridges=30), Node(self.refpoints["QB2_port_drive"]), ], term2=self.b, ) # Qb2 fluxline self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["SE_port"]), Node((self.refpoints["SE_port"].x, self.refpoints["ES_port"].y - tl_gap)), Node(self.refpoints["QB2_port_flux_corner"], n_bridges=30), Node(self.refpoints["QB2_port_flux"]), ], ) # Qb3 driveline self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["EN_port"]), Node((self.refpoints["NE_port"].x + tl_gap, self.refpoints["EN_port"].y)), Node(self.refpoints["QB3_port_drive"], n_bridges=25), ], term2=self.b, ) # Qb3 fluxline self.insert_cell( WaveguideComposite, nodes=[ Node(self.refpoints["ES_port"]), Node(self.refpoints["ES_port_corner"]), Node(self.refpoints["QB3_port_flux_corner"], n_bridges=30), Node(self.refpoints["QB3_port_flux"]), ], )