3. Capacitance matrix extraction for an Xmon qubit
3.1. Requirements
3.1.1. Software components
QTCAD
Gmsh
3.1.2. Geometry file
qtcad/examples/tutorials/meshes/xmon.py
3.1.3. Python script
qtcad/examples/tutorials/cap_xmon.py
3.1.4. References
3.2. Briefing
In this example, we extract the capacitance matrix for an Xmon qubit with coupling capacitors that are meant to couple the qubit to a readout line, XY control line, and a quantum bus resonator. For more details, please see [BKM+13]. The layout and dimensions for this example were kindly provided by Christopher Xu from Red Blue Quantum.
3.3. Geometry of the problem
In the geometry file qtcad/examples/tutorials/meshes/xmon.py
there are various parameters, such as strip
, gap
,
arm_length
, etc. Some of these parameters are labelled in the figures below




One important parameter is metal_t
, which controls the thickness of the metal. The geometry
file code handles both cases: when metal_t
is zero (metal repretented as sheets) or nonzero
(metal has some thickness).
3.4. Setting up the device and extracting the capacitance
The procedure for extracting the capacitance matrix is similar to the previous tutorial.
3.4.1. Header, input parameters, and file paths
# Capacitance matrix for an XMON with coupling capacitors.
#
# The layout and dimensions for this example were kindly provided by Christopher
# Xu, Red Blue Quantum.
#
# See the following article for more details on the operation of an Xmon qubit
# coupled to a readout line, XY control line, and a quantum bus resonator.
#
# Barends, Rami, et al. "Coherent Josephson qubit suitable for scalable quantum
# integrated circuits." Physical review letters 111.8 (2013): 080502.
from pathlib import Path
from time import time
import os
# import relevant modules of QTCAD
import qtcad.device.capacitance as cap
from qtcad.device.mesh3d import Mesh
from qtcad.device import Device
from qtcad.device import materials as mt
# directories and file paths
script_dir = Path(__file__).parent.resolve()
input_dir = script_dir / "meshes" # for mesh and raw geometry files
result_dir = script_dir / "output" / Path(__file__).stem # for results
fpath_mesh = input_dir / "xmon.msh" # mesh file
fpath_xao = input_dir / "xmon.xao" # raw geometry file (needed for adaptive meshing)
# code to check that the mesh and raw geometry files exist
if not os.path.isfile(fpath_mesh) or not os.path.isfile(fpath_xao):
raise Exception(
"Please run %s/xmon.py to generate the mesh and raw geometry files." % (input_dir)
)
3.4.2. Loading the initial mesh and defining the device
# scale in the Gmsh files
scale = 1e-6 # i.e. Gmsh files are in um
# parse the mesh
mesh = Mesh(scale, fpath_mesh)
# Create device from mesh.
dvc = Device(mesh)
# Create regions
dvc.new_region("substrate", mt.Si)
dvc.new_region("air", mt.vacuum)
# Set potential to zero on the surfaces of each conductor (including ground)
dvc.new_dirichlet_bnd("gnd", 0.0)
dvc.new_dirichlet_bnd("xmon_cross", 0.0)
dvc.new_dirichlet_bnd("xy_ctrl", 0.0)
dvc.new_dirichlet_bnd("readout", 0.0)
dvc.new_dirichlet_bnd("qbus", 0.0)
Note
A common mistake in creating the geometry files and the device in this type of problems
is forgetting to create a 3D physical group for "air"
or forgetting to define the
corresponding region. It is important to mesh and assign the correct medium to any region
of space that contains a significant electric field when voltages are applied to the signal
conductors.
Note
As previously mentioned previously, if we were to set metal_t
parameter in the mesh file to
a nonzero value, the conductors would have a nonzero thickness. The procedure followed in this
tutorial in this case is outlined below:
Define
"gnd"
,"xmon_cross"
,"xy_ctrl"
,"readout"
, and"qbus"
as the 2D physical group corresponding to the surfaces of the corresponding thick conductors. This allows us to use the last five lines in the code above to treat these objects as perfect electric conductors.Ensure that the inside of the thick conductors is not meshed. This is accomplished by the following lines in the geometry file:
if metal_t: air = gmsh.model.occ.cut( [(3, air)], [(3, gnd), (3, xy), (3, r_line), (3, qbus), (3, xmon_cross)], removeTool=False, )[0][0][1]
Meshing the inside of the conducting 3D objects can complicate the code and slow down the capacitance extraction.
3.4.3. Creating and running the capacitance solver
Next, we set up the solver parameters. For more more details on the adaptive algorithm parameters, see the previous tutorial and Capacitance Matrix pages.
######################################################################################
# setup and run the solver
######################################################################################
params = cap.SolverParams()
# directory where results will be stored
params.output_dir = result_dir
# tolerances
params.tol_rel = 0.05
params.tol_abs = 0
# name
params.name = Path(__file__).stem
The signal conductors include all perfect conductor boundaries, except “gnd”.
# Set up signal conductors
signal_conductors = ["xmon_cross", "xy_ctrl", "readout", "qbus"]
The following code initializes and executes the adaptive solver:
# initialize the solver
cap_solver = cap.Solver(dvc, signal_conductors, params, geo_file=fpath_xao)
# execute the solver algorithm
t0 = time()
c = cap_solver.solve()
dt = time() - t0
Finally, we display the final result of the solver:
######################################################################################
# Display the final results (in addition to the data in convergence files)
######################################################################################
cap_solver.print_cap(c, decimals=3)
print("Time taken: %.1f s" % dt)
Here, the print_cap
method is used, which is convenient for printing out matrices with
multiple rows and columns.
The resulting values are shown below:
xmon_cross xy_ctrl readout qbus
xmon_cross 1.014e-13 -1.832e-16 -3.075e-15 -3.078e-15
xy_ctrl -1.832e-16 4.878e-14 -6.343e-18 -1.610e-17
readout -3.075e-15 -6.343e-18 8.568e-14 -1.037e-16
qbus -3.078e-15 -1.610e-17 -1.037e-16 8.564e-14
3.5. Full code
__copyright__ = "Copyright 2022-2025, Nanoacademic Technologies Inc."
# Capacitance matrix for an XMON with coupling capacitors.
#
# The layout and dimensions for this example were kindly provided by Christopher
# Xu, Red Blue Quantum.
#
# See the following article for more details on the operation of an Xmon qubit
# coupled to a readout line, XY control line, and a quantum bus resonator.
#
# Barends, Rami, et al. "Coherent Josephson qubit suitable for scalable quantum
# integrated circuits." Physical review letters 111.8 (2013): 080502.
from pathlib import Path
from time import time
import os
# import relevant modules of QTCAD
import qtcad.device.capacitance as cap
from qtcad.device.mesh3d import Mesh
from qtcad.device import Device
from qtcad.device import materials as mt
# directories and file paths
script_dir = Path(__file__).parent.resolve()
input_dir = script_dir / "meshes" # for mesh and raw geometry files
result_dir = script_dir / "output" / Path(__file__).stem # for results
fpath_mesh = input_dir / "xmon.msh" # mesh file
fpath_xao = input_dir / "xmon.xao" # raw geometry file (needed for adaptive meshing)
# code to check that the mesh and raw geometry files exist
if not os.path.isfile(fpath_mesh) or not os.path.isfile(fpath_xao):
raise Exception(
"Please run %s/xmon.py to generate the mesh and raw geometry files." % (input_dir)
)
# scale in the Gmsh files
scale = 1e-6 # i.e. Gmsh files are in um
# parse the mesh
mesh = Mesh(scale, fpath_mesh)
# Create device from mesh.
dvc = Device(mesh)
# Create regions
dvc.new_region("substrate", mt.Si)
dvc.new_region("air", mt.vacuum)
# Set potential to zero on the surfaces of each conductor (including ground)
dvc.new_dirichlet_bnd("gnd", 0.0)
dvc.new_dirichlet_bnd("xmon_cross", 0.0)
dvc.new_dirichlet_bnd("xy_ctrl", 0.0)
dvc.new_dirichlet_bnd("readout", 0.0)
dvc.new_dirichlet_bnd("qbus", 0.0)
######################################################################################
# setup and run the solver
######################################################################################
params = cap.SolverParams()
# directory where results will be stored
params.output_dir = result_dir
# tolerances
params.tol_rel = 0.05
params.tol_abs = 0
# name
params.name = Path(__file__).stem
# Set up signal conductors
signal_conductors = ["xmon_cross", "xy_ctrl", "readout", "qbus"]
# initialize the solver
cap_solver = cap.Solver(dvc, signal_conductors, params, geo_file=fpath_xao)
# execute the solver algorithm
t0 = time()
c = cap_solver.solve()
dt = time() - t0
######################################################################################
# Display the final results (in addition to the data in convergence files)
######################################################################################
cap_solver.print_cap(c, decimals=3)
print("Time taken: %.1f s" % dt)