# -*- 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.
"""Lumped Resonator, 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 QComponent
[docs]
class ResonatorLumped(QComponent):
"""
The base ResonatorLumped class
Inherits the QComponent class
.. TODO: add resonator_lumped.png once asset is available for docs
.. meta::
:description: Lumped Resonator
Default Options:
* pos_x: '0um' -- x-coordinate of the bottom center of the resonator
* pos_y: '0um' -- y-coordinate of the bottom center of the resonator
* orientation: '0' -- angle of rotation of the resonator
* box_width: '5mm' -- the width of the rectangular resonator structure
* box_height: '5mm' -- the height of the rectangular resonator structure
* perimeter_thicknes: '0.01mm' -- the width of the resonator along the perimeter
* res_width: '0.01m' -- the width of the resonator
* initial: '0.1m' -- the length of the lower straight resonator segment
* n_turns: '10' -- the number of turns in the curved resonator segment
* turn_radius: '0.1mm' - the radius of the turns in the curved resonator segment
* inner_space: '0.1mm' - the space between the curved resonator
* outer_space: '0.1mm' -- the space between rectangular and curved resonator turns
* final: '2.5mm' -- the length of the upper straight segment of the resonator
* break_width: '0.2mm' -- the width of the "break" in the top of the rectangular resonator
* layer: '1' -- the layer of the component
"""
default_options = Dict(
pos_x="0 um",
pos_y="0 um",
orientation="0",
box_width="5mm",
box_height="5mm",
perimeter_thickness="0.01mm",
res_width="0.01mm",
initial="0.1mm",
n_turns="10",
turn_radius="0.1mm",
inner_space="0.1mm",
outer_space="0.1mm",
final="2.5mm",
break_width="0.2mm",
layer="1",
)
##########################
[docs]
def make(self):
"""Builds the component."""
"""Convert self.options into QGeometry."""
p = self.parse_options() # Parse the string options into numbers
# draw the perimeter
box_out = draw.rectangle(p.box_width, p.box_height, 0.0, 0.0)
box_in = draw.rectangle(
p.box_width - 2.0 * p.perimeter_thickness,
p.box_height - 2.0 * p.perimeter_thickness,
0.0,
0.0,
)
perimeter = draw.subtract(box_out, box_in)
perimeter = draw.translate(perimeter, xoff=0.0, yoff=0.5 * p.box_height)
break_rect = draw.rectangle(p.break_width, p.break_width, 0.0, p.box_height)
perimeter = draw.subtract(perimeter, break_rect)
# start the resonator
initial = draw.LineString(
[(0.0, p.perimeter_thickness), (0.0, p.perimeter_thickness + p.initial)]
)
# Draw the first quarter turn
centerx, centery = -1.0 * p.turn_radius, p.perimeter_thickness + p.initial
radius = p.turn_radius
start_angle, end_angle = 0, 90 # In degrees
numsegments = 1000
# The coordinates of the arc
theta = np.radians(np.linspace(start_angle, end_angle, numsegments))
x = centerx + radius * np.cos(theta)
y = centery + radius * np.sin(theta)
arc = draw.LineString(np.column_stack([x, y]))
# Draw the first half-turn (left); this gets repeated
centerx2 = -0.5 * p.box_width + p.outer_space + p.turn_radius
centery2 = p.perimeter_thickness + p.initial + 2.0 * p.turn_radius
radius2 = p.turn_radius
start_angle2, end_angle2 = 270, 90 # In degrees
numsegments2 = 1000
# The coordinates of the arc
theta2 = np.radians(np.linspace(start_angle2, end_angle2, numsegments2))
x2 = centerx2 + radius2 * np.cos(theta2)
y2 = centery2 + radius2 * np.sin(theta2)
arc_left_1 = draw.LineString(np.column_stack([x2, y2]))
# Draw the first half-turn (right); this gets repeated
centerx3 = 0.5 * p.box_width - p.outer_space - p.turn_radius
centery3 = p.perimeter_thickness + p.initial + 4.0 * p.turn_radius
radius3 = p.turn_radius
start_angle3, end_angle3 = 90, -90 # In degrees
numsegments3 = 1000
# The coordinates of the arc
theta3 = np.radians(np.linspace(start_angle3, end_angle3, numsegments3))
x3 = centerx3 + radius3 * np.cos(theta3)
y3 = centery3 + radius3 * np.sin(theta3)
arc_right_1 = draw.LineString(np.column_stack([x3, y3]))
# bottom half-line
line1 = draw.LineString(
[
(
-1.0 * p.turn_radius - 0.0 * p.res_width,
p.perimeter_thickness + p.initial + p.turn_radius,
),
(
-0.5 * p.box_width + p.outer_space + p.turn_radius,
p.perimeter_thickness + p.initial + p.turn_radius,
),
]
)
# bottom full-line (this one gets repeated)
line2 = draw.LineString(
[
(
-0.5 * p.box_width + p.outer_space + p.turn_radius,
p.initial + 3.0 * p.turn_radius + p.res_width,
),
(
0.5 * p.box_width - p.outer_space - p.turn_radius,
p.initial + 3.0 * p.turn_radius + p.res_width,
),
]
)
# repeat the full fline
line3 = draw.translate(line2, 0.0, 2.0 * p.turn_radius)
line4 = draw.translate(line3, 0.0, 2.0 * p.turn_radius)
line5 = draw.translate(line4, 0.0, 2.0 * p.turn_radius)
line6 = draw.translate(line5, 0.0, 2.0 * p.turn_radius)
line7 = draw.translate(line6, 0.0, 2.0 * p.turn_radius)
line8 = draw.translate(line7, 0.0, 2.0 * p.turn_radius)
line9 = draw.translate(line8, 0.0, 2.0 * p.turn_radius)
line10 = draw.translate(line9, 0.0, 2.0 * p.turn_radius)
line11 = draw.translate(line10, 0.0, 2.0 * p.turn_radius)
line12 = draw.translate(line11, 0.0, 2.0 * p.turn_radius)
line13 = draw.translate(line12, 0.0, 2.0 * p.turn_radius)
line14 = draw.translate(line13, 0.0, 2.0 * p.turn_radius)
# hard code the position for now; make it adjustable later
line_last = draw.translate(
line1,
0.5 * p.box_width - 0.0 * p.turn_radius - p.outer_space,
28 * p.turn_radius,
)
# draw the line exiting the rectangle
final = draw.LineString(
[
(0.0, p.perimeter_thickness + p.initial + 30.0 * p.turn_radius),
(
0.0,
p.perimeter_thickness + p.initial + 30.0 * p.turn_radius + p.final,
),
]
)
arc_last = draw.rotate(
arc,
180,
origin=(0.0, p.perimeter_thickness + p.initial + 1.5 * p.turn_radius),
)
arc_last = draw.translate(arc_last, 0.0, p.initial + 26 * p.turn_radius)
# repeat the left turns
arc_left_2 = draw.translate(arc_left_1, 0.0, 4.0 * p.turn_radius)
arc_left_3 = draw.translate(arc_left_2, 0.0, 4.0 * p.turn_radius)
arc_left_4 = draw.translate(arc_left_3, 0.0, 4.0 * p.turn_radius)
arc_left_5 = draw.translate(arc_left_4, 0.0, 4.0 * p.turn_radius)
arc_left_6 = draw.translate(arc_left_5, 0.0, 4.0 * p.turn_radius)
arc_left_7 = draw.translate(arc_left_6, 0.0, 4.0 * p.turn_radius)
# repeat the right turns
arc_right_2 = draw.translate(arc_right_1, 0.0, 4.0 * p.turn_radius)
arc_right_3 = draw.translate(arc_right_2, 0.0, 4.0 * p.turn_radius)
arc_right_4 = draw.translate(arc_right_3, 0.0, 4.0 * p.turn_radius)
arc_right_5 = draw.translate(arc_right_4, 0.0, 4.0 * p.turn_radius)
arc_right_6 = draw.translate(arc_right_5, 0.0, 4.0 * p.turn_radius)
arc_right_7 = draw.translate(arc_right_6, 0.0, 4.0 * p.turn_radius)
# Translate and rotate all shapes
objects = [
perimeter,
initial,
arc,
arc_left_1,
arc_left_2,
arc_left_3,
arc_left_4,
arc_left_5,
arc_left_6,
arc_left_7,
arc_right_1,
arc_right_2,
arc_right_2,
arc_right_3,
arc_right_4,
arc_right_4,
arc_right_5,
arc_right_6,
arc_right_7,
arc_last,
final,
line1,
line2,
line3,
line4,
line5,
line6,
line7,
line8,
line9,
line10,
line11,
line12,
line13,
line14,
line_last,
]
# first translate so that the origin is at the middle of the loop
objects = draw.translate(objects, 0.0, -0.5 * p.box_height)
# now translate and rotate according to the values specified in the dictionary
objects = draw.rotate(objects, p.orientation, origin=(0, 0))
objects = draw.translate(objects, xoff=p.pos_x, yoff=p.pos_y)
[
perimeter,
initial,
arc,
arc_left_1,
arc_left_2,
arc_left_3,
arc_left_4,
arc_left_5,
arc_left_6,
arc_left_7,
arc_right_1,
arc_right_2,
arc_right_2,
arc_right_3,
arc_right_4,
arc_right_4,
arc_right_5,
arc_right_6,
arc_right_7,
arc_last,
final,
line1,
line2,
line3,
line4,
line5,
line6,
line7,
line8,
line9,
line10,
line11,
line12,
line13,
line14,
line_last,
] = objects
# give polys names for qgeometry
geom_perimeter = {"poly1": perimeter}
geom_initial = {"poly2": initial}
geom_arc = {"poly3": arc}
geom_arc_left_1 = {"poly4": arc_left_1}
geom_arc_left_2 = {"poly4": arc_left_2}
geom_arc_left_3 = {"poly4": arc_left_3}
geom_arc_left_4 = {"poly4": arc_left_4}
geom_arc_left_5 = {"poly4": arc_left_5}
geom_arc_left_6 = {"poly4": arc_left_6}
geom_arc_left_7 = {"poly4": arc_left_7}
geom_arc_right_1 = {"poly4": arc_right_1}
geom_arc_right_2 = {"poly4": arc_right_2}
geom_arc_right_3 = {"poly4": arc_right_3}
geom_arc_right_4 = {"poly4": arc_right_4}
geom_arc_right_5 = {"poly4": arc_right_5}
geom_arc_right_6 = {"poly4": arc_right_6}
geom_arc_right_7 = {"poly4": arc_right_7}
geom_arc_last = {"poly4": arc_last}
geom_final = {"poly": final}
geom_line1 = {"poly5": line1}
geom_line2 = {"poly6": line2}
geom_line3 = {"poly7": line3}
geom_line4 = {"poly8": line4}
geom_line5 = {"poly9": line5}
geom_line6 = {"poly10": line6}
geom_line7 = {"poly11": line7}
geom_line8 = {"poly11": line8}
geom_line9 = {"poly9": line9}
geom_line10 = {"poly10": line10}
geom_line11 = {"poly11": line11}
geom_line12 = {"poly12": line12}
geom_line13 = {"poly13": line13}
geom_line14 = {"poly14": line14}
geom_line_last = {"poly14": line_last}
# add to qgeometry
self.add_qgeometry("poly", geom_perimeter, layer=p.layer, subtract=False)
self.add_qgeometry(
"path", geom_initial, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_left_1, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_left_2, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_left_3, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_left_4, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_left_5, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_left_6, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_left_7, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_right_1, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_right_2, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_right_3, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_right_4, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_right_5, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_right_6, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_right_7, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_arc_last, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line1, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line2, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line3, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line4, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line5, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line6, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line7, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line8, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line9, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line10, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line11, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line12, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line13, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line14, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_line_last, layer=p.layer, subtract=False, width=p.res_width
)
self.add_qgeometry(
"path", geom_final, layer=p.layer, subtract=False, width=p.res_width
)
##########################
# 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
# East pin
qp1a = (0.5 * p.box_width - p.perimeter_thickness, 0.0)
qp1b = (0.5 * p.box_width, 0.0)
qp1a = qpin_rotate_translate(qp1a)
qp1b = qpin_rotate_translate(qp1b)
self.add_pin(
"pin_east", points=np.array([qp1a, qp1b]), width=0.01, input_as_norm=True
)
# North-East pin
qpa_ne = (
0.5 * p.box_width - p.perimeter_thickness,
0.5 * p.box_height - p.perimeter_thickness,
)
qpb_ne = (0.5 * p.box_width, 0.5 * p.box_height)
qpa_ne = qpin_rotate_translate(qpa_ne)
qpb_ne = qpin_rotate_translate(qpb_ne)
self.add_pin(
"pin_ne", points=np.array([qpa_ne, qpb_ne]), width=0.01, input_as_norm=True
)
# South-East pin
qpa_se = (
0.5 * p.box_width - p.perimeter_thickness,
-0.5 * p.box_height + p.perimeter_thickness,
)
qpb_se = (0.5 * p.box_width, -0.5 * p.box_height)
qpa_se = qpin_rotate_translate(qpa_se)
qpb_se = qpin_rotate_translate(qpb_se)
self.add_pin(
"pin_se", points=np.array([qpa_se, qpb_se]), width=0.01, input_as_norm=True
)
# North-West pin
qpa_nw = (
-0.5 * p.box_width + p.perimeter_thickness,
0.5 * p.box_height - p.perimeter_thickness,
)
qpb_nw = (-0.5 * p.box_width, 0.5 * p.box_height)
qpa_nw = qpin_rotate_translate(qpa_nw)
qpb_nw = qpin_rotate_translate(qpb_nw)
self.add_pin(
"pin_nw", points=np.array([qpa_nw, qpb_nw]), width=0.01, input_as_norm=True
)
# West pin
qp2a = (-0.5 * p.box_width + p.perimeter_thickness, 0.0)
qp2b = (-0.5 * p.box_width, 0.0)
qp2a = qpin_rotate_translate(qp2a)
qp2b = qpin_rotate_translate(qp2b)
self.add_pin(
"pin_west", points=np.array([qp2a, qp2b]), width=0.01, input_as_norm=True
)
# South-West pin
qpa_sw = (
-0.5 * p.box_width + p.perimeter_thickness,
-0.5 * p.box_height + p.perimeter_thickness,
)
qpb_sw = (-0.5 * p.box_width, -0.5 * p.box_height)
qpa_sw = qpin_rotate_translate(qpa_sw)
qpb_sw = qpin_rotate_translate(qpb_sw)
self.add_pin(
"pin_sw", points=np.array([qpa_sw, qpb_sw]), width=0.01, input_as_norm=True
)
# South pin
qpa_s = (0.0, -0.5 * p.box_height + p.perimeter_thickness)
qpb_s = (0.0, -0.5 * p.box_height)
qpa_s = qpin_rotate_translate(qpa_s)
qpb_s = qpin_rotate_translate(qpb_s)
self.add_pin(
"pin_s", points=np.array([qpa_s, qpb_s]), width=0.01, input_as_norm=True
)
# north pin
qpa_n = (
0.0,
-0.5 * p.box_height
+ p.perimeter_thickness
+ p.initial
+ 30.0 * p.turn_radius,
)
qpb_n = (
0.0,
-0.5 * p.box_height
+ p.perimeter_thickness
+ p.initial
+ 30.0 * p.turn_radius
+ p.final,
)
qpa_n = qpin_rotate_translate(qpa_n)
qpb_n = qpin_rotate_translate(qpb_n)
self.add_pin(
"pin_n", points=np.array([qpa_n, qpb_n]), width=0.01, input_as_norm=True
)