Note
This page was generated from circuit-examples//F.Small-quantum-chips//51-Four_qubit_chip.ipynb.
Four Qubit Chip Design¶
Creates a complete quantum chip and exports it
Preparations¶
The next cell enables module automatic reload. Your notebook will be able to pick up code updates made to the qiskit-metal (or other) module code.
[1]:
%reload_ext autoreload
%autoreload 2
Import key libraries and open the Metal GUI. Also we configure the notebook to enable overwriting of existing components
[2]:
import numpy as np
from collections import OrderedDict
from qiskit_metal import designs, draw
from qiskit_metal import MetalGUI, Dict, Headings
design = designs.DesignPlanar()
gui = MetalGUI(design)
# if you disable the next line, then you will need to delete a component [<component>.delete()] before recreating it
design.overwrite_enabled = True
Import components that will be necessary for the design
[3]:
from qiskit_metal.qlibrary.qubits.transmon_pocket_cl import TransmonPocketCL
from qiskit_metal.qlibrary.tlines.meandered import RouteMeander
from qiskit_metal.qlibrary.tlines.anchored_path import RouteAnchors
from qiskit_metal.qlibrary.tlines.pathfinder import RoutePathfinder
from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround
from qiskit_metal.qlibrary.terminations.launchpad_wb import LaunchpadWirebond
from qiskit_metal.qlibrary.terminations.launchpad_wb_coupled import LaunchpadWirebondCoupled
Let’s design the core of the chip¶
Setup the design-wide default settings for trace width and trace gap. These can be customized later for individual transmission lines.
[4]:
design.variables['cpw_width'] = '10 um'
design.variables['cpw_gap'] = '6 um'
design._chips['main']['size']['size_y'] = '9mm'
design._chips['main']['size']['size_y'] = '6.5mm'
We need 4 transmons with 3 connection pads each and a chargeline. Let’s explore the options of one transmon
[5]:
TransmonPocketCL.get_template_options(design)
[5]:
{'pos_x': '0um',
'pos_y': '0um',
'connection_pads': {},
'_default_connection_pads': {'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': '50um',
'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 want to change the pad_width
for these transmons, as well as define the 3 connection pads and chargeline.
To apply the same modifications to all 4 transmons, we define a single option-dictionary to pass to all transmons at the monent of creation
[6]:
transmon_options = dict(
connection_pads=dict(
a = dict(loc_W=+1, loc_H=-1, pad_width='70um', cpw_extend = '50um'),
b = dict(loc_W=-1, loc_H=-1, pad_width='125um', cpw_extend = '50um'),
c = dict(loc_W=-1, loc_H=+1, pad_width='110um', cpw_extend = '50um')
),
gds_cell_name='FakeJunction_01',
cl_off_center = '-50um',
cl_pocket_edge = '180'
)
We can now create the 4 transmons by specifying the desired coordinates and orientations.
[7]:
offset_tm = 69 #we the transmon slightly out of center-line
q1 = TransmonPocketCL(design, 'Q1', options = dict(
pos_x='+2420um', pos_y=f'{offset_tm}um', **transmon_options))
q2 = TransmonPocketCL(design, 'Q2', options = dict(
pos_x='0um', pos_y='-857.6um', orientation = '270', **transmon_options))
q3 = TransmonPocketCL(design, 'Q3', options = dict(
pos_x='-2420um', pos_y=f'{offset_tm}um', orientation = '180', **transmon_options))
q4 = TransmonPocketCL(design, 'Q4', options = dict(
pos_x='0um', pos_y='+857.6um', orientation = '90', **transmon_options))
gui.rebuild()
gui.autoscale()
Let’s now connect the transmons with tranismission lines. We want to have an “exact length” transmission line, so we will use the RouteMeander
. Let’s first observe what are the default options
[8]:
RouteMeander.get_template_options(design)
[8]:
{'pin_inputs': {'start_pin': {'component': '', 'pin': ''},
'end_pin': {'component': '', 'pin': ''}},
'fillet': '0',
'lead': {'start_straight': '0mm',
'end_straight': '0mm',
'start_jogged_extension': '',
'end_jogged_extension': ''},
'total_length': '7mm',
'chip': 'main',
'layer': '1',
'trace_width': 'cpw_width',
'meander': {'spacing': '200um', 'asymmetry': '0um'},
'snap': 'true',
'prevent_short_edges': 'true',
'hfss_wire_bonds': False,
'q3d_wire_bonds': False}
We want to globally override the default lead (straight initial segment leaving the transmon) and the default fillet (corner rounding radius). Let’s collect this information in one dictionary
[9]:
fillet='99.99um'
cpw_options = Dict(
lead=Dict(
start_straight='100um',
end_straight='250um'),
fillet=fillet
)
We then want each transmission line to be connected to different pins and to have different lengths and asymmetry w.r.t their centerline. Let’s collect this information in other dictionaries. Before doing that, to manage the dictionaries in a simpler way, we redefine the RouteMeander
signature by wrapping it into a convenience method named connect
[10]:
def connect(cpw_name: str, pin1_comp_name: str, pin1_comp_pin: str, pin2_comp_name: str, pin2_comp_pin: str,
length: str, asymmetry='0 um'):
"""Connect two pins with a CPW."""
myoptions = Dict(
pin_inputs=Dict(
start_pin=Dict(
component=pin1_comp_name,
pin=pin1_comp_pin),
end_pin=Dict(
component=pin2_comp_name,
pin=pin2_comp_pin)),
total_length=length)
myoptions.update(cpw_options)
myoptions.meander.asymmetry = asymmetry
return RouteMeander(design, cpw_name, myoptions)
We can now proceed and define the meanders following the signature: connect(cpw_name, pin1_comp_name, pin1_comp_pin, pin2_comp_name, pin2_comp_pin, length, asymmetry)
[11]:
asym = 500
cpw1 = connect('cpw1', 'Q1', 'c', 'Q4', 'b', '9000um', f'-{asym-1.25*offset_tm}um')
cpw2 = connect('cpw2', 'Q3', 'b', 'Q4', 'c', '9000um', f'+{asym-1.25*offset_tm}um')
cpw3 = connect('cpw3', 'Q3', 'c', 'Q2', 'b', '9000um', f'-{asym+0.75*offset_tm}um')
cpw4 = connect('cpw4', 'Q1', 'b', 'Q2', 'c', '9000um', f'+{asym+0.75*offset_tm}um')
gui.rebuild()
gui.autoscale()
Let’s now connect the core elements to the launchpads¶
First we setup the launchpad location and orientation
[12]:
# V1 - Corners
p1_c = LaunchpadWirebond(design, 'P1_C', options = dict(pos_x='3545um', pos_y='2812um', orientation='270', lead_length='0um'))
p2_c = LaunchpadWirebond(design, 'P2_C', options = dict(pos_x='3545um', pos_y='-2812um', orientation='90', lead_length='0um'))
p3_c = LaunchpadWirebond(design, 'P3_C', options = dict(pos_x='-3545um', pos_y='-2812um', orientation='90', lead_length='0um'))
p4_c = LaunchpadWirebond(design, 'P4_C', options = dict(pos_x='-3545um', pos_y='2812um', orientation='270', lead_length='0um'))
# V2
p1_q = LaunchpadWirebondCoupled(design, 'P1_Q', options = dict(pos_x='4020um', pos_y='0', orientation='180', lead_length='30um'))
p2_q = LaunchpadWirebondCoupled(design, 'P2_Q', options = dict(pos_x='-990um', pos_y='-2812um', orientation='90', lead_length='30um'))
p3_q = LaunchpadWirebondCoupled(design, 'P3_Q', options = dict(pos_x='-4020um', pos_y='0', orientation='0', lead_length='30um'))
p4_q = LaunchpadWirebondCoupled(design, 'P4_Q', options = dict(pos_x='990um', pos_y='2812um', orientation='270', lead_length='30um'))
gui.rebuild()
gui.autoscale()
Then we route. First the V2 launchpads - Exchange Coupler Lines to Edges
[13]:
asym = 150
cpw_options = Dict(
lead=Dict(
start_straight='430um',
end_straight='0um'),
fillet=fillet
)
ol1 = connect('ol1', 'Q1', 'a', 'P1_Q', 'tie', '8.6 mm', f'+{asym}um')
ol3 = connect('ol3', 'Q3', 'a', 'P3_Q', 'tie', '8.6 mm', f'+{asym}um')
asym = 200
cpw_options = Dict(
lead=Dict(
start_straight='535um',
end_straight='0um'),
fillet=fillet
)
ol2 = connect('ol2', 'Q2', 'a', 'P2_Q', 'tie', '8.6 mm', f'+{asym}um')
ol4 = connect('ol4', 'Q4', 'a', 'P4_Q', 'tie', '8.6 mm', f'+{asym}um')
gui.rebuild()
gui.autoscale()
Finally we route the V1 launchpads - Charge Lines to Corners
We create the transmission lines between the corner launchpads and the open to grounds
[14]:
from collections import OrderedDict
jogsA_in = OrderedDict()
jogsA_in[0] = ["L", '200um']
options_line_cl1 = {'pin_inputs':
{'start_pin': {'component': 'Q1', 'pin': 'Charge_Line'},
'end_pin': {'component': 'P1_C', 'pin': 'tie'}},
'lead': {'start_straight': '120um', 'end_straight': '225um','start_jogged_extension': jogsA_in},
'fillet': fillet
}
cl1 = RouteAnchors(design, 'line_cl1', options_line_cl1)
options_line_cl3 = {'pin_inputs':
{'start_pin': {'component': 'Q3', 'pin': 'Charge_Line'},
'end_pin': {'component': 'P3_C', 'pin': 'tie'}},
'lead': {'start_straight': '120um', 'end_straight': '225um', 'start_jogged_extension': jogsA_in},
'fillet': fillet
}
cl3 = RouteAnchors(design, 'line_cl3', options_line_cl3)
gui.rebuild()
gui.autoscale()
[15]:
jogsB_in = OrderedDict()
jogsB_in[0] = ["L", '300um']
anchors2c = OrderedDict()
anchors2c[0] = np.array([2, -2.5])
options_line_cl2 = {'pin_inputs':
{'start_pin': {'component': 'Q2', 'pin': 'Charge_Line'},
'end_pin': {'component': 'P2_C', 'pin': 'tie'}},
'lead': {'start_straight': '200um', 'end_straight': '225um',
'start_jogged_extension': jogsB_in},
'anchors': anchors2c,
'fillet': fillet
}
cl2 = RouteAnchors(design, 'line_cl2', options_line_cl2)
anchors4c = OrderedDict()
anchors4c[0] = np.array([-2, 2.5])
options_line_cl4 = {'pin_inputs':
{'start_pin': {'component': 'Q4', 'pin': 'Charge_Line'},
'end_pin': {'component': 'P4_C', 'pin': 'tie'}},
'lead': {'start_straight': '200um', 'end_straight': '225um',
'start_jogged_extension': jogsB_in},
'anchors': anchors4c,
'fillet': fillet
}
cl4 = RouteAnchors(design, 'line_cl4', options_line_cl4)
gui.rebuild()
gui.autoscale()
[16]:
gui.rebuild() # rebuild the design and plot
gui.autoscale() #resize GUI to see QComponent
[17]:
# Get a list of all the qcomponents in QDesign and then zoom on them.
all_component_names = design.components.keys()
gui.zoom_on_components(all_component_names)
[18]:
#Save screenshot as a .png formatted file.
gui.screenshot()
[19]:
# Screenshot the canvas only as a .png formatted file.
gui.figure.savefig('shot.png')
from IPython.display import Image, display
_disp_ops = dict(width=500)
display(Image('shot.png', **_disp_ops))
[20]:
# Closing the Qiskit Metal GUI
gui.main_window.close()
[20]:
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 |