Note
This page was generated from tut/2-From-components-to-chip/2.32-Create-a-QComponent-Advanced.ipynb.
2.32 Create a QComponent - Advanced¶
[1]:
from qiskit_metal import draw, Dict
from qiskit_metal.toolbox_metal import math_and_overrides
from qiskit_metal.qlibrary.core import QComponent
import qiskit_metal as metal
[2]:
design = metal.designs.DesignPlanar()
Qubits and Junctions¶
The vast majority of junction management is actually under the QRenderers. The only information that a component designer needs to provide, is a linestring and width which indicates the location and orientation of a given junction. We can see this from a couple extracted lines of code from TransmonPocket
...
rect_jj = draw.LineString([(0, -pad_gap / 2), (0, +pad_gap / 2)])
...
self.add_qgeometry('junction', dict(rect_jj=rect_jj), width=p.inductor_width)
In this case, the linestring is drawn between the two charge islands of the TransmonPocket. Much more of the junctions options are from renderer options added when the QRenderers are initiated. These are covered more in the renderer tutorials and sessions.
It should be noted, currently multiple junctions in a component will receive the same renderer options. This is fine if, say, making a symmetric SQUID, though if trying to have asymmetry, (or, say fluxonium), a manner to handled multiple junction renderer options in a component is required.
[3]:
from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket
?TransmonPocket
Init signature:
TransmonPocket(
design,
name: str = None,
options: addict.addict.Dict = None,
options_connection_pads: dict = None,
make: bool = True,
**kwargs,
)
Docstring:
The base `TransmonPocket` class.
Inherits `BaseQubit` class.
Create a standard pocket transmon qubit for a ground plane,
with two pads connected by a junction (see drawing below).
Connector lines can be added using the `connection_pads`
dictionary. Each connector pad has a name and a list of default
properties.
Sketch:
Below is a sketch of the qubit
::
+1 +1
________________________________
-1 |______ ____ __________| +1 Y
| |____| |____| | ^
| __________________ | |
| | island | | |-----> X
| |__________________| |
| | |
| pocket x |
| _________|________ |
| | | |
| |__________________| |
| ______ |
|_______|______| |
-1 |________________________________| +1
-1 -1
.. image::
TransmonPocket.png
.. meta::
:description: Transmon Pocket
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:
* pad_gap: '30um' -- The distance between the two charge islands, which is also the resulting 'length' of the pseudo junction
* inductor_width: '20um' -- Width of the pseudo junction between the two charge islands (if in doubt, make the same as pad_gap). Really just for simulating in HFSS / other EM software
* pad_width: '455um' -- The width (x-axis) of the charge island pads
* pad_height: '90um' -- The size (y-axis) of the charge island pads
* pocket_width: '650um' -- Size of the pocket (cut out in ground) along x-axis
* pocket_height: '650um' -- Size of the pocket (cut out in ground) along y-axis
* _default_connection_pads: Dict
* pad_gap: '15um' -- Space between the connector pad and the charge island it is nearest to
* pad_width: '125um' -- Width (x-axis) of the connector pad
* pad_height: '30um' -- Height (y-axis) of the connector pad
* pad_cpw_shift: '5um' -- Shift the connector pad cpw line by this much away from qubit
* pad_cpw_extent: '25um' -- Shift the connector pad cpw line by this much away from qubit
* cpw_width: 'cpw_width' -- Center trace width of the CPW line
* cpw_gap: 'cpw_gap' -- Dielectric gap width of the CPW line
* cpw_extend: '100um' -- Depth the connector line extense into ground (past the pocket edge)
* pocket_extent: '5um' -- How deep into the pocket should we penetrate with the cpw connector (into the fround plane)
* pocket_rise: '65um' -- How far up or downrelative to the center of the transmon should we elevate the cpw connection point on the ground plane
* loc_W: '+1' -- Width location only +-1
* loc_H: '+1' -- Height location only +-1
Init docstring:
Args:
design (QDesign): The parent design.
name (str): Name of the component.
options (dict): User options that will override the defaults. Defaults to None.
options_connection_pads(dict): User options for connection pads on qubit
make (bool): True if the make function should be called at the end of the init.
Options be used in the make function to create the geometry. Defaults to None.
File: ~/CODE_REPOS/quantum_hardware/qiskit-metal/src/qiskit_metal/qlibrary/qubits/transmon_pocket.py
Type: type
Subclasses:
Exteriors, Interiors, and MultiPolygons¶
As was shown in 3.1, there is a great amount of flexibility already present in Metal for what a component can be, though as it is still in development, there are some limitations with respect to if renderers can accurately render a given shape, say, a multi-faceted polygon where some facets are composed of splines. What capabilities are currently missing and would be beneficial to be added are all part of the development process.
Currently, a poly can be generated with interior cut outs, such as the smiley face previously,
[4]:
face = draw.shapely.geometry.Point(0, 0).buffer(1)
eye = draw.shapely.geometry.Point(0, 0).buffer(0.2)
eye_l = draw.translate(eye, -0.4, 0.4)
eye_r = draw.translate(eye, 0.4, 0.4)
smile = draw.shapely.geometry.Point(0, 0).buffer(0.8)
cut_sq = draw.shapely.geometry.box(-1, -0.3, 1, 1)
smile = draw.subtract(smile, cut_sq)
face = draw.subtract(face, smile)
face = draw.subtract(face, eye_r)
face = draw.subtract(face, eye_l)
face
[4]:
This differs from qgeometries which have subtract=True, as that specifically sets that geometry to be “etched” from the ground plane. The polygon face is composed of an exterior;
[5]:
face.exterior
[5]:
and interiors, such as;
[6]:
face.interiors[0]
[6]:
A renderer must recognize the difference between these shapes, as the current QRenderers do. This allows for the component designer to generate complex shapes, without having to worry about how to add the qgeometries in any particular manner. This is also true with MultiPolygons.
[7]:
big_square = draw.rectangle(10, 10, 0, 0)
cut_rectangle = draw.rectangle(12, 1, 0, 0)
multi_poly = draw.subtract(big_square, cut_rectangle)
multi_poly
[7]:
[8]:
type(multi_poly)
[8]:
shapely.geometry.multipolygon.MultiPolygon
The MultiPolygon can still just be passed to add_qgeometry as one would with a regular polygon. It is broken up behind the scenes so two separate rectangles (with the appropriate coordinates) are added to the poly qgeometry table. This is handled by the add_qgeometry method of QGeometryTables.
[9]:
?metal.qgeometries.QGeometryTables.add_qgeometry
Signature:
metal.qgeometries.QGeometryTables.add_qgeometry(
self,
kind: str,
component_name: str,
geometry: dict,
subtract: bool = False,
helper: bool = False,
layer: Union[int, str] = 1,
chip: str = 'main',
**other_options,
)
Docstring:
Main interface to add qgeometries.
Args:
kind (str): Must be in get_element_types ('path', 'poly', etc.).
component_name (str): Component name.
geometry (dict): Dict of shapely geometry.
subtract (bool): Subtract - passed through. Defaults to False.
helper (bool): Helper - passed through. Defaults to False.
layer (Union[int, str]): Layer - passed through. Defaults to 1.
chip (str): Chip name - passed through. Defaults to 'main'.
**other_options (object): Other_options - passed through.
File: ~/CODE_REPOS/quantum_hardware/qiskit-metal/src/qiskit_metal/qgeometries/qgeometries_handler.py
Type: function
This method also handles rounding of coordinates to try and avoid any numerical errors. It is called by metal.qlibrary.core.QComponent.add_qgeometry and should not be called directly.
QComponent Inheritance¶
As is the case with python classes, one can extend a given component by creating a qcomponent which inherits said class, making it a parent/child relationship. While python does support multiple inheritances, Metal may run into some bugs, so it is best to keep inheritances as single paths of heritage.
A good example is TransmonPocketCL, which adds a “charge line” the a “standard” TransmonPocket. As can be seen in the below code, none of the charge islands or other connection pads are present, but will still be generated via the super().make() line in the make() method.
[ ]:
import numpy as np
from qiskit_metal import draw, Dict
from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket
class TransmonPocketCL(TransmonPocket):
"""
The base `TransmonPocketCL` class
Inherits `TransmonPocket` class
Description:
Create a standard pocket transmon qubit for a ground plane,
with two pads connected by a junction (see drawing below).
Connector lines can be added using the `connection_pads`
dictionary. Each connector line has a name and a list of default
properties.
This is a child of TransmonPocket, see TransmonPocket for the variables and
description of that class.
::
_________________
| |
|_______________| ^
________x________ | N
| | |
|_______________|
.. image::
Component_Qubit_Transmon_Pocket_CL.png
Charge Line:
* make_CL (bool): If a chargeline should be included.
* cl_gap (string): The cpw dielectric gap of the charge line.
* cl_width (string): The cpw width of the charge line.
* cl_length (string): The length of the charge line 'arm' coupling the the qubit pocket.
Measured from the base of the 90 degree bend.
* cl_ground_gap (string): How much ground is present between the charge line and the
qubit pocket.
* cl_pocket_edge (string): What side of the pocket the charge line is.
-180 to +180 from the 'west edge', will round to the nearest 90.
* cl_off_center (string): Distance from the center axis the qubit pocket is referenced to
"""
component_metadata = Dict(short_name="Q", _qgeometry_table_poly="True")
"""Component metadata"""
default_options = Dict(
make_CL=True,
cl_gap="6um", # the cpw dielectric gap of the charge line
cl_width="10um", # the cpw trace width of the charge line
# the length of the charge line 'arm' coupling the the qubit pocket.
cl_length="20um",
# Measured from the base of the 90 degree bend
cl_ground_gap="6um", # how much ground between the charge line and the qubit pocket
# -180 to +180 from the 'left edge', will round to the nearest 90.
cl_pocket_edge="0",
cl_off_center="100um", # distance from the center axis the qubit pocket is built on
)
"""Default drawing options"""
def make(self):
"""Define the way the options are turned into QGeometry."""
super().make()
if self.options.make_CL is True:
self.make_charge_line()
#####################################################################
def make_charge_line(self):
"""Creates the charge line if the user has charge line option to TRUE"""
# Grab option values
name = "Charge_Line"
p = self.p
cl_arm = draw.box(0, 0, -p.cl_width, p.cl_length)
cl_cpw = draw.box(0, 0, -8 * p.cl_width, p.cl_width)
cl_metal = draw.unary_union([cl_arm, cl_cpw])
cl_etcher = draw.buffer(cl_metal, p.cl_gap)
port_line = draw.LineString(
[(-8 * p.cl_width, 0), (-8 * p.cl_width, p.cl_width)]
)
polys = [cl_metal, cl_etcher, port_line]
# Move the charge line to the side user requested
cl_rotate = 0
if (abs(p.cl_pocket_edge) > 135) or (abs(p.cl_pocket_edge) < 45):
polys = draw.translate(
polys,
-(p.pocket_width / 2 + p.cl_ground_gap + p.cl_gap),
-(p.pad_gap + p.pad_height) / 2,
)
if abs(p.cl_pocket_edge) > 135:
p.cl_rotate = 180
else:
polys = draw.translate(
polys,
-(p.pocket_height / 2 + p.cl_groundGap + p.cl_gap),
-(p.pad_width) / 2,
)
cl_rotate = 90
if p.cl_pocket_edge < 0:
cl_rotate = -90
# Rotate it to the pockets orientation
polys = draw.rotate(polys, p.orientation + cl_rotate, origin=(0, 0))
# Move to the final position
polys = draw.translate(polys, p.pos_x, p.pos_y)
[cl_metal, cl_etcher, port_line] = polys
# Generating pins
points = list(draw.shapely.geometry.shape(port_line).coords)
self.add_pin(name, points, p.cl_width) # TODO: chip
# Adding to element table
self.add_qgeometry("poly", dict(cl_metal=cl_metal))
self.add_qgeometry("poly", dict(cl_etcher=cl_etcher), subtract=True)
We can see this is the case by generating a TransmonPocketCL in the GUI.
[11]:
gui = metal.MetalGUI(design)
[12]:
my_transmon_cl = TransmonPocketCL(
design,
"my_transmon_cl",
options=dict(connection_pads=dict(a=dict(), b=dict(loc_W=-1))),
)
gui.rebuild()
gui.autoscale()
gui.screenshot()
[13]:
my_transmon_cl.options
[13]:
{'pos_x': '0um',
'pos_y': '0um',
'connection_pads': {'a': {'pad_gap': '15um',
'pad_width': '125um',
'pad_height': '30um',
'pad_cpw_shift': '5um',
'pad_cpw_extent': '25um',
'cpw_width': 'cpw_width',
'cpw_gap': 'cpw_gap',
'cpw_extend': '100um',
'pocket_extent': '5um',
'pocket_rise': '65um',
'loc_W': '+1',
'loc_H': '+1'},
'b': {'pad_gap': '15um',
'pad_width': '125um',
'pad_height': '30um',
'pad_cpw_shift': '5um',
'pad_cpw_extent': '25um',
'cpw_width': 'cpw_width',
'cpw_gap': 'cpw_gap',
'cpw_extend': '100um',
'pocket_extent': '5um',
'pocket_rise': '65um',
'loc_W': -1,
'loc_H': '+1'}},
'chip': 'main',
'pad_gap': '30um',
'inductor_width': '20um',
'pad_width': '455um',
'pad_height': '90um',
'pocket_width': '650um',
'pocket_height': '650um',
'orientation': '0',
'make_CL': True,
'cl_gap': '6um',
'cl_width': '10um',
'cl_length': '20um',
'cl_ground_gap': '6um',
'cl_pocket_edge': '0',
'cl_off_center': '100um',
'hfss_wire_bonds': False,
'q3d_wire_bonds': False,
'hfss_inductance': '10nH',
'hfss_capacitance': 0,
'hfss_resistance': 0,
'hfss_mesh_kw_jj': 7e-06,
'q3d_inductance': '10nH',
'q3d_capacitance': 0,
'q3d_resistance': 0,
'q3d_mesh_kw_jj': 7e-06,
'gds_cell_name': 'my_other_junction'}
We can see that my_transmon_cl inherited the appropriate options from TransmonPocket, and even got the junction renderer options since its parent class does declare _qgeometry_table_junction='True'
[14]:
gui.main_window.close()
[14]:
True
For more information, review the Introduction to Quantum Computing and Quantum Hardware lectures below
|
Lecture Video | Lecture Notes | Lab |
|
Lecture Video | Lecture Notes | Lab |
|
Lecture Video | Lecture Notes | Lab |
|
Lecture Video | Lecture Notes | Lab |
|
Lecture Video | Lecture Notes | Lab |
|
Lecture Video | Lecture Notes | Lab |