4.19 Analyse a Transmon Qubit using ElmerFEM

This notebook demonstrates the new open-source rendering and simulation capabilities of Qiskit Metal using Gmsh and ElmerFEM for tuning the performance parameters of a transmon qubit. instructions to download and install this branch of Qiskit Metal with Gmsh and ElmerFEM, can he found here The tutorial has the following steps:

Contents

1. Creating a Transmon Qubit in Qiskit Metal

2. Rendering and meshing your design in the QGmshRenderer

  • Rendering the design wireframe

  • Applying a basic mesh

  • Customizing the mesh

    • Setting initial mesh size parameters

    • Using the Intelli-mesh feature in QGmshRenderer

  • Saving your mesh to a file

3. Rendering your design in QElmerRenderer (uses QGmshRenderer)

  • Render design and generate mesh

  • Export the mesh

  • Run the capacitance simulation

    • Add solution setup

    • Run the solver

    • Export capacitance matrix

4. Perform LOM 2.0 Analysis

  • Import the capacitance matrix

  • Define cells and subsystems

  • Define the composite system

  • Compute the results:

    • Qubit Frequency (\(f_Q\))

    • Anharmonicity (\(\alpha\))

    • Readout \(\chi\)

    • Coupling \(g\)

💡 Using this tutorial without the Qt GUI

This tutorial uses the desktop MetalGUI. To follow along on Colab, Binder, JupyterHub, or any environment where Qt isn’t available, replace any ``gui.rebuild()`` / ``gui.screenshot()`` call with ``qm.view(design)`` — it renders the design to a matplotlib Figure you can display inline or save with fig.savefig(...).

See 1.4 Headless quick view for a complete runnable walkthrough and `docs/headless-usage.rst <../../../docs/headless-usage.rst>`__ for the full reference.

Necessary Imports

[ ]:
%load_ext autoreload
%autoreload 2

# Import basic things of Qiskit Metal
from qiskit_metal import MetalGUI, designs
from qiskit_metal.qlibrary.qubits.transmon_pocket_6 import TransmonPocket6

# Import the Gmsh renderer
from qiskit_metal.renderers.renderer_gmsh.gmsh_renderer import QGmshRenderer

# Import the Elmer renderer
from qiskit_metal.renderers.renderer_elmer.elmer_renderer import QElmerRenderer
from qiskit_metal.renderers.renderer_elmer.elmer_renderer import (
    load_capacitance_matrix_from_file,
)
[ ]:
%metal_heading 1. Create a Transmon Qubit in Qiskit Metal
[ ]:
# Instantiate a design object
design = designs.MultiPlanar({}, True)

# Invoke the Qiskit Metal GUI
gui = MetalGUI(design)
[ ]:
# Define a dictionary for connection pad options for the transmon
conn_pads = dict(
    connection_pads=dict(
        readout=dict(loc_W=0, loc_H=-1),
        coupler1=dict(loc_W=-1, loc_H=1),
        coupler2=dict(loc_W=1, loc_H=1),
    )
)

# Create a TransmonPocket6 object
q1 = TransmonPocket6(design, "Q1", options=dict(**conn_pads))

# Rebuild and autoscale the GUI
gui.rebuild()
gui.autoscale()
[ ]:
%metal_heading 2. Rendering and meshing your design in the `QGmshRenderer`

Rendering the design wireframe

[ ]:
# Instantiate the Gmsh renderer
gmsh_renderer = QGmshRenderer(design)

# Render the design
# Tip: `mesh_geoms = False` will not mesh the design,
# but only draw the wire-frame of the geomtries
gmsh_renderer.render_design(
    open_pins=[("Q1", "coupler1"), ("Q1", "coupler2"), ("Q1", "readout")],
    mesh_geoms=False,
)
[ ]:
# Launch Gmsh GUI to see the rendererd design
gmsh_renderer.launch_gui()

Applying a basic mesh

[ ]:
# Add a basic mesh to the design and luanch the GUI to view
gmsh_renderer.add_mesh(dim=3, intelli_mesh=False)
gmsh_renderer.launch_gui()

Customizing the mesh

Setting initial mesh size parameters

[ ]:
# Update the mesh options
gmsh_renderer.options.mesh.min_size = "5um"
gmsh_renderer.options.mesh.max_size = "20um"

# Render the design
gmsh_renderer.render_design(
    open_pins=[("Q1", "coupler1"), ("Q1", "coupler2"), ("Q1", "readout")],
    mesh_geoms=False,
)

# Mesh the design (without intelli-mesh)
gmsh_renderer.add_mesh(intelli_mesh=False)
gmsh_renderer.launch_gui()

Using the Intelli-mesh feature in QGmshRenderer

[ ]:
# Update the mesh options
gmsh_renderer.options.mesh.min_size = "5um"
gmsh_renderer.options.mesh.max_size = "50um"

# Render and mesh the design (with intelli-mesh)
gmsh_renderer.render_design(
    open_pins=[("Q1", "coupler1"), ("Q1", "coupler2"), ("Q1", "readout")],
    mesh_geoms=True,
)
gmsh_renderer.launch_gui()

Saving your mesh to a file

[ ]:
# Export the Gmsh generated mesh to a file
gmsh_renderer.export_mesh("test.msh")
[ ]:
# Close the Gmsh renderer
gmsh_renderer.close()
[ ]:
%metal_heading 3. Rendering your design in `QElmerRenderer` (uses `QGmshRenderer`)
[ ]:
# Instantiate the Elmer renderer
elmer_renderer = QElmerRenderer(design)

