Source code for kqcircuits.chips.shaping

# 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.chips.chip import Chip
from kqcircuits.util.parameters import Param, pdt
from kqcircuits.elements.meander import Meander
from kqcircuits.junctions.squid import Squid
from kqcircuits.qubits.swissmon import Swissmon
from kqcircuits.elements.waveguide_coplanar import WaveguideCoplanar
from kqcircuits.elements.waveguide_coplanar_splitter import WaveguideCoplanarSplitter, t_cross_parameters
from kqcircuits.util.coupler_lib import cap_params


[docs] class Shaping(Chip): """The PCell declaration for a Shaping chip.""" tunable = Param(pdt.TypeBoolean, "Tunable", False)
[docs] def build(self): # Launcher launchers = self.produce_launchers("SMA8") # Finnmon _, finnmon_refpoints_abs = self.insert_cell( Swissmon, pya.DTrans(3, False, 4000, 5000), arm_width=[30, 23, 30, 23], arm_length=[190, 96, 160, 96], gap_width=[29.5, 33, 29.5, 33], island_r=2, cpl_length=[235, 0, 205], cpl_width=[60, 42, 60], cpl_gap=[110, 112, 110], cl_offset=[150, 150], ) port_qubit_dr = finnmon_refpoints_abs["port_drive"] port_qubit_fl = finnmon_refpoints_abs["port_flux"] port_qubit_ro = finnmon_refpoints_abs["port_cplr0"] port_qubit_sh = finnmon_refpoints_abs["port_cplr2"] # Chargeline self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ launchers["WN"][0], launchers["WN"][0] + pya.DVector(self.r, 0), pya.DPoint((launchers["WN"][0] + pya.DVector(self.r, 0)).x, port_qubit_dr.y), port_qubit_dr - pya.DVector(self.r, 0), port_qubit_dr, ], 1, ), term2=self.b, ) # Fluxline self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ launchers["WS"][0], launchers["WS"][0] + pya.DVector(self.r, 0), pya.DPoint((launchers["WS"][0] + pya.DVector(self.r, 0)).x, port_qubit_fl.y), port_qubit_fl - pya.DVector(self.r, 0), port_qubit_fl, ], 1, ), ) ####### Readout resonator with the purcell filter segment_length_target_rr = [611.586, 1834.76, 611.586] # from qubit to shorted end segment_length_target_pr = [3158.32, 789.581] # from output to shorted end caps_fingers = [4, 4, 4] # J, kappa, drive caps_length = [37.5, 67.9, 36.2] # J, kappa, drive caps_type = ["gap", "interdigital", "gap"] # J, kappa, drive # Waveguide t-cross used in multiple locations cross1 = self.add_element( WaveguideCoplanarSplitter, **t_cross_parameters( a=self.a, b=self.b, a2=self.a, b2=self.b, length_extra_side=2 * self.a, length_extra=50 ), ) cross1_refpoints_rel = self.get_refpoints(cross1, pya.DTrans(0, False, 0, 0)) cross1_length = cross1_refpoints_rel["port_right"].distance(cross1_refpoints_rel["port_left"]) # Readout resonator first segment wg1_end = port_qubit_ro + pya.DVector(0, segment_length_target_rr[0] - cross1_length) self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_qubit_ro, port_qubit_ro + pya.DVector(0, self.r), wg1_end + pya.DVector(0, -self.r), wg1_end, ], 1, ), ) waveguide_length = cross1_length + cross1_refpoints_rel["base"].distance(cross1_refpoints_rel["port_bottom"]) _, cross1_refpoints_abs = self.insert_cell( cross1, pya.DTrans(1, False, wg1_end - pya.DTrans(1, False, 0, 0) * cross1_refpoints_rel["port_left"]) ) meander2_end = cross1_refpoints_abs["port_bottom"] + pya.DVector(630, 0) self.insert_cell( Meander, start_point=cross1_refpoints_abs["port_bottom"], end_point=meander2_end, length=segment_length_target_rr[1] - waveguide_length, meanders=2, ) cross2_refpoints_rel = self.get_refpoints(cross1, pya.DTrans(2, False, 0, 0)) port_rel_cross2_wg2 = cross2_refpoints_rel["port_right"] _, port_abs_cross2 = self.insert_cell(cross1, pya.DTrans(2, False, meander2_end - port_rel_cross2_wg2)) # Last bit of the readout resonator waveguide_length = cross1_refpoints_rel["base"].distance(cross1_refpoints_rel["port_bottom"]) self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_abs_cross2["port_bottom"], port_abs_cross2["port_bottom"] + pya.DVector(0, (segment_length_target_rr[2] - waveguide_length)), ], 1, ), ) # Capacitor J capj = self.add_element(**cap_params(caps_fingers[0], caps_length[0], caps_type[0])) port_rel_capj = self.get_refpoints(capj, pya.DTrans()) self.insert_cell(capj, pya.DTrans(port_abs_cross2["port_left"] - port_rel_capj["port_a"])) _, port_abs_cross3 = self.insert_cell( cross1, pya.DTrans( 2, False, port_abs_cross2["port_left"] - port_rel_capj["port_a"] + port_rel_capj["port_b"] - port_rel_cross2_wg2, ), ) waveguide_length = cross1_length meander3_end = port_abs_cross3["port_left"] + pya.DVector(900, 0) waveguide2 = self.add_element( WaveguideCoplanar, path=pya.DPath( [ meander3_end, meander3_end + pya.DVector(self.r, 0), meander3_end + pya.DVector(self.r, 400), meander3_end + pya.DVector(self.r, 400 + self.r), ], 1, ), ) self.insert_cell(waveguide2) waveguide_length += waveguide2.length() self.insert_cell( Meander, start_point=port_abs_cross3["port_left"], end_point=meander3_end, length=segment_length_target_pr[0] - waveguide_length, meanders=3, ) # Last bit of the Purcell filter of RR waveguide_length = cross1_refpoints_rel["base"].distance(cross1_refpoints_rel["port_bottom"]) wg6_end = port_abs_cross3["port_bottom"] + pya.DVector(0, (segment_length_target_pr[1] - waveguide_length)) self.insert_cell( WaveguideCoplanar, path=pya.DPath([port_abs_cross3["port_bottom"], wg6_end], 1), term2=(40 if self.tunable else 0), ) # Purcell resonator SQUID if self.tunable: # SQUID refpoint at the ground plane edge transf = pya.DTrans(2, False, wg6_end + pya.DVector(0, 40)) self.insert_cell(Squid, transf) self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ wg6_end + pya.DVector(-20, 40 + 15), wg6_end + pya.DVector(+20 + self.r, 40 + 15), pya.DPoint((wg6_end + pya.DVector(+20 + self.r, 40 + 15)).x, (launchers["NE"][0]).y - self.r), launchers["NE"][0] + pya.DVector(0, -self.r), launchers["NE"][0] + pya.DVector(0, 0), ], 1, ), ) # Capacitor Kappa capk = self.add_element(**cap_params(caps_fingers[1], caps_length[1], caps_type[1])) port_rel_capk = self.get_refpoints(capk, pya.DTrans(1, False, 0, 0)) _, port_abs_capk = self.insert_cell( capk, pya.DTrans(1, False, meander3_end + pya.DVector(self.r, 400 + self.r) - port_rel_capk["port_a"]) ) # Output port of the purcell resonator self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_abs_capk["port_b"], port_abs_capk["port_b"] + pya.DVector(0, self.r), pya.DPoint((port_abs_capk["port_b"] + pya.DVector(0, self.r)).x, launchers["EN"][0].y), launchers["EN"][0] + pya.DVector(-self.r, 0), launchers["EN"][0], ], 1, ), ) # Capacitor for the driveline capi = self.add_element(**cap_params(caps_fingers[2], caps_length[2], caps_type[2])) port_rel_capi = self.get_refpoints(capi, pya.DTrans(1, False, 0, 0)) _, port_abs_capi = self.insert_cell( capi, pya.DTrans(1, False, cross1_refpoints_abs["port_right"] - port_rel_capi["port_a"]) ) # Driveline of the readout resonator self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_abs_capi["port_b"], port_abs_capi["port_b"] + pya.DVector(0, self.r), pya.DPoint(launchers["NW"][0].x, (port_abs_capi["port_b"] + pya.DVector(0, self.r)).y), launchers["NW"][0] + pya.DVector(0, -self.r), launchers["NW"][0] + pya.DVector(0, 0), ], 1, ), ) ####### Shaping resonator with the purcell filter segment_length_target_rr = [634.71, 1904.13, 634.71] # from qubit to shorted end segment_length_target_pr = [3253.65, 813.413] # from output to shorted end caps_fingers = [4, 4, 4] # J, kappa, drive caps_length = [36.8, 71.5, 36.2] # J, kappa, drive caps_type = ["gap", "interdigital", "gap"] # J, kappa, drive # Readout resonator first segment wg1_end = port_qubit_sh + pya.DVector(0, -(segment_length_target_rr[0] - cross1_length)) self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_qubit_sh, port_qubit_sh + pya.DVector(0, -self.r), wg1_end + pya.DVector(0, +self.r), wg1_end, ], 1, ), ) waveguide_length = cross1_length + cross1_refpoints_rel["base"].distance(cross1_refpoints_rel["port_bottom"]) _, cross1_refpoints_abs = self.insert_cell( cross1, pya.DTrans(1, False, wg1_end - pya.DTrans(1, False, 0, 0) * cross1_refpoints_rel["port_right"]) ) meander2_end = cross1_refpoints_abs["port_bottom"] + pya.DVector(630, 0) self.insert_cell( Meander, start_point=cross1_refpoints_abs["port_bottom"], end_point=meander2_end, length=segment_length_target_rr[1] - waveguide_length, meanders=2, ) cross2_refpoints_rel = self.get_refpoints(cross1, pya.DTrans(0, False, 0, 0)) port_rel_cross2_wg2 = cross2_refpoints_rel["port_left"] _, port_abs_cross2 = self.insert_cell(cross1, pya.DTrans(0, False, meander2_end - port_rel_cross2_wg2)) # Last bit of the readout resonator waveguide_length = cross1_refpoints_rel["base"].distance(cross1_refpoints_rel["port_bottom"]) self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_abs_cross2["port_bottom"], port_abs_cross2["port_bottom"] + pya.DVector(0, -(segment_length_target_rr[2] - waveguide_length)), ], 1, ), ) # Capacitor J capj = self.add_element(**cap_params(caps_fingers[0], caps_length[0], caps_type[0])) port_rel_capj = self.get_refpoints(capj) self.insert_cell(capj, pya.DTrans(port_abs_cross2["port_right"] - port_rel_capj["port_a"])) _, port_abs_cross3 = self.insert_cell( cross1, pya.DTrans( 0, False, port_abs_cross2["port_right"] - port_rel_capj["port_a"] + port_rel_capj["port_b"] - port_rel_cross2_wg2, ), ) waveguide_length = cross1_length meander3_end = port_abs_cross3["port_right"] + pya.DVector(900, 0) self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ meander3_end, meander3_end + pya.DVector(self.r, 0), meander3_end + pya.DVector(self.r, -400), meander3_end + pya.DVector(self.r, -400 - self.r), ], 1, ), ) waveguide_length += waveguide2.length() self.insert_cell( Meander, start_point=port_abs_cross3["port_right"], end_point=meander3_end, length=segment_length_target_pr[0] - waveguide_length, meanders=3, ) # Last bit of the Purcell filter of shaping resonator waveguide_length = cross1_refpoints_rel["base"].distance(cross1_refpoints_rel["port_bottom"]) wg6_end = port_abs_cross3["port_bottom"] + pya.DVector(0, -(segment_length_target_pr[1] - waveguide_length)) self.insert_cell( WaveguideCoplanar, path=pya.DPath([port_abs_cross3["port_bottom"], wg6_end], 1), term2=(40 if self.tunable else 0), ) # Purcell resonator SQUID if self.tunable: # SQUID refpoint at the ground plane edge transf = pya.DTrans(0, False, wg6_end + pya.DVector(0, -40)) self.insert_cell(Squid, transf) self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ wg6_end + pya.DVector(-20, -40 - 15), wg6_end + pya.DVector(+20 + self.r, -40 - 15), pya.DPoint((wg6_end + pya.DVector(+20 + self.r, -40 - 15)).x, (launchers["SE"][0]).y + self.r), launchers["SE"][0] + pya.DVector(0, self.r), launchers["SE"][0] + pya.DVector(0, 0), ], 1, ), ) # Capacitor Kappa capk = self.add_element(**cap_params(caps_fingers[1], caps_length[1], caps_type[1])) port_rel_capk = self.get_refpoints(capk, pya.DTrans(3, False, 0, 0)) _, port_abs_capk = self.insert_cell( capk, pya.DTrans(3, False, meander3_end + pya.DVector(self.r, -400 - self.r) - port_rel_capk["port_a"]) ) # Output port of the purcell resonator self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_abs_capk["port_b"], port_abs_capk["port_b"] + pya.DVector(0, -self.r), pya.DPoint((port_abs_capk["port_b"] + pya.DVector(0, -self.r)).x, (launchers["ES"][0]).y), launchers["ES"][0] + pya.DVector(-self.r, 0), launchers["ES"][0] + pya.DVector(0, 0), ], 1, ), ) # Capacitor for the driveline capi = self.add_element(**cap_params(caps_fingers[2], caps_length[2], caps_type[2])) port_rel_capi = self.get_refpoints(capi, pya.DTrans(3, False, 0, 0)) _, port_abs_capi = self.insert_cell( capi, pya.DTrans(3, False, cross1_refpoints_abs["port_left"] - port_rel_capi["port_a"]) ) # Driveline of the shaping resonator self.insert_cell( WaveguideCoplanar, path=pya.DPath( [ port_abs_capi["port_b"], port_abs_capi["port_b"] + pya.DVector(0, -self.r), pya.DPoint(launchers["SW"][0].x, (port_abs_capi["port_b"] + pya.DVector(0, -self.r)).y), launchers["SW"][0] + pya.DVector(0, self.r), launchers["SW"][0] + pya.DVector(0, 0), ], 1, ), )