Note

This page was generated from tut//4-Analysis//4.01-Capacitance-and-LOM.ipynb.

Capacitance matrix and LOM analysis#

Prerequisite#

You need to have a working local installation of Ansys.

1. Create the design in Metal#

[1]:
%reload_ext autoreload
%autoreload 2
[2]:
import qiskit_metal as metal
from qiskit_metal import designs, draw
from qiskit_metal import MetalGUI, Dict, Headings
[3]:
design = designs.DesignPlanar()
gui = MetalGUI(design)

from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket
from qiskit_metal.qlibrary.tlines.meandered import RouteMeander
[4]:
design.variables['cpw_width'] = '15 um'
design.variables['cpw_gap'] = '9 um'

In this example, the design consists of 4 qubits and 4 CPWs#

[5]:
# Allow running the same cell here multiple times to overwrite changes
design.overwrite_enabled = True

## Custom options for all the transmons
options = dict(
    # Some options we want to modify from the defaults
    # (see below for defaults)
    pad_width = '425 um',
    pocket_height = '650um',
    # Adding 4 connectors (see below for defaults)
    connection_pads=dict(
        readout = dict(loc_W=+1,loc_H=-1, pad_width='200um'),
        bus1 = dict(loc_W=-1,loc_H=+1, pad_height='30um'),
        bus2 = dict(loc_W=-1,loc_H=-1, pad_height='50um')
    )
)

## Create 4 transmons

q1 = TransmonPocket(design, 'Q1', options = dict(
    pos_x='+2.42251mm', pos_y='+0.0mm', **options))
q2 = TransmonPocket(design, 'Q2', options = dict(
    pos_x='+0.0mm', pos_y='-0.95mm', orientation = '270', **options))
q3 = TransmonPocket(design, 'Q3', options = dict(
    pos_x='-2.42251mm', pos_y='+0.0mm', orientation = '180', **options))
q4 = TransmonPocket(design, 'Q4', options = dict(
    pos_x='+0.0mm', pos_y='+0.95mm', orientation = '90', **options))

RouteMeander.get_template_options(design)

options = Dict(
        lead=Dict(
            start_straight='0.2mm',
            end_straight='0.2mm'),
        trace_gap='9um',
        trace_width='15um')

def connect(component_name: str, component1: str, pin1: str, component2: str, pin2: str,
            length: str, asymmetry='0 um', flip=False, fillet='90um'):
    """Connect two pins with a CPW."""
    myoptions = Dict(
        fillet=fillet,
        hfss_wire_bonds = True,
        pin_inputs=Dict(
            start_pin=Dict(
                component=component1,
                pin=pin1),
            end_pin=Dict(
                component=component2,
                pin=pin2)),
        total_length=length)
    myoptions.update(options)
    myoptions.meander.asymmetry = asymmetry
    myoptions.meander.lead_direction_inverted = 'true' if flip else 'false'
    return RouteMeander(design, component_name, myoptions)

asym = 140
cpw1 = connect('cpw1', 'Q1', 'bus2', 'Q2', 'bus1', '6.0 mm', f'+{asym}um')
cpw2 = connect('cpw2', 'Q3', 'bus1', 'Q2', 'bus2', '6.1 mm', f'-{asym}um', flip=True)
cpw3 = connect('cpw3', 'Q3', 'bus2', 'Q4', 'bus1', '6.0 mm', f'+{asym}um')
cpw4 = connect('cpw4', 'Q1', 'bus1', 'Q4', 'bus2', '6.1 mm', f'-{asym}um', flip=True)

gui.rebuild()
gui.autoscale()
[6]:
gui.screenshot()
../../_images/tut_4-Analysis_4.01-Capacitance-and-LOM_8_0.png

2. Capacitance Analysis and LOM derivation using the analysis package - most users#

Capacitance Analysis#

Select the analysis you intend to run from the qiskit_metal.analyses collection. Select the design to analyze and the tool to use for any external simulation

