# -*- coding: utf-8 -*-
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Concentric Transmon, as shown in Phys. Rev. Appl. 10, 034050 (2018)."""
from math import sin, cos
import numpy as np
from qiskit_metal import draw, Dict
from qiskit_metal.qlibrary.core import BaseQubit
[docs]
class TransmonConcentricType2(BaseQubit):
""".. image::
TransmonConcentricType2.png
The base `TrasmonConcentric` class
Inherits `BaseQubit` class.
Metal transmon object consisting of a circle surrounding by a concentric
ring. There are two Josephson Junction connecting the circle to the ring;
one at the south end and one at the north end. There is a readout resonator.
.. TODO: add TransmonConcentricType2.png when available
.. meta::
:description: Transmon Concentric Type 2
BaseQubit Default Options:
* connection_pads: empty Dict -- the dictionary which contains all active
connection lines for the qubit.
* _default_connection_pads: empty Dict -- the default values for the
(if any) connection lines of the qubit.
Default Options:
* width: '1000um' -- Width of transmon pocket
* height: '1000um' -- Height of transmon pocket
* rad_o: '170um' -- Outer radius
* rad_i: '115um' -- Inner radius
* gap: '35um' -- Radius of gap between two pads
* jj_w: '10um' -- Josephson Junction width
* res_s: '100um' -- Space between top electrode and readout resonator
* res_ext: '100um' -- Extension of readout resonator in x-direction
beyond midpoint of transmon
* fbl_rad: '100um' -- Radius of the flux bias line loop
* fbl_sp: '100um' -- Spacing between metal pad and flux bias loop
* fbl_gap: '80um' -- Space between parallel lines of the flux bias loop
* fbl_ext: '300um' -- Run length of flux bias line between circular
loop and edge of pocket
* pocket_w: '1500um' -- Transmon pocket width
* pocket_h: '1000um' -- Transmon pocket height
* cpw_width: '10.0um' -- Width of the readout resonator and flux bias line
* layer: '1' -- default layer
"""
# default drawing options
default_options = Dict(
pos_x="0mm",
pos_y="0mm",
orientation="0",
rad_outer="2mm",
rad_inner="1mm",
gap="0.5mm",
jj_w="0.2mm",
finger_NE_width="0.1mm",
finger_NE_length="0.5mm",
coupler_NE_width="0.1mm",
coupler_NE_gap="0.1mm",
finger_NW_width="0.1mm",
finger_NW_length="0.5mm",
coupler_NW_width="0.1mm",
coupler_NW_gap="0.1mm",
finger_SW_width="0.1mm",
finger_SW_length="0.5mm",
coupler_SW_width="0.1mm",
coupler_SW_gap="0.1mm",
finger_E_width="0.1mm",
finger_E_length="0.5mm",
box_E_width="0.7mm",
box_E_length="0.7mm",
finger_N_width="0.1mm",
finger_N_length="2mm",
triangle_base="2mm",
triangle_height="1mm",
pocket_w="10mm",
pocket_h="10mm",
layer="1",
)
"""Default drawing options"""
[docs]
def make(self):
"""Convert self.options into QGeometry."""
p = self.parse_options() # Parse the string options into numbers
# draw the concentric pad regions
outer_pad = draw.Point(0, 0).buffer(p.rad_outer)
space = draw.Point(0, 0).buffer((p.gap + p.rad_inner))
cutout = draw.rectangle(
8.0 * p.finger_N_width,
p.finger_N_length,
0.0,
p.rad_inner + 0.5 * p.finger_N_length,
)
outer_pad = draw.subtract(outer_pad, space)
outer_pad = draw.subtract(outer_pad, cutout)
inner_pad = draw.Point(0, 0).buffer(p.rad_inner)
# draw the Josephson Junction
JJ = draw.LineString(
[
(
p.rad_inner * cos(45 * 3.14159 / 180),
-1.0 * p.rad_inner * sin(45 * 3.14159 / 180),
),
(
(p.rad_inner + p.gap) * cos(45 * 3.14159 / 180),
-1.0 * (p.rad_inner + p.gap) * sin(45 * 3.14159 / 180),
),
]
)
# draw the northeast finger
finger_NE = draw.LineString(
[
(
p.rad_outer * cos(45 * 3.14159 / 180),
p.rad_outer * sin(45 * 3.14159 / 180),
),
(
(p.rad_outer + p.finger_NE_length) * cos(45 * 3.14159 / 180),
(p.rad_outer + p.finger_NE_length) * sin(45 * 3.14159 / 180),
),
]
)
# draw the coupling resonator to the northeast finger
r = (
p.rad_outer
+ 0.5 * p.finger_NE_length
+ 0.5 * (0.5 * p.finger_NE_length + p.coupler_NE_gap + p.coupler_NE_width)
)
coupler_NE = draw.rectangle(
2.0 * p.coupler_NE_width + p.finger_NE_width + 2 * p.coupler_NE_gap,
0.5 * p.finger_NE_length + p.coupler_NE_gap + p.coupler_NE_width,
r * cos(45 * 3.14159 / 180),
r * sin(45 * 3.14159 / 180),
)
coupler_NE = draw.rotate(
coupler_NE,
-45,
origin=(r * cos(45 * 3.14159 / 180), r * sin(45 * 3.14159 / 180)),
)
l = (
p.rad_outer
+ 0.5 * p.finger_NE_length
+ 0.5 * (0.5 * p.finger_NE_length + p.coupler_NE_gap)
)
coupler_NE_cut = draw.rectangle(
p.finger_NE_width + 2.0 * p.coupler_NE_gap,
0.5 * p.finger_NE_length + p.coupler_NE_gap + 0.05 * p.finger_NE_length,
l * cos(45 * 3.145159 / 180),
l * sin(45 * 3.14159 / 180),
)
coupler_NE_cut = draw.rotate(
coupler_NE_cut,
-45,
origin=(l * cos(45 * 3.14159 / 180), l * sin(45 * 3.14159 / 180)),
)
coupler_NE = draw.subtract(coupler_NE, coupler_NE_cut)
# draw the northwest finger
finger_NW = draw.LineString(
[
(
-1.0 * p.rad_outer * cos(45 * 3.14159 / 180),
p.rad_outer * sin(45 * 3.14159 / 180),
),
(
-1.0 * (p.rad_outer + p.finger_NW_length) * cos(45 * 3.14159 / 180),
(p.rad_outer + p.finger_NW_length) * sin(45 * 3.14159 / 180),
),
]
)
# draw the coupling resonator to the northwest finger
r_nw = (
p.rad_outer
+ 0.5 * p.finger_NW_length
+ 0.5 * (0.5 * p.finger_NW_length + p.coupler_NW_gap + p.coupler_NW_width)
)
coupler_NW = draw.rectangle(
2.0 * p.coupler_NW_width + p.finger_NW_width + 2 * p.coupler_NW_gap,
0.5 * p.finger_NW_length + p.coupler_NW_gap + p.coupler_NW_width,
-1.0 * r_nw * cos(45 * 3.14159 / 180),
r_nw * sin(45 * 3.14159 / 180),
)
coupler_NW = draw.rotate(
coupler_NW,
45,
origin=(
-1.0 * r_nw * cos(45 * 3.14159 / 180),
r_nw * sin(45 * 3.14159 / 180),
),
)
l_nw = (
p.rad_outer
+ 0.5 * p.finger_NW_length
+ 0.5 * (0.5 * p.finger_NW_length + p.coupler_NW_gap)
)
coupler_NW_cut = draw.rectangle(
p.finger_NW_width + 2.0 * p.coupler_NW_gap,
0.5 * p.finger_NW_length + p.coupler_NW_gap + 0.05 * p.finger_NW_length,
-1.0 * l_nw * cos(45 * 3.145159 / 180),
l_nw * sin(45 * 3.14159 / 180),
)
coupler_NW_cut = draw.rotate(
coupler_NW_cut,
45,
origin=(
-1.0 * l_nw * cos(45 * 3.14159 / 180),
l_nw * sin(45 * 3.14159 / 180),
),
)
coupler_NW = draw.subtract(coupler_NW, coupler_NW_cut)
# draw the southwest finger
finger_SW = draw.LineString(
[
(
-1.0 * p.rad_outer * cos(45 * 3.14159 / 180),
-1.0 * p.rad_outer * sin(45 * 3.14159 / 180),
),
(
-1.0 * (p.rad_outer + p.finger_SW_length) * cos(45 * 3.14159 / 180),
-1.0 * (p.rad_outer + p.finger_SW_length) * sin(45 * 3.14159 / 180),
),
]
)
# draw the coupling resonator to the southwest finger
r_sw = (
p.rad_outer
+ 0.5 * p.finger_SW_length
+ 0.5 * (0.5 * p.finger_SW_length + p.coupler_SW_gap + p.coupler_SW_width)
)
coupler_SW = draw.rectangle(
2.0 * p.coupler_SW_width + p.finger_SW_width + 2 * p.coupler_SW_gap,
0.5 * p.finger_SW_length + p.coupler_SW_gap + p.coupler_SW_width,
-1.0 * r_sw * cos(45 * 3.14159 / 180),
-1.0 * r_sw * sin(45 * 3.14159 / 180),
)
coupler_SW = draw.rotate(
coupler_SW,
135,
origin=(
-1.0 * r_sw * cos(45 * 3.14159 / 180),
-1.0 * r_sw * sin(45 * 3.14159 / 180),
),
)
l_sw = (
p.rad_outer
+ 0.5 * p.finger_SW_length
+ 0.5 * (0.5 * p.finger_SW_length + p.coupler_SW_gap)
)
coupler_SW_cut = draw.rectangle(
p.finger_SW_width + 2.0 * p.coupler_SW_gap,
0.5 * p.finger_SW_length + p.coupler_SW_gap + 0.05 * p.finger_SW_length,
-1.0 * l_sw * cos(45 * 3.145159 / 180),
-1.0 * l_sw * sin(45 * 3.14159 / 180),
)
coupler_SW_cut = draw.rotate(
coupler_SW_cut,
135,
origin=(
-1.0 * l_sw * cos(45 * 3.14159 / 180),
-1.0 * l_sw * sin(45 * 3.14159 / 180),
),
)
coupler_SW = draw.subtract(coupler_SW, coupler_SW_cut)
# draw the east finger with the rectangular coupling pad
finger_E = draw.LineString(
[(-1.0 * p.rad_outer, 0.0), (-1.0 * (p.rad_outer + p.finger_E_length), 0.0)]
)
box = draw.rectangle(
p.box_E_width,
p.box_E_length,
-1.0 * (p.rad_outer + p.finger_E_length + 0.5 * p.box_E_width),
0.0,
)
# draw the north finger with the triangular coupling pad
finger_N = draw.LineString(
[(0.0, p.rad_inner), (0.0, p.rad_inner + p.finger_N_length)]
)
# draw the top triangular coupling pad
padtop_i = draw.rectangle(
p.triangle_base,
p.triangle_height,
0.0,
p.rad_inner + p.finger_N_length + 0.5 * p.triangle_height,
)
cut1 = draw.rotate(
padtop_i,
45,
origin=(
0.5 * p.triangle_base,
p.rad_inner + p.finger_N_length + p.triangle_height,
),
)
padtop = draw.subtract(padtop_i, cut1)
cut2 = draw.rotate(
padtop_i,
315,
origin=(
-0.5 * p.triangle_base,
p.rad_inner + p.finger_N_length + p.triangle_height,
),
)
padtop = draw.subtract(padtop, cut2)
padtop = draw.translate(padtop, 0.0, -0.05 * p.triangle_height)
# draw the transmon pocket bounding box
# pocket = draw.rectangle(p.pocket_w, p.pocket_h)
# Translate and rotate all shapes
objects = [
outer_pad,
inner_pad,
JJ,
finger_NE,
finger_NW,
finger_SW,
finger_E,
box,
finger_N,
padtop,
coupler_NE,
coupler_NW,
coupler_SW,
]
objects = draw.rotate(objects, p.orientation, origin=(0, 0))
objects = draw.translate(objects, xoff=p.pos_x, yoff=p.pos_y)
[
outer_pad,
inner_pad,
JJ,
finger_NE,
finger_NW,
finger_SW,
finger_E,
box,
finger_N,
padtop,
coupler_NE,
coupler_NW,
coupler_SW,
] = objects
##############################################################
# Use the geometry to create Metal QGeometry
geom_outer = {"poly1": outer_pad}
geom_inner = {"poly2": inner_pad}
geom_jj = {"poly3": JJ}
geom_finger_NE = {"finger_NE": finger_NE}
geom_finger_NW = {"finger_NW": finger_NW}
geom_finger_SW = {"finger_SW": finger_SW}
geom_finger_E = {"finger_E": finger_E}
geom_box_E = {"box_E": box}
geom_finger_N = {"finger_N": finger_N}
geom_pad_top = {"pad_top": padtop}
geom_coupler_NE = {"coupler_NE": coupler_NE}
geom_coupler_NW = {"coupler_NW": coupler_NW}
geom_coupler_SW = {"coupler_SW": coupler_SW}
self.add_qgeometry("poly", geom_outer, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_inner, layer=p.layer, subtract=False)
self.add_qgeometry(
"junction", geom_jj, layer=p.layer, subtract=False, width=p.jj_w
)
self.add_qgeometry(
"path",
geom_finger_NE,
layer=p.layer,
subtract=False,
width=p.finger_NE_width,
)
self.add_qgeometry(
"path",
geom_finger_NW,
layer=p.layer,
subtract=False,
width=p.finger_NW_width,
)
self.add_qgeometry(
"path",
geom_finger_SW,
layer=p.layer,
subtract=False,
width=p.finger_SW_width,
)
self.add_qgeometry(
"path", geom_finger_E, layer=p.layer, subtract=False, width=p.finger_E_width
)
self.add_qgeometry("poly", geom_box_E, layer=p.layer, subtract=False)
self.add_qgeometry(
"path", geom_finger_N, layer=p.layer, subtract=False, width=p.finger_N_width
)
self.add_qgeometry("poly", geom_pad_top, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_coupler_NE, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_coupler_NW, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_coupler_SW, layer=p.layer, subtract=False)
###########################################################################
# Add Qpin connections
# define a function that both rotates and translates the qpin coordinates
def qpin_rotate_translate(x):
y = list(x)
z = [0.0, 0.0]
z[0] = y[0] * cos(p.orientation * 3.14159 / 180) - y[1] * sin(
p.orientation * 3.14159 / 180
)
z[1] = y[0] * sin(p.orientation * 3.14159 / 180) + y[1] * cos(
p.orientation * 3.14159 / 180
)
z[0] = z[0] + p.pos_x
z[1] = z[1] + p.pos_y
x = (z[0], z[1])
return x
# Northeast coupler
qp1a_r = p.rad_outer + p.finger_NE_length + p.coupler_NE_gap
qp1a = (qp1a_r * cos(45 * 3.14159 / 180), qp1a_r * sin(45 * 3.14159 / 180))
qp1b_r = (
p.rad_outer + p.finger_NE_length + p.coupler_NE_gap + p.coupler_NE_width
)
qp1b = (qp1b_r * cos(45 * 3.14159 / 180), qp1b_r * sin(45 * 3.14159 / 180))
qp1a = qpin_rotate_translate(qp1a)
qp1b = qpin_rotate_translate(qp1b)
self.add_pin(
"pin1", points=np.array([qp1a, qp1b]), width=0.01, input_as_norm=True
)
# Northwest coupler
qp2a_r = p.rad_outer + p.finger_NW_length + p.coupler_NW_gap
qp2a = (
-1.0 * qp2a_r * cos(45 * 3.14159 / 180),
qp2a_r * sin(45 * 3.14159 / 180),
)
qp2b_r = (
p.rad_outer + p.finger_NW_length + p.coupler_NW_gap + p.coupler_NW_width
)
qp2b = (
-1.0 * qp2b_r * cos(45 * 3.14159 / 180),
qp2b_r * sin(45 * 3.14159 / 180),
)
qp2a = qpin_rotate_translate(qp2a)
qp2b = qpin_rotate_translate(qp2b)
self.add_pin(
"pin2", points=np.array([qp2a, qp2b]), width=0.01, input_as_norm=True
)
# Southwest coupler
qp3a_r = p.rad_outer + p.finger_SW_length + p.coupler_SW_gap
qp3a = (
-1.0 * qp3a_r * cos(45 * 3.14159 / 180),
-1.0 * qp3a_r * sin(45 * 3.14159 / 180),
)
qp3b_r = (
p.rad_outer + p.finger_SW_length + p.coupler_SW_gap + p.coupler_SW_width
)
qp3b = (
-1.0 * qp3b_r * cos(45 * 3.14159 / 180),
-1.0 * qp3b_r * sin(45 * 3.14159 / 180),
)
qp3a = qpin_rotate_translate(qp3a)
qp3b = qpin_rotate_translate(qp3b)
self.add_pin(
"pin3", points=np.array([qp3a, qp3b]), width=0.01, input_as_norm=True
)