# -*- 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.
"""Tunable Coupler, as shown in Phys. Rev. Research 2, 033447 (2020)."""
from math import sin, cos
import numpy as np
from qiskit_metal import draw, Dict
from qiskit_metal.qlibrary.core import BaseQubit
[docs]
class TunableCoupler02(BaseQubit):
"""One of the tunable couplers
.. TODO: add apidocs/TunableCoupler02.png once available
.. meta::
:description: Tunable Coupler 2
BaseQubit Default Options:
* connection_pads: empty Dict -- Currently not used, connection count is static. (WIP)
Default Options:
* pocket_width: '3mm' -- The width (x-axis) of the transmon pocket
* pocket_height: '2m' -- The height (y-axis) of the transmon pocket
* pos_x: '0mm' -- the x-coordinate location of the JJ in the middle of the qubit
* pos_y: '0mm' -- the y-coordinate location of the JJ in the middle of the qubit
* orientation: '0' -- the angle of rotation
* pad_radius: '0.3mm' -- the radius of the two circular pads on either side of the JJ
* bus_width: '0.1mm' -- the width of the CPW resonator in the coupler
* bus_inner_length: '0.5mm' -- length of the CPW between the JJ and the circular pad
* bus_outer_length: '0.5mm' -- length of the CPW between the circular pad and the in/out pin
* bus_JJ_height: '0.5mm' -- vertical distance between the main cpw line and the offset JJ
* JJ_width: '0.1mm' -- the width of the JJ
* JJ_length: '0.4mm' -- the length of the JJ
* fbl_width: '0.1mm' -- the width of the flux bias line drawn near the JJ
* fbl_length: '0.5mm' -- the length of the flux bias line drawn near the JJ
* fbl_offset: '0.1mm' -- the lateral offset between the flux bias line and the JJ
* layer: '1' -- the default design layer
"""
default_options = Dict(
pocket_width="3mm",
pocket_height="2mm",
pos_x="0mm",
pos_y="0mm",
orientation="0",
pad_radius="0.3mm",
bus_width="0.1mm",
bus_inner_length="0.5mm",
bus_outer_length="0.5mm",
bus_JJ_height="0.5mm",
JJ_width="0.1mm",
JJ_length="0.4mm",
fbl_width="0.1mm",
fbl_length="0.5mm",
fbl_offset="0.1mm",
layer="1",
)
component_metadata = Dict(
short_name="Pocket",
_qgeometry_table_path="True",
_qgeometry_table_poly="True",
_qgeometry_table_junction="True",
)
TOOLTIP = """One of the tunable couplers"""
[docs]
def make(self):
"""Builds the component."""
"""Convert self.options into QGeometry."""
p = self.parse_options() # Parse the string options into numbers
# draw the Josephson Junction
JJ = draw.LineString(
[
(-0.5 * p.JJ_length, p.bus_JJ_height - 0.5 * p.JJ_width),
(0.5 * p.JJ_length, p.bus_JJ_height - 0.5 * p.JJ_width),
]
)
# draw the individual components of the CPW resonator
bus_vertical_left = draw.rectangle(
p.bus_width,
p.bus_JJ_height,
-0.5 * p.JJ_length - 0.5 * p.bus_width,
0.5 * p.bus_JJ_height,
)
bus_vertical_right = draw.rectangle(
p.bus_width,
p.bus_JJ_height,
0.5 * p.JJ_length + 0.5 * p.bus_width,
0.5 * p.bus_JJ_height,
)
bus_left = draw.rectangle(
p.bus_inner_length + p.bus_outer_length + 2.0 * p.pad_radius,
p.bus_width,
-0.5 * p.JJ_length
- p.bus_width
- 0.5 * (p.bus_inner_length + p.bus_outer_length + 2.0 * p.pad_radius),
0.5 * p.bus_width,
)
bus_right = draw.rectangle(
p.bus_inner_length + p.bus_outer_length + 2.0 * p.pad_radius,
p.bus_width,
0.5 * p.JJ_length
+ p.bus_width
+ 0.5 * (p.bus_inner_length + p.bus_outer_length + 2.0 * p.pad_radius),
0.5 * p.bus_width,
)
# draw the circular charge pads
left_pad = draw.Point(
-0.5 * p.JJ_length - p.bus_width - p.bus_inner_length - 0.5 * p.pad_radius,
0.5 * p.bus_width,
).buffer(p.pad_radius)
right_pad = draw.Point(
0.5 * p.JJ_length + p.bus_width + p.bus_inner_length + 0.5 * p.pad_radius,
0.5 * p.bus_width,
).buffer(p.pad_radius)
# draw the flux bias line
fbl = draw.rectangle(
p.fbl_width,
p.fbl_length,
-0.5 * p.JJ_length - p.bus_width - p.fbl_offset - 0.5 * p.fbl_width,
p.bus_JJ_height + 0.5 * p.fbl_length,
)
# draw the pocket surrounding the qubit
pocket = draw.rectangle(0.0, 0.0, p.pocket_width, p.pocket_height)
# Translate and rotate all shapes
objects = [
JJ,
bus_vertical_left,
bus_vertical_right,
bus_left,
bus_right,
left_pad,
right_pad,
fbl,
pocket,
]
objects = draw.rotate(objects, p.orientation, origin=(0, 0))
objects = draw.translate(objects, xoff=p.pos_x, yoff=p.pos_y)
[
JJ,
bus_vertical_left,
bus_vertical_right,
bus_left,
bus_right,
left_pad,
right_pad,
fbl,
pocket,
] = objects
# give each poly a name to send to qgeometry
geom_jj = {"poly1": JJ}
geom_bus_vertical_left = {"poly2": bus_vertical_left}
geom_bus_vertical_right = {"poly3": bus_vertical_right}
geom_bus_left = {"poly4": bus_left}
geom_bus_right = {"poly5": bus_right}
geom_left_pad = {"poly6": left_pad}
geom_right_pad = {"poly7": right_pad}
geom_fbl = {"poly8": fbl}
# geom_pocket = {'poly9': pocket}
# add to qgeometry
self.add_qgeometry(
"junction", geom_jj, layer=p.layer, subtract=False, width=p.JJ_width
)
self.add_qgeometry(
"poly", geom_bus_vertical_left, layer=p.layer, subtract=False
)
self.add_qgeometry(
"poly", geom_bus_vertical_right, layer=p.layer, subtract=False
)
self.add_qgeometry("poly", geom_bus_left, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_bus_right, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_left_pad, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_right_pad, layer=p.layer, subtract=False)
self.add_qgeometry("poly", geom_fbl, layer=p.layer, subtract=False)
# self.add_qgeometry('poly', geom_pocket, layer=1, subtract=True)
###########################################################################
# 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
# Right-hand pin
qp1b = (
0.5 * p.JJ_length
+ p.bus_width
+ p.bus_inner_length
+ p.bus_outer_length
+ 2.0 * p.pad_radius,
0.5 * p.bus_width,
)
qp1a = (
0.5 * p.JJ_length
+ p.bus_width
+ 0.9 * p.bus_inner_length
+ p.bus_outer_length
+ 2.0 * p.pad_radius,
0.5 * p.bus_width,
)
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
)
# Left-hand pin
qp2b = (
-0.5 * p.JJ_length
- p.bus_width
- p.bus_inner_length
- p.bus_outer_length
- 2.0 * p.pad_radius,
0.5 * p.bus_width,
)
qp2a = (
-0.5 * p.JJ_length
- p.bus_width
- 0.9 * p.bus_inner_length
- p.bus_outer_length
- 2.0 * p.pad_radius,
0.5 * p.bus_width,
)
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
)
# Flux Bias Line pin
qp3b = (
-0.5 * p.JJ_length - p.bus_width - p.fbl_offset - 0.5 * p.fbl_width,
p.bus_JJ_height + p.fbl_length,
)
qp3a = (
-0.5 * p.JJ_length - p.bus_width - p.fbl_offset - 0.5 * p.fbl_width,
p.bus_JJ_height + 0.9 * p.fbl_length,
)
qp3a = qpin_rotate_translate(qp3a)
qp3b = qpin_rotate_translate(qp3b)
self.add_pin(
"fbl", points=np.array([qp3a, qp3b]), width=0.01, input_as_norm=True
)