[7]:
from qiskit_metal.analyses.quantization import LOManalysis
c1 = LOManalysis(design, "q3d")

(optional) You can review and update the Analysis default setup following the examples in the next two cells.

[8]:
c1.sim.setup
[8]:
{'name': 'Setup',
 'reuse_selected_design': True,
 'freq_ghz': 5.0,
 'save_fields': False,
 'enabled': True,
 'max_passes': 15,
 'min_passes': 2,
 'min_converged_passes': 2,
 'percent_error': 0.5,
 'percent_refinement': 30,
 'auto_increase_solution_order': True,
 'solution_order': 'High',
 'solver_type': 'Iterative'}
[9]:
# example: update single setting
c1.sim.setup.max_passes = 6
# example: update multiple settings
c1.sim.setup_update(solution_order = 'Medium', auto_increase_solution_order = 'False')

c1.sim.setup
[9]:
{'name': 'Setup',
 'reuse_selected_design': True,
 'freq_ghz': 5.0,
 'save_fields': False,
 'enabled': True,
 'max_passes': 6,
 'min_passes': 2,
 'min_converged_passes': 2,
 'percent_error': 0.5,
 'percent_refinement': 30,
 'auto_increase_solution_order': 'False',
 'solution_order': 'Medium',
 'solver_type': 'Iterative'}

Analyze a single qubit with 2 endcaps using the default (or edited) analysis setup. Then show the capacitance matrix (from the last pass).

You can use the method run() instead of sim.run() in the following cell if you want to run both cap extraction and lom analysis in a single step. If so, make sure to also tweak the setup for the lom analysis. The input parameters are otherwise the same for the two methods.

[10]:
c1.sim.run(components=['Q1'], open_terminations=[('Q1', 'readout'), ('Q1', 'bus1'), ('Q1', 'bus2')])
c1.sim.capacitance_matrix
INFO 08:32AM [connect_project]: Connecting to Ansys Desktop API...
INFO 08:32AM [load_ansys_project]:      Opened Ansys App
INFO 08:32AM [load_ansys_project]:      Opened Ansys Desktop v2020.2.0
INFO 08:32AM [load_ansys_project]:      Opened Ansys Project
        Folder:    C:/Ansoft/
        Project:   Project22
INFO 08:32AM [connect_design]: No active design found (or error getting active design).
INFO 08:32AM [connect]:          Connected to project "Project22". No design detected
INFO 08:32AM [connect_design]:  Opened active design
        Design:    Design_q3d [Solution type: Q3D]
WARNING 08:32AM [connect_setup]:        No design setup detected.
WARNING 08:32AM [connect_setup]:        Creating Q3D default setup.
INFO 08:32AM [get_setup]:       Opened setup `Setup`  (<class 'pyEPR.ansys.AnsysQ3DSetup'>)
INFO 08:32AM [get_setup]:       Opened setup `Setup1`  (<class 'pyEPR.ansys.AnsysQ3DSetup'>)
INFO 08:32AM [analyze]: Analyzing setup Setup1
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmp9kdob592.txt, C, , Setup1:LastAdaptive, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 1, False
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpsk8_aon5.txt, C, , Setup1:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 1, False
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmp6zdkc4y0.txt, C, , Setup1:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 2, False
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmp2hpfznmn.txt, C, , Setup1:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 3, False
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpj38u4y4a.txt, C, , Setup1:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 4, False
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpknqz7sw0.txt, C, , Setup1:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 5, False
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmp9mj4v6i8.txt, C, , Setup1:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 6, False
INFO 08:33AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpj0mu6o1u.txt, C, , Setup1:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 7, False
[10]:
bus1_connector_pad_Q1 bus2_connector_pad_Q1 ground_main_plane pad_bot_Q1 pad_top_Q1 readout_connector_pad_Q1
bus1_connector_pad_Q1 49.77794 -0.42560 -33.50861 -1.57029 -13.15538 -0.20494
bus2_connector_pad_Q1 -0.42560 54.01885 -35.77522 -13.99741 -1.82852 -1.01319
ground_main_plane -33.50861 -35.77522 237.69029 -31.53485 -37.88741 -36.55732
pad_bot_Q1 -1.57029 -13.99741 -31.53485 98.20667 -30.07382 -18.86490
pad_top_Q1 -13.15538 -1.82852 -37.88741 -30.07382 87.85076 -2.20122
readout_connector_pad_Q1 -0.20494 -1.01319 -36.55732 -18.86490 -2.20122 59.92347