# Elmer renderer uses the Gmsh renderer to
# generate a mesh for the design
# Set initial parameters for meshing in Gmsh (IMPORTANT step!!)
elmer_renderer.gmsh.options.mesh.min_size = "5um"
elmer_renderer.gmsh.options.mesh.max_size = "50um"
[ ]:
# Render the design
elmer_renderer.render_design(
    open_pins=[("Q1", "coupler1"), ("Q1", "coupler2"), ("Q1", "readout")],
    skip_junctions=True,
)
[ ]:
# View the generated mesh
elmer_renderer.launch_gmsh_gui()
[ ]:
# Export the generated mesh
elmer_renderer.export_mesh()
[ ]:
# Add a solution setup to solve for the capacitance matrix
elmer_renderer.add_solution_setup("capacitance")
[ ]:
# Run the simulation in ElmerFEM
elmer_renderer.run("capacitance")
[ ]:
# Display the capacitnce matrix obtained after the simulation
elmer_renderer.capacitance_matrix
[ ]:
# Run this, and in the Gmsh window,
# Right click on an empty area, click on "Toggle mesh visibility"
# Next, go to: Tools -> Visibility, select "Physical groups" in drop down menu
# Select "Volume 2", click on apply
# On the left pane, click on "Post-processing", and select the views that you want to observe
elmer_renderer.display_post_processing_data()
[ ]:
# Export the capacitance matrix
elmer_renderer.save_capacitance_matrix("cap_matrix.txt")

# Close the elmer renderer
elmer_renderer.close()
[ ]:
%metal_heading 4. Perform LOM 2.0 Analysis
[ ]:
# Import necessary things for LOM 2.0 Analysis
import numpy as np
from qiskit_metal.analyses.quantization.lom_core_analysis import (
    CompositeSystem,
    Cell,
    Subsystem,
)
from scipy.constants import speed_of_light as c_light
import matplotlib.pyplot as plt

%matplotlib inline
[ ]:
# Load the saved capacitance matrix
cap_matrix = load_capacitance_matrix_from_file("cap_matrix.txt")
[ ]:
# Define cells
opt1 = dict(
    node_rename={
        "Q1_coupler1_connector_pad": "coupler1",
        "Q1_coupler2_connector_pad": "coupler2",
        "Q1_readout_connector_pad": "readout",
    },
    cap_mat=cap_matrix,
    ind_dict={("Q1_pad_top", "Q1_pad_bot"): 12},  # junction inductance in nH
    jj_dict={("Q1_pad_top", "Q1_pad_bot"): "j1"},
    cj_dict={("Q1_pad_top", "Q1_pad_bot"): 2},  # junction capacitance in fF
)
cell_1 = Cell(opt1)
[ ]:
# Define subsystems
# subsystem 1: Transmon
transmon = Subsystem(name="transmon1_sys", sys_type="TRANSMON", nodes=["j1"])

# subsystem 2: Coupler 1
q_opts = dict(
    f_res=7.4,  # resonator dressed frequency in GHz
    Z0=50,  # characteristic impedance in Ohm
    vp=0.404314 * c_light,  # phase velocity
)
coup1 = Subsystem(
    name="coup1_sys", sys_type="TL_RESONATOR", nodes=["coupler1"], q_opts=q_opts
)

# subsystem 3: Coupler 2
q_opts = dict(
    f_res=7.2,  # resonator dressed frequency in GHz
    Z0=50,  # characteristic impedance in Ohm
    vp=0.404314 * c_light,  # phase velocity
)
coup2 = Subsystem(
    name="coup2_sys", sys_type="TL_RESONATOR", nodes=["coupler2"], q_opts=q_opts
)

# subsystem 4: Readout
q_opts = dict(
    f_res=7,  # resonator dressed frequency in GHz
    Z0=50,  # characteristic impedance in Ohm
    vp=0.404314 * c_light,  # phase velocity
)
readout = Subsystem(
    name="readout_sys", sys_type="TL_RESONATOR", nodes=["readout"], q_opts=q_opts
)
[ ]:
# Define the composite system
composite_sys = CompositeSystem(
    subsystems=[transmon, coup1, coup2, readout],
    cells=[cell_1],
    grd_node="ground_plane",
    nodes_force_keep=["coupler1", "coupler2", "readout"],
)
[ ]:
# Get the circuit graph object
cg = composite_sys.circuitGraph()
print(cg)
[ ]:
# Create a hilbert space with the composite system
hilbertspace = composite_sys.create_hilbertspace()
print(hilbertspace)
[ ]:
# Add interaction between the subsystems
hilbertspace = composite_sys.add_interaction()

# Get the total hamiltonian of the composite system
hilbertspace.hamiltonian()
[ ]:
# Get the reults from the hamiltonian
# Qubit frequency
# Chi matrix (having anharmonicity and readout chi values)
hamiltonian_results = composite_sys.hamiltonian_results(hilbertspace, evals_count=30)
[ ]:
chi_df = hamiltonian_results["chi_in_MHz"].to_dataframe()
print(
    "Transmon frequency     :", hamiltonian_results["fQ_in_Ghz"]["transmon1_sys"], "GHz"
)
print("Transmon Anharmonicity :", chi_df["transmon1_sys"]["transmon1_sys"], "MHz")
print("Readou chi             :", chi_df["readout_sys"]["transmon1_sys"], "MHz")
[ ]:
# Get the coupling 'g' values between qubit and resonators
composite_sys.compute_gs().to_dataframe()
[ ]:
# Hamiltonian parameters for the transmon
transmon.h_params
[ ]:
# Close the Qiskit Metal GUI
gui.main_window.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