The last variables you pass to the run() or sim.run() methods, will be stored in the sim.setup dictionary under the key run. You can recall the information passed by either accessing the dictionary directly, or by using the print handle below.

[11]:
# c1.setup.run    <- direct access
c1.print_run_args()
This analysis object run with the following kwargs:
{}

You can re-run the analysis after varying the parameters. Not passing the parameter components to the sim.run() method, skips the rendering and tries to run the analysis on the latest design. If a design is not found, the full metal design is rendered.

[12]:
c1.sim.setup.freq_ghz = 4.8
c1.sim.run()
c1.sim.capacitance_matrix
INFO 08:33AM [get_setup]:       Opened setup `Setup2`  (<class 'pyEPR.ansys.AnsysQ3DSetup'>)
INFO 08:33AM [analyze]: Analyzing setup Setup2
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmp2zqpsp70.txt, C, , Setup2:LastAdaptive, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 1, False
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmp5r0te98b.txt, C, , Setup2:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 1, False
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpvakd3cxo.txt, C, , Setup2:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 2, False
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmppo2b9z67.txt, C, , Setup2:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 3, False
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpskxpuv4a.txt, C, , Setup2:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 4, False
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmprf7et9ty.txt, C, , Setup2:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 5, False
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpuooj6mi9.txt, C, , Setup2:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 6, False
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmpm9a1sk65.txt, C, , Setup2:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 4800000000, Maxwell, 7, False
[12]:
bus1_connector_pad_Q1 bus2_connector_pad_Q1 ground_main_plane pad_bot_Q1 pad_top_Q1 readout_connector_pad_Q1
bus1_connector_pad_Q1 49.77794 -0.42560 -33.50861 -1.57029 -13.15538 -0.20494
bus2_connector_pad_Q1 -0.42560 54.01885 -35.77522 -13.99741 -1.82852 -1.01319
ground_main_plane -33.50861 -35.77522 237.69029 -31.53485 -37.88741 -36.55732
pad_bot_Q1 -1.57029 -13.99741 -31.53485 98.20667 -30.07382 -18.86490
pad_top_Q1 -13.15538 -1.82852 -37.88741 -30.07382 87.85076 -2.20122
readout_connector_pad_Q1 -0.20494 -1.01319 -36.55732 -18.86490 -2.20122 59.92347
[13]:
type(c1.sim.capacitance_matrix)
[13]:
pandas.core.frame.DataFrame

Lumped oscillator model (LOM)#

Using capacitance matrices obtained from each pass, save the many parameters of the Hamiltonian of the system. get_lumped_oscillator() operates on 4 setup parameters: Lj: float Cj: float fr: Union[list, float] fb: Union[list, float]

[14]:
c1.setup.junctions = Dict({'Lj': 12.31, 'Cj': 2})
c1.setup.freq_readout = 7.0
c1.setup.freq_bus = [6.0, 6.2]

c1.run_lom()
c1.lumped_oscillator_all
[3, 4] [5 0 1]
Predicted Values

Transmon Properties
f_Q 5.424935 [GHz]
EC 311.976959 [MHz]
EJ 13.273404 [GHz]
alpha -363.792421 [MHz]
dispersion 46.550369 [KHz]
Lq 12.305036 [nH]
Cq 62.088650 [fF]
T1 35.336766 [us]

**Coupling Properties**

tCqbus1 7.383750 [fF]
gbus1_in_MHz 114.265793 [MHz]
χ_bus1 -3.174191 [MHz]
1/T1bus1 2809.277762 [Hz]
T1bus1 56.653331 [us]

tCqbus2 -6.455281 [fF]
gbus2_in_MHz -85.831803 [MHz]
χ_bus2 -9.970470 [MHz]
1/T1bus2 1205.469467 [Hz]
T1bus2 132.027353 [us]

tCqbus3 5.372192 [fF]
gbus3_in_MHz 73.765178 [MHz]
χ_bus3 -4.515417 [MHz]
1/T1bus3 489.200415 [Hz]
T1bus3 325.336893 [us]
Bus-Bus Couplings
gbus1_2 7.097123 [MHz]
gbus1_3 9.957495 [MHz]
gbus2_3 5.377146 [MHz]
[14]:
fQ EC EJ alpha dispersion gbus chi_in_MHz χr MHz gr MHz
1 5.748104 353.230672 13.273404 -417.375147 135.208268 [108.79200978040816, -73.21708181328188, 76.45... [-4.790610087146514, -26.5770698752867, -12.45... 4.790610 108.792010
2 5.664672 342.295447 13.273404 -403.045739 103.898327 [112.48401834623373, -82.16156406673579, 68.80... [-4.4594265208402275, -22.018835553935766, -7.... 4.459427 112.484018
3 5.574019 330.639537 13.273404 -387.872732 77.330688 [111.33612864790418, -84.09226785308748, 71.77... [-3.7804661114555205, -15.865600375824991, -6.... 3.780466 111.336129
4 5.523032 324.186357 13.273404 -379.516629 65.212167 [110.99790102064628, -84.10822360591214, 72.87... [-3.4720716615303537, -13.185856349486748, -5.... 3.472072 110.997901
5 5.463772 316.778339 13.273404 -369.962716 53.275261 [113.07905190117796, -84.87724687606234, 72.79... [-3.293717894242756, -11.011779798984726, -4.8... 3.293718 113.079052
6 5.424935 311.976959 13.273404 -363.792421 46.550369 [114.26579286281127, -85.83180315154853, 73.76... [-3.1741912468040616, -9.970469520050226, -4.5... 3.174191 114.265793
[15]:
c1.plot_convergence();
c1.plot_convergence_chi()
Design "Design_q3d" info:
        # eigenmodes    0
        # variations    1
INFO 08:34AM [hfss_report_full_convergence]: Creating report for variation 0

Once you are done with your analysis, please close it with close(). This will free up resources currently occupied by qiskit-metal to communiate with the tool.

[16]:
c1.sim.close()

3. Directly access the renderer to modify other parameters#

[17]:
c1.sim.start()
c1.sim.renderer
INFO 08:34AM [connect_project]: Connecting to Ansys Desktop API...
INFO 08:34AM [load_ansys_project]:      Opened Ansys App
INFO 08:34AM [load_ansys_project]:      Opened Ansys Desktop v2020.2.0
INFO 08:34AM [load_ansys_project]:      Opened Ansys Project
        Folder:    C:/Ansoft/
        Project:   Project22
INFO 08:34AM [connect_design]:  Opened active design
        Design:    Design_q3d [Solution type: Q3D]
INFO 08:34AM [get_setup]:       Opened setup `Setup`  (<class 'pyEPR.ansys.AnsysQ3DSetup'>)
INFO 08:34AM [connect]:         Connected to project "Project22" and design "Design_q3d" 😀

[17]:
<qiskit_metal.renderers.renderer_ansys.q3d_renderer.QQ3DRenderer at 0x268898f7fc8>

Every renderer will have its own collection of methods. Below an example with q3d

Prepare and run a collection of predefined setups#

This is equivalent to going to the Project Manager panel in Ansys, right clicking on Analysis within the active Q3D design, selecting “Add Solution Setup…”, and choosing/entering default values in the resulting popup window. You might want to do this to keep track of different solution setups, giving each of them a different/specific name.

[18]:
setup = c1.sim.renderer.new_ansys_setup(name = "Setup_demo", max_passes = 6)

You can directly pass to new_ansys_setup all the setup parameters. Of course you will then need to run the individual setups by name as well.

[19]:
c1.sim.renderer.analyze_setup(setup.name)
INFO 08:34AM [get_setup]:       Opened setup `Setup_demo`  (<class 'pyEPR.ansys.AnsysQ3DSetup'>)
INFO 08:34AM [analyze]: Analyzing setup Setup_demo

Get the capactiance matrix at a different pass#

You might want to use this if you intend to know what was the matrix at a different pass of the simulation.

[20]:
# Using the analysis results, get its capacitance matrix as a dataframe.
c1.sim.renderer.get_capacitance_matrix(variation = '', solution_kind = 'AdaptivePass', pass_number = 5)
INFO 08:34AM [get_matrix]: Exporting matrix data to (C:\Temp\tmp3caa8vjk.txt, C, , Setup_demo:AdaptivePass, "Original", "ohm", "nH", "fF", "mSie", 5000000000, Maxwell, 5, False
[20]:
(                          bus1_connector_pad_Q1  bus2_connector_pad_Q1  \
 bus1_connector_pad_Q1                  48.92803               -0.42235
 bus2_connector_pad_Q1                  -0.42235               53.06961
 ground_main_plane                     -33.01607              -35.14374
 pad_bot_Q1                             -1.53861              -13.67515
 pad_top_Q1                            -12.84517               -1.81368
 readout_connector_pad_Q1               -0.20677               -0.99928

                           ground_main_plane  pad_bot_Q1  pad_top_Q1  \
 bus1_connector_pad_Q1             -33.01607    -1.53861   -12.84517
 bus2_connector_pad_Q1             -35.14374   -13.67515    -1.81368
 ground_main_plane                 234.01567   -31.50558   -37.64437
 pad_bot_Q1                        -31.50558    96.95568   -29.44070
 pad_top_Q1                        -37.64437   -29.44070    86.62922
 readout_connector_pad_Q1          -36.15710   -18.48102    -2.19686

                           readout_connector_pad_Q1
 bus1_connector_pad_Q1                     -0.20677
 bus2_connector_pad_Q1                     -0.99928
 ground_main_plane                        -36.15710
 pad_bot_Q1                               -18.48102
 pad_top_Q1                                -2.19686
 readout_connector_pad_Q1                  59.14496  ,
 'fF')

Code to swap rows and columns in capacitance matrix#

from qiskit_metal.analyses.quantization.lumped_capacitive import df_reorder_matrix_basis

df_reorder_matrix_basis(fourq_q3d.get_capacitance_matrix(), 1, 2)

[22]:
c1.sim.close()

For more information, review the Introduction to Quantum Computing and Quantum Hardware lectures below

  • Superconducting Qubits I: Quantizing a Harmonic Oscillator, Josephson Junctions Part 1
Lecture Video Lecture Notes Lab
  • Superconducting Qubits I: Quantizing a Harmonic Oscillator, Josephson Junctions Part 2
Lecture Video Lecture Notes Lab
  • Superconducting Qubits I: Quantizing a Harmonic Oscillator, Josephson Junctions Part 3
Lecture Video Lecture Notes Lab
  • Superconducting Qubits II: Circuit Quantum Electrodynamics, Readout and Calibration Methods Part 1
Lecture Video Lecture Notes Lab
  • Superconducting Qubits II: Circuit Quantum Electrodynamics, Readout and Calibration Methods Part 2
Lecture Video Lecture Notes Lab
  • Superconducting Qubits II: Circuit Quantum Electrodynamics, Readout and Calibration Methods Part 3
Lecture Video Lecture Notes Lab