Tutorial 7: Simulating Qiskit Metal design objects with palace using SQDMetal#

In this tutorial, we will cover how to do electrostatic and eigenmode simulations of a qubit-cavity system using palace.

Requirements:

  • ☐ Ensure that SQDMetal is installed in your environment.

  • ☐ Ensure that palace is installed in your environment. Instructions here.

[1]:
%load_ext autoreload
%autoreload 2
%matplotlib inline
[2]:
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
os.environ["PMIX_MCA_gds"]="hash"

import gmsh
gmsh.initialize()

os.makedirs('sims', exist_ok=True)

Define the path to the palace executable

[3]:
path_to_palace = '/Users/shanto/LFL/palace/build/bin/palace'

Electrostatic Simulation#

We will be learning how to extract the capacitance matrix from an electrostatic simulation.

For a qubit-claw system#

Importing the relevant modules

[4]:
import qiskit_metal as metal
from qiskit_metal import designs, draw
from qiskit_metal import MetalGUI, Dict, open_docs
from qiskit_metal.toolbox_metal import math_and_overrides
from qiskit_metal.qlibrary.core import QComponent
from collections import OrderedDict
from qiskit_metal.qlibrary.tlines.meandered import RouteMeander
from qiskit_metal.qlibrary.tlines.straight_path import RouteStraight
from qiskit_metal.qlibrary.tlines.pathfinder import RoutePathfinder
from qiskit_metal.qlibrary.terminations.launchpad_wb import LaunchpadWirebond
from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround
from qiskit_metal.qlibrary.terminations.short_to_ground import ShortToGround
from qiskit_metal.qlibrary.couplers.coupled_line_tee import CoupledLineTee
from qiskit_metal.qlibrary.qubits.transmon_cross import TransmonCross
import pandas as pd

We want to get the cap matrix for a system with TransmonCross, claw and ground (similar to the simulations we ran to build SQuADDS_DB)

[5]:
from squadds import SQuADDS_DB, Analyzer
FutureWarning: Module 'pyaedt' has become an alias to the new package structure. Please update you imports to use the new architecture based on 'ansys.aedt.core'. In addition, some files have been renamed to follow the PEP 8 naming convention. The old structure and file names will be deprecated in future versions, see https://aedt.docs.pyansys.com/version/stable/release_1_0.html
[6]:
# First, get a design from SQuADDS
db = SQuADDS_DB()
db.select_system("qubit")
db.select_qubit("TransmonCross")
df = db.create_system_df()
analyzer = Analyzer(db)

# Define target parameters for your qubit
target_params = {
    "qubit_frequency_GHz": 4.2,  # Example value
    "anharmonicity_MHz": -200    # Example value
}

# Find the closest design
results = analyzer.find_closest(target_params, num_top=1)
best_device = results.iloc[0]

# Get the design options
qubit_options = best_device["design_options"]
[7]:
# Set up chip design as planar
design = designs.DesignPlanar({}, overwrite_enabled=True)


# Create GUI
gui = MetalGUI(design)

# Qubit and a claw
# Create the TransmonCross object with the modified options
# Update only the position parameters
qubit_options["pos_x"] = '0.6075mm'
qubit_options["pos_y"] = '-1.464'
Q1 = TransmonCross(design, 'Q1', options=qubit_options)

gui.rebuild()
design.rebuild()
gui.autoscale()
gui.screenshot('sims/qubit.png')
02:50PM 05s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  WARNING: Populating font family aliases took 284 ms. Replace uses of missing font family "Courier" with one that exists to avoid this cost.

02:50PM 05s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f971d018da0; contentView=<QNSView: 0x7f971d018600; QCocoaWindow(0x7f971d0184f0, window=QWidgetWindow(0x7f971d017f90, name="MainWindowPlotWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

02:50PM 05s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f971d022660; contentView=<QNSView: 0x7f971d021ec0; QCocoaWindow(0x7f971d021db0, window=QWidgetWindow(0x7f971d021830, name="ElementsWindowWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

02:50PM 05s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f971d12a350; contentView=<QNSView: 0x7f971d129970; QCocoaWindow(0x7f971d129860, window=QWidgetWindow(0x7f971d129360, name="MainWindowWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

02:50PM 05s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f971cfabb30; contentView=<QNSView: 0x7f971cfab390; QCocoaWindow(0x7f971cfab280, window=QWidgetWindow(0x7f971cfaad20, name="NetListWindowWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

../../_images/source_tutorials_Tutorial-7_Simulate_designs_with_palace_12_1.png

Call the SQDMetal objects. Change the hyper-parameters as needed for a more accurate simulation.

[8]:
from SQDMetal.PALACE.Capacitance_Simulation import PALACE_Capacitance_Simulation

user_defined_options = {
                "mesh_refinement": 0,                             #refines mesh in PALACE - essetially divides every mesh element in half
                "dielectric_material": "silicon",                  #choose dielectric material - 'silicon' or 'sapphire'
                "solver_order": 1,                                 #increasing solver order increases accuracy of simulation, but significantly increases sim time
                "solver_tol": 1.0e-8,                              #error residual tolerance for iterative solver
                "solver_maxits": 500,                              #number of solver iterations
                "mesh_max": 120e-6,                                #maxiumum element size for the mesh in mm
                "mesh_sampling": 150,                              #number of points to mesh along a geometry
                "fillet_resolution":12,                            #number of vertices per quarter turn on a filleted path
                "num_cpus": 10,                                      #number of CPU cores to use for simulation
                "palace_dir":path_to_palace
                }
[9]:
#Creat the Palace Eigenmode simulation
cap_sim = PALACE_Capacitance_Simulation(name = 'transmon_cross_cap_sim',                                 #name of simulation
                                        metal_design = design,                                      #feed in qiskit metal design
                                        sim_parent_directory = "sims/",            #choose directory where mesh file, config file and HPC batch file will be saved
                                        mode = 'simPC',                                             #choose simulation mode 'HPC' or 'simPC'
                                        meshing = 'GMSH',                                           #choose meshing 'GMSH' or 'COMSOL'
                                        user_options = user_defined_options,                        #provide options chosen above
                                        view_design_gmsh_gui = False,                               #view design in GMSH gui
                                        create_files = True,
                                        )                                        #create mesh, config and HPC batch files

cap_sim.add_metallic(1, threshold=1e-10, fuse_threshold=1e-10)
cap_sim.add_ground_plane(threshold=1e-10)

To generate a fine mesh around our region of interest, we can use the fine_mesh_in_rectangle method by first getting the bounds of the region of interest.

[10]:
bounds = design.components["Q1"].qgeometry_bounds()
bounds
[10]:
array([ 0.3675, -1.704 ,  0.9277, -1.224 ])
[11]:
#Fine-mesh the transmon cross qubit region
cap_sim.fine_mesh_in_rectangle(bounds[0]*1e-3, bounds[1]*1e-3, bounds[2]*1e-3, bounds[3]*1e-3, mesh_sampling=100, mesh_min=10e-3, mesh_max=125e-3)
[12]:
cap_sim.prepare_simulation()

You can check to see if all the metal components are correctly identified

[13]:
cap_sim.display_conductor_indices()
[13]:
../../_images/source_tutorials_Tutorial-7_Simulate_designs_with_palace_21_0.svg

Similarly, you can verify the mesh is correct by visualizing the mesh

[14]:
from SQDMetal.PALACE.Utilities.GMSH_Navigator import GMSH_Navigator

gmsh_nav = GMSH_Navigator(cap_sim.path_mesh)
gmsh_nav.open_GUI()

If all looks good, you can run the simulation

[15]:
cap_matrix =cap_sim.run()
>> /opt/homebrew/bin/mpirun -n 10 /Users/shanto/LFL/palace/build/bin/palace-arm64.bin transmon_cross_cap_sim.json

_____________     _______
_____   __   \____ __   /____ ____________
____   /_/  /  __ ` /  /  __ ` /  ___/  _ \
___   _____/  /_/  /  /  /_/  /  /__/  ___/
  /__/     \___,__/__/\___,__/\_____\_____/

Git changeset ID: v0.13.0-117-g748660c
Running with 10 MPI processes
Device configuration: cpu
Memory configuration: host-std
libCEED backend: /cpu/self/xsmm/blocked

Added 369 elements in 2 iterations of local bisection for under-resolved interior boundaries
Added 7772 duplicate vertices for interior boundaries in the mesh
Added 16409 duplicate boundary elements for interior boundaries in the mesh
Added 4040 boundary elements for material interfaces to the mesh
Finished partitioning mesh into 10 subdomains

Characteristic length and time scales:
 L₀ = 1.080e-02 m, t₀ = 3.602e-02 ns

Mesh curvature order: 1
Mesh bounding box:
 (Xmin, Ymin, Zmin) = (-5.400e-03, -3.600e-03, -7.500e-04) m
 (Xmax, Ymax, Zmax) = (+5.400e-03, +3.600e-03, +7.500e-04) m

Parallel Mesh Stats:

                minimum     average     maximum       total
 vertices          7422        7920        8388       79201
 edges            48320       49915       51242      499150
 faces            79214       80632       81980      806329
 elements         38316       38637       39385      386378
 neighbors            2           4           7

            minimum     maximum
 h      0.000552426   0.0217216
 kappa      1.01738     11.1252

Configuring Dirichlet BC at attributes:
 7, 1-3

Assembling system matrices, number of global unknowns:
 H1 (p = 1): 79201, ND (p = 1): 499150, RT (p = 1): 806329
 Operator assembly level: Partial
 Mesh geometries:
  Tetrahedron: P = 6, Q = 4 (quadrature order = 2)

Assembling multigrid hierarchy:
 Level 0 (p = 1): 79201 unknowns, 1105237 NNZ

Computing electrostatic fields for 3 terminal boundaries

It 1/3: Index = 1 (elapsed time = 4.20e-08 s)

  Residual norms for PCG solve
  0 KSP residual norm ||r||_B = 1.990521e+01
  1 KSP residual norm ||r||_B = 1.819635e+00
  2 KSP residual norm ||r||_B = 2.004853e-01
  3 KSP residual norm ||r||_B = 3.448215e-02
  4 KSP residual norm ||r||_B = 5.786581e-03
  5 KSP residual norm ||r||_B = 9.102787e-04
  6 KSP residual norm ||r||_B = 1.491365e-04
  7 KSP residual norm ||r||_B = 2.723162e-05
  8 KSP residual norm ||r||_B = 4.884593e-06
  9 KSP residual norm ||r||_B = 8.463240e-07
PCG solver converged in 9 iterations (avg. reduction factor: 1.236e-01)
 Sol. ||V|| = 1.770460e+02 (||RHS|| = 1.249420e+02)
 Field energy E = 1.624e+00 J
 Updating solution error estimates
 Wrote fields to disk for terminal 1

It 2/3: Index = 2 (elapsed time = 1.94e+00 s)

  Residual norms for PCG solve
  0 KSP residual norm ||r||_B = 8.173841e-01
  1 KSP residual norm ||r||_B = 8.983963e-02
  2 KSP residual norm ||r||_B = 1.454760e-02
  3 KSP residual norm ||r||_B = 2.128182e-03
  4 KSP residual norm ||r||_B = 3.333766e-04
  5 KSP residual norm ||r||_B = 6.577703e-05
  6 KSP residual norm ||r||_B = 1.180018e-05
  7 KSP residual norm ||r||_B = 1.987690e-06
  8 KSP residual norm ||r||_B = 3.601812e-07
  9 KSP residual norm ||r||_B = 6.149758e-08
PCG solver converged in 9 iterations (avg. reduction factor: 1.164e-01)
 Sol. ||V|| = 1.812398e+01 (||RHS|| = 1.571719e+01)
 Field energy E = 4.756e-02 J
 Updating solution error estimates
 Wrote fields to disk for terminal 2

It 3/3: Index = 3 (elapsed time = 3.66e+00 s)

  Residual norms for PCG solve
  0 KSP residual norm ||r||_B = 1.826447e+00
  1 KSP residual norm ||r||_B = 2.466585e-01
  2 KSP residual norm ||r||_B = 4.728945e-02
  3 KSP residual norm ||r||_B = 7.134869e-03
  4 KSP residual norm ||r||_B = 1.244552e-03
  5 KSP residual norm ||r||_B = 2.185094e-04
  6 KSP residual norm ||r||_B = 3.939749e-05
  7 KSP residual norm ||r||_B = 7.145503e-06
  8 KSP residual norm ||r||_B = 1.180785e-06
  9 KSP residual norm ||r||_B = 2.068803e-07
PCG solver converged in 9 iterations (avg. reduction factor: 1.260e-01)
 Sol. ||V|| = 3.791320e+01 (||RHS|| = 2.584766e+01)
 Field energy E = 2.559e-02 J
 Updating solution error estimates
 Wrote fields to disk for terminal 3

Completed 0 iterations of adaptive mesh refinement (AMR):
 Indicator norm = 5.098e-01, global unknowns = 79201
 Max. iterations = 0, tol. = 1.000e-02

Elapsed Time Report (s)           Min.        Max.        Avg.
==============================================================
Initialization                   8.096       8.106       8.101
Operator Construction            0.401       0.419       0.411
Linear Solve                     0.130       0.153       0.139
  Setup                          0.020       0.027       0.021
  Preconditioner                 0.498       0.532       0.519
Estimation                       0.072       0.093       0.083
  Construction                   5.676       5.676       5.676
  Solve                          1.764       1.773       1.766
Postprocessing                   0.371       0.393       0.380
Disk IO                          4.590       4.615       4.601
--------------------------------------------------------------
Total                           21.794      21.803      21.800

Error in plotting: 'Data array (V) not present in this dataset.'
[16]:
cdf = pd.DataFrame(cap_matrix)

# get rid of the first column
cdf = cdf.iloc[:, 1:]

# assigning the columns and indices based on our geometry
cdf.columns = ["ground", "claw", "cross"]
cdf.index = ["ground", "claw", "cross"]
cdf
[16]:
ground claw cross
ground 8.621504e-12 -2.458660e-13 -1.239444e-13
claw -2.458660e-13 2.524815e-13 -4.830456e-15
cross -1.239444e-13 -4.830456e-15 1.358696e-13

The above dataframe is the capacitance matrix for our system in Farads.

To get a more accurate result - consider a higher order solver and a finer mesh.


Eigenmodal Simulation#

For a qubit-cavity system#

[17]:
# Import useful packages
import qiskit_metal as metal
from qiskit_metal import designs, draw
from qiskit_metal import MetalGUI, Dict, open_docs
from qiskit_metal.toolbox_metal import math_and_overrides
from qiskit_metal.qlibrary.core import QComponent
from collections import OrderedDict
from squadds.components.qubits import TransmonCross
from qiskit_metal.qlibrary.tlines.meandered import RouteMeander
from qiskit_metal.qlibrary.tlines.straight_path import RouteStraight
from qiskit_metal.qlibrary.tlines.pathfinder import RoutePathfinder
from qiskit_metal.qlibrary.terminations.launchpad_wb import LaunchpadWirebond
from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround
from qiskit_metal.qlibrary.terminations.short_to_ground import ShortToGround
from qiskit_metal.qlibrary.couplers.coupled_line_tee import CoupledLineTee

import numpy as np
import matplotlib.pyplot as plt

For this example lets use an example geometry from Tutorial 5 and build the design with SQDMetal

[18]:
db.unselect_all()
db.select_system(["cavity_claw", "qubit"])
db.select_qubit("TransmonCross")
db.select_cavity_claw("RouteMeander")
db.select_resonator_type("quarter")
df = db.create_system_df()

analyzer.reload_db()
[19]:
target_params = {
                "qubit_frequency_GHz": 3.7,
                "resonator_type":"quarter",
                "anharmonicity_MHz": -210,
                "g_MHz": 100 # should provide a big punchout shift
                }

# computing the cavity frequency desired as per the design requirements
target_params["cavity_frequency_GHz"] = 2*(target_params["qubit_frequency_GHz"]+target_params["anharmonicity_MHz"]/1000)

results = analyzer.find_closest(target_params=target_params,num_top=1,metric="Euclidean")
results
Time taken to add the coupled H params: 4.424401044845581 seconds
[19]:
index_qc PI_qubit date_created_qubit group_qubit institution_qubit uploader_qubit design_options_qubit design_tool_qubit claw_to_claw claw_to_ground ... units_cavity_claw renderer_options_cavity_claw setup_cavity_claw simulator_cavity_claw design_options EC EJ qubit_frequency_GHz anharmonicity_MHz g_MHz
12514 1900 Eli Levenson-Falk, PhD 2023-09-20-142549 LFL USC Andre Kuo {'aedt_hfss_capacitance': 0, 'aedt_hfss_induct... qiskit-metal 102.50358 94.66779 ... Hz None {'basis_order': 1, 'max_delta_f': 0.05, 'max_p... Ansys HFSS {'cavity_claw_options': {'coupler_type': 'CLT'... 0.180488 10.278024 3.66213 -205.109839 98.903433

1 rows × 41 columns

[20]:
data_qubit = analyzer.get_qubit_options(results)
data_cpw = analyzer.get_cpw_options(results)
data_coupler = analyzer.get_coupler_options(results)
LJs = analyzer.get_Ljs(results) # in nH

Creating a new design and gui object since we are running this in the same notebook.

[ ]:
# First delete components
design.delete_all_components()

# Close the GUI
gui.main_window.close()

# Forced garbage collection
gui = None
design = None
[23]:
design = designs.DesignPlanar({}, overwrite_enabled=True)
gui = MetalGUI(design)


# Set up chip dimensions
design.chips.main.size.size_x = '4.6mm'
design.chips.main.size.size_y = '2.4mm'
design.chips.main.size.size_z = '-280um'
design.chips.main.size.center_x = '0mm'
design.chips.main.size.center_y = '-1mm'

02:51PM 19s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f97382d8840; contentView=<QNSView: 0x7f971d1b05a0; QCocoaWindow(0x7f971e2c8c30, window=QWidgetWindow(0x7f97381cdac0, name="MainWindowPlotWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

02:51PM 19s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f9719fed4b0; contentView=<QNSView: 0x7f9719fecf40; QCocoaWindow(0x7f9719fece90, window=QWidgetWindow(0x7f972d533470, name="ElementsWindowWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

02:51PM 19s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f972b3eadd0; contentView=<QNSView: 0x7f972b3ea650; QCocoaWindow(0x7f972b3ea540, window=QWidgetWindow(0x7f972b3ea040, name="MainWindowWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

02:51PM 19s CRITICAL [_qt_message_handler]: line: 0, func: None(), file: None  CRITICAL: <QNSWindow: 0x7f9719ff4b00; contentView=<QNSView: 0x7f9719ff4590; QCocoaWindow(0x7f9719ff44e0, window=QWidgetWindow(0x7f972d53b930, name="NetListWindowWindow"))>> has active key-value observers (KVO)! These will stop working now that the window is recreated, and will result in exceptions when the observers are removed. Break in QCocoaWindow::recreateWindowIfNeeded to debug.

Lets create the qubit with a junction and a claw

Qubit (with a junction) and Claw#

[24]:
from SQDMetal.Comps.Xmon import Xmon
from SQDMetal.Comps.Junctions import JunctionDolanPinStretch
from SQDMetal.Comps.Capacitors import CapacitorProngPin
[25]:
# Calculate vBar_gap and hBar_gap
def extract_um(value: str) -> float:
    """Extract float from '30um'."""
    return float(value.replace('um', ''))

# Unpack parameters from data_qubit
cross_width = extract_um(data_qubit['cross_width'][0])
cross_length = extract_um(data_qubit['cross_length'][0])
cross_gap = extract_um(data_qubit['cross_gap'][0])

# Now create the Xmon
xmon = Xmon(
    design,
    'xmon',
    options=Dict(
        pos_x = '0.375mm',
        pos_y = '-1.3',
        hBar_width = f"{cross_width}um",
        vBar_width = f"{cross_width}um",
        vBar_gap = f"{cross_gap}um",
        hBar_gap = f"{cross_gap}um",
        cross_width = f"{2*cross_length}um",
        cross_height = f"{2*cross_length}um",
        gap_up = data_qubit['cross_gap'][0],
        gap_left = data_qubit['cross_gap'][0],
        gap_right = data_qubit['cross_gap'][0],
        gap_down = data_qubit['cross_gap'][0]
    )
)
[26]:
# Claw
prong_length = extract_um(data_qubit['claw_length'][0]) - extract_um(data_qubit['claw_width'][0])
pin_gap_side = extract_um(data_qubit['claw_gap'][0])+extract_um(data_qubit['cross_gap'][0])+extract_um(data_qubit['ground_spacing'][0])

claw = CapacitorProngPin(
    design,
    'claw',
    options=Dict(
        pin_inputs=Dict(start_pin=Dict(component='xmon', pin='up')),
        prong_width = data_qubit['claw_width'][0],
        pad_thickness = data_qubit['claw_width'][0],
        gap_front = data_qubit['cross_gap'][0],
        gap_back = data_qubit['claw_gap'][0],
        gap_side = data_qubit['claw_gap'][0],
        prong_length = f"{prong_length}um",
        pin_gap_side = f"{pin_gap_side}um"
    )
)

[27]:
# Junction
junction = JunctionDolanPinStretch(design, 'junction', options=Dict(pin_inputs=Dict(start_pin=Dict(component=f'xmon',pin='right')),
                                                         dist_extend=data_qubit['cross_gap'][0],
                                                         layer=2,
                                                         finger_width='0.4um', t_pad_size='0.385um',
                                                         squid_width='5.4um', prong_width='0.9um'))


Resonator and Feedline#

Now lets add the resonator and feedline

[28]:
# Lauchpad 1
x1 = '-2mm'
y1 = '0mm'
launch_options1 = dict(chip='main', pos_x=x1, pos_y=y1, orientation='360', lead_length='30um', pad_height='103um',
                      pad_width='103um', pad_gap='60um', trace_width = data_cpw["trace_width"], trace_gap = data_cpw["trace_gap"])
LP1 = LaunchpadWirebond(design, 'LP1', options = launch_options1)

# Launchpad 2
x2 = '2mm'
y1 = '0mm'
launch_options2 = dict(chip='main', pos_x=x2, pos_y=y1, orientation='180', lead_length='30um', pad_height='103um',
                      pad_width='103um', pad_gap='60um', trace_width = data_cpw["trace_width"], trace_gap = data_cpw["trace_gap"])
LP2 = LaunchpadWirebond(design, 'LP2', options = launch_options2)

# Using path finder to connect the two launchpads
feedline = RoutePathfinder(design, 'feedline', options = dict(chip='main', trace_width = data_cpw["trace_width"],
                                            trace_gap = data_cpw["trace_gap"],
                                            fillet='90um',
                                            hfss_wire_bonds = True,
                                            lead=dict(end_straight='0.1mm'),
                                            pin_inputs=Dict(
                                                start_pin=Dict(
                                                    component='LP1',
                                                    pin='tie'),
                                                end_pin=Dict(
                                                    component='LP2',
                                                    pin='tie')
                                            )))

[29]:
#open to ground for resonator
otg1 = OpenToGround(design, 'otg1', options=dict(chip='main', pos_x='-0.2mm',  pos_y='-40um', orientation = 180))


# Resonator and feedline gap width (W) and center conductor width (S)
design.variables['cpw_width'] = data_cpw["trace_width"]
design.variables['cpw_gap'] = data_cpw["trace_gap"]

# Use RouteMeander to fix the total length of the resonator
res1 = RouteMeander(design, 'resonator',  Dict(
        trace_width ='10um',
        trace_gap ='6um',
        total_length='3.7mm',
        hfss_wire_bonds = False,
        fillet='99.9 um',
        lead = dict(start_straight='300um'),
        pin_inputs=Dict(
        start_pin=Dict(component= 'otg1', pin= 'open'),
        end_pin=Dict(component= 'claw', pin= 'a')), ))

Check the design

[30]:
# rebuild the GUI
design.rebuild()
gui.rebuild()
gui.autoscale()
gui.screenshot('sims/qubit-cavity.png')
../../_images/source_tutorials_Tutorial-7_Simulate_designs_with_palace_46_0.png

Define the hyper-parameters for the eigenmode simulation

[31]:
from SQDMetal.PALACE.Eigenmode_Simulation import PALACE_Eigenmode_Simulation

#Eigenmode Simulation Options
user_defined_options = {
                 "mesh_refinement":  0,                             #refines mesh in PALACE - essetially divides every mesh element in half
                 "dielectric_material": "silicon",                  #choose dielectric material - 'silicon' or 'sapphire'
                 "starting_freq": 2e9,                              #starting frequency in Hz
                 "number_of_freqs": 6,                              #number of eigenmodes to find
                 "solns_to_save": 6,                                #number of electromagnetic field visualizations to save
                 "solver_order": 1,                                 #increasing solver order increases accuracy of simulation, but significantly increases sim time
                 "solver_tol": 1.0e-3,                              #error residual tolerance foriterative solver
                 "solver_maxits": 3,                              #number of solver iterations
                 "mesh_max": 120e-3,                                #maxiumum element size for the mesh in mm
                 "mesh_min": 10e-3,                                 #minimum element size for the mesh in mm
                 "mesh_sampling": 130,                              #number of points to mesh along a geometry
                 "fillet_resolution":12,
                 "num_cpus": 10,                                      #number of CPU cores to use for simulation
                 "palace_dir":path_to_palace
                }

#Creat the Palace Eigenmode simulation
eigen_sim = PALACE_Eigenmode_Simulation(name ='qubit-cavity-eig-test',                              #name of simulation
                                        metal_design = design,                                      #feed in qiskit metal design
                                        sim_parent_directory = "sims/",            #choose directory where mesh file, config file and HPC batch file will be saved
                                        mode = 'simPC',                                               #choose simulation mode 'HPC' or 'simPC'
                                        meshing = 'GMSH',                                         #choose meshing 'GMSH' or 'COMSOL'
                                        user_options = user_defined_options,                        #provide options chosen above
                                        view_design_gmsh_gui = False,                               #view design in GMSH gui
                                        create_files = True)                                        #create mesh, config and HPC batch files

Assigning the materials to the interfaces, add ports to the design, and add some mesh.

[32]:
from SQDMetal.Utilities.Materials import MaterialInterface

eigen_sim.add_metallic(1, threshold=1e-10, fuse_threshold=1e-10)
eigen_sim.add_ground_plane(threshold=1e-10)

#Fine-mesh the transmon cross qubit region
eigen_sim.fine_mesh_in_rectangle(0.2875e-3, -1.2e-3, 0.63e-3, -1.72e-3, min_size=15e-6, max_size=120e-6)

#Add in the RF ports
eigen_sim.create_port_CPW_on_Launcher('LP1', 20e-6)
eigen_sim.create_port_CPW_on_Launcher('LP2', 20e-6)
eigen_sim.create_port_JosephsonJunction('junction', L_J=LJs[0]*1e-9, C_J=10e-15) # Guessing the C_J value really

# #Fine-mesh routed paths
eigen_sim.fine_mesh_around_comp_boundaries(['feedline', 'resonator'], min_size=25e-6, max_size=250e-6)
eigen_sim.fine_mesh_around_comp_boundaries(['xmon'], min_size=14e-6, max_size=75e-6)

eigen_sim.setup_EPR_interfaces(metal_air=MaterialInterface('Aluminium-Vacuum'), substrate_air=MaterialInterface('Silicon-Vacuum'), substrate_metal=MaterialInterface('Silicon-Aluminium'))
[33]:
eigen_sim.prepare_simulation()

Checking the meshfile

[ ]:
gmsh_nav = GMSH_Navigator(eigen_sim.path_mesh)
gmsh_nav.open_GUI()

If all looks good, lets run the simulation

NOTE: If you are using a palace build that is from 2025, you will need to remove the Excitation key from the LumpedPort boundary condition in the sim_config.json file so please execute the following cell.

If you are using a palace build that is from 2024 or older, you should skip this cell.

[ ]:
import json

with open(eigen_sim._sim_config, 'r') as file:
    sim_config_dict = json.load(file)

del sim_config_dict["Boundaries"]["LumpedPort"][0]["Excitation"]

with open(eigen_sim._sim_config, 'w') as file:
    json.dump(sim_config_dict, file, indent=4)
[34]:
eigen_sim.run()
>> /opt/homebrew/bin/mpirun -n 10 /Users/shanto/LFL/palace/build/bin/palace-arm64.bin qubit-cavity-eig-test.json

_____________     _______
_____   __   \____ __   /____ ____________
____   /_/  /  __ ` /  /  __ ` /  ___/  _ \
___   _____/  /_/  /  /  /_/  /  /__/  ___/
  /__/     \___,__/__/\___,__/\_____\_____/

Git changeset ID: v0.13.0-117-g748660c
Running with 10 MPI processes
Device configuration: cpu
Memory configuration: host-std
libCEED backend: /cpu/self/xsmm/blocked

Added 2574 elements in 2 iterations of local bisection for under-resolved interior boundaries
Added 5333 duplicate vertices for interior boundaries in the mesh
Added 12701 duplicate boundary elements for interior boundaries in the mesh
Added 1550 boundary elements for material interfaces to the mesh
Finished partitioning mesh into 10 subdomains

Characteristic length and time scales:
 L₀ = 5.520e-03 m, t₀ = 1.841e-02 ns

Mesh curvature order: 1
Mesh bounding box:
 (Xmin, Ymin, Zmin) = (-2.760e-03, -2.440e-03, -2.800e-04) m
 (Xmax, Ymax, Zmax) = (+2.760e-03, +4.400e-04, +2.800e-04) m

Parallel Mesh Stats:

                minimum     average     maximum       total
 vertices          2786        3522        3859       35223
 edges            18749       20919       22124      209195
 faces            31110       32653       33699      326538
 elements         15011       15256       15457      152568
 neighbors            2           4           5

            minimum     maximum
 h      0.000513927   0.0271869
 kappa      1.01967     157.435

Configuring Robin absorbing BC (order 1) at attributes:
 13

Configuring Robin impedance BC for lumped ports at attributes:
 5: Rs = 6.667e+01 Ω/sq, n = (+0.0, +0.0, +1.0)
 6: Rs = 6.667e+01 Ω/sq, n = (+0.0, +0.0, -1.0)
 7: Rs = 6.667e+01 Ω/sq, n = (-0.0, +0.0, +1.0)
 8: Rs = 6.667e+01 Ω/sq, n = (+0.0, +0.0, -1.0)
 9: Ls = 5.725e-09 H/sq, Cs = 2.778e-14 F/sq, n = (+0.0, +0.0, +1.0)

Configuring lumped port circuit properties:
 Index = 1: R = 5.000e+01 Ω
 Index = 2: R = 5.000e+01 Ω
 Index = 3: L = 1.590e-08 H, C = 1.000e-14 F

Configuring lumped port excitation source term at attributes:
 5: Index = 1
 6: Index = 1

Configuring Dirichlet PEC BC at attributes:
 1-4

Assembling system matrices, number of global unknowns:
 H1 (p = 1): 35223, ND (p = 1): 209195, RT (p = 1): 326538
 Operator assembly level: Partial
 Mesh geometries:
  Tetrahedron: P = 6, Q = 4 (quadrature order = 2)

Configuring SLEPc eigenvalue solver:
 Scaling γ = 4.711e+02, δ = 1.089e-05
 Configuring divergence-free projection
 Using random starting vector
 Shift-and-invert σ = 2.000e+00 GHz (2.314e-01)

Assembling multigrid hierarchy:
 Level 0 (p = 1): 209195 unknowns, 3111237 NNZ
 Level 0 (auxiliary) (p = 1): 35223 unknowns, 467972 NNZ

#PETSc Option Table entries:
-eps_monitor # (source: code)
#End of PETSc Option Table entries

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.430279e+03
1 (restart 0) KSP residual norm 1.025289e-01
FGMRES solver converged in 1 iteration (avg. reduction factor: 7.168e-05)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.363427e+02
1 (restart 0) KSP residual norm 4.284830e-01
2 (restart 0) KSP residual norm 5.323492e-02
FGMRES solver converged in 2 iterations (avg. reduction factor: 1.258e-02)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 4.995177e+01
1 (restart 0) KSP residual norm 2.962309e-01
2 (restart 0) KSP residual norm 1.384106e-01
3 (restart 0) KSP residual norm 4.256018e-03
FGMRES solver converged in 3 iterations (avg. reduction factor: 4.400e-02)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.399569e+02
1 (restart 0) KSP residual norm 1.230768e+00
2 (restart 0) KSP residual norm 5.933160e-01
3 (restart 0) KSP residual norm 2.217576e-02
FGMRES solver converged in 3 iterations (avg. reduction factor: 4.521e-02)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.244339e+02
1 (restart 0) KSP residual norm 1.137913e+00
2 (restart 0) KSP residual norm 3.299754e-01
3 (restart 0) KSP residual norm 1.271091e-02
FGMRES solver converged in 3 iterations (avg. reduction factor: 4.675e-02)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.330694e+02
1 (restart 0) KSP residual norm 6.423500e+00
2 (restart 0) KSP residual norm 2.903788e+00
3 (restart 0) KSP residual norm 5.072627e-02
FGMRES solver converged in 3 iterations (avg. reduction factor: 6.015e-02)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.177260e+02
1 (restart 0) KSP residual norm 1.965855e+01
2 (restart 0) KSP residual norm 1.019226e+01
3 (restart 0) KSP residual norm 4.281215e-02
FGMRES solver converged in 3 iterations (avg. reduction factor: 7.138e-02)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 7.166516e+01
1 (restart 0) KSP residual norm 1.882151e+01
2 (restart 0) KSP residual norm 8.034346e+00
3 (restart 1) KSP residual norm 8.581616e-02
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.062e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.197e-03 (norm(b) = 7.167e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 4.438828e+01
1 (restart 0) KSP residual norm 3.915629e+01
2 (restart 0) KSP residual norm 2.771825e+01
3 (restart 1) KSP residual norm 1.376060e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.458e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 3.100e-03 (norm(b) = 4.439e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.881353e+01
1 (restart 0) KSP residual norm 1.794439e+01
2 (restart 0) KSP residual norm 1.621458e+01
3 (restart 1) KSP residual norm 2.216238e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.275e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.178e-02 (norm(b) = 1.881e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 7.437849e+01
1 (restart 0) KSP residual norm 4.763870e+01
2 (restart 0) KSP residual norm 2.423142e+01
3 (restart 1) KSP residual norm 1.437091e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.246e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.932e-03 (norm(b) = 7.438e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.741477e+01
1 (restart 0) KSP residual norm 1.922261e+01
2 (restart 0) KSP residual norm 1.103699e+01
3 (restart 1) KSP residual norm 1.051296e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.411e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 2.810e-03 (norm(b) = 3.741e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 5.816988e+01
1 (restart 0) KSP residual norm 1.515933e+01
2 (restart 0) KSP residual norm 4.254473e+00
3 (restart 1) KSP residual norm 1.630771e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.410e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 2.803e-03 (norm(b) = 5.817e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 9.802764e+01
1 (restart 0) KSP residual norm 1.492573e+01
2 (restart 0) KSP residual norm 3.576847e+00
3 (restart 1) KSP residual norm 2.360518e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.340e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 2.408e-03 (norm(b) = 9.803e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 7.515375e+01
1 (restart 0) KSP residual norm 2.017880e+01
2 (restart 0) KSP residual norm 1.033416e+01
3 (restart 1) KSP residual norm 2.479146e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.489e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 3.299e-03 (norm(b) = 7.515e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.893357e+01
1 (restart 0) KSP residual norm 1.684603e+01
2 (restart 0) KSP residual norm 6.739747e+00
3 (restart 1) KSP residual norm 3.242989e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.238e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.121e-02 (norm(b) = 2.893e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 6.275288e+01
1 (restart 0) KSP residual norm 3.481004e+01
2 (restart 0) KSP residual norm 8.956162e+00
3 (restart 1) KSP residual norm 2.241883e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.529e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 3.573e-03 (norm(b) = 6.275e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 9.813501e+01
1 (restart 0) KSP residual norm 5.771674e+01
2 (restart 0) KSP residual norm 2.303109e+01
3 (restart 1) KSP residual norm 3.287289e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.496e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 3.350e-03 (norm(b) = 9.814e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 7.720080e+01
1 (restart 0) KSP residual norm 6.971510e+01
2 (restart 0) KSP residual norm 5.686810e+01
3 (restart 1) KSP residual norm 6.714601e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.057e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 8.698e-03 (norm(b) = 7.720e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 7.638992e+01
1 (restart 0) KSP residual norm 5.367765e+01
2 (restart 0) KSP residual norm 3.439303e+01
3 (restart 1) KSP residual norm 4.234628e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.770e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 5.543e-03 (norm(b) = 7.639e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 4.046472e+01
1 (restart 0) KSP residual norm 3.724911e+01
2 (restart 0) KSP residual norm 2.931985e+01
3 (restart 1) KSP residual norm 5.039609e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.318e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.245e-02 (norm(b) = 4.046e+01)!

  Eigenvalue approximations and residual norms for  solve.
  1 EPS nconv=3 first unconverged value (error) -5.99788e-05+0.00236959i (7.88472977e-03)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 9.338336e+01
1 (restart 0) KSP residual norm 6.841398e+01
2 (restart 0) KSP residual norm 1.550734e+01
3 (restart 1) KSP residual norm 3.357722e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.532e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 3.596e-03 (norm(b) = 9.338e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.848724e+01
1 (restart 0) KSP residual norm 3.529266e+01
2 (restart 0) KSP residual norm 1.276312e+01
3 (restart 1) KSP residual norm 4.107400e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.202e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.067e-02 (norm(b) = 3.849e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.146016e+01
1 (restart 0) KSP residual norm 1.793989e+01
2 (restart 0) KSP residual norm 3.548481e+00
3 (restart 1) KSP residual norm 3.491101e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.534e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.627e-02 (norm(b) = 2.146e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.626228e+01
1 (restart 0) KSP residual norm 1.619951e+01
2 (restart 0) KSP residual norm 9.739910e+00
3 (restart 1) KSP residual norm 2.572633e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.140e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 9.796e-03 (norm(b) = 2.626e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 6.053278e+01
1 (restart 0) KSP residual norm 3.773032e+01
2 (restart 0) KSP residual norm 9.383100e+00
3 (restart 1) KSP residual norm 3.134839e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.730e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 5.179e-03 (norm(b) = 6.053e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.068695e+01
1 (restart 0) KSP residual norm 2.227342e+01
2 (restart 0) KSP residual norm 1.148230e+01
3 (restart 1) KSP residual norm 3.263643e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.199e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.064e-02 (norm(b) = 3.069e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.999870e+01
1 (restart 0) KSP residual norm 3.774763e+01
2 (restart 0) KSP residual norm 3.236711e+01
3 (restart 1) KSP residual norm 4.540024e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.247e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.135e-02 (norm(b) = 4.000e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 5.487457e+01
1 (restart 0) KSP residual norm 1.479069e+01
2 (restart 0) KSP residual norm 3.900170e+00
3 (restart 1) KSP residual norm 3.848939e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.914e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 7.014e-03 (norm(b) = 5.487e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.998237e+01
1 (restart 0) KSP residual norm 2.593476e+01
2 (restart 0) KSP residual norm 1.755288e+01
3 (restart 1) KSP residual norm 2.091052e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.911e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 6.974e-03 (norm(b) = 2.998e+01)!

  2 EPS nconv=3 first unconverged value (error) -6.48921e-06+0.00237218i (3.24934625e-03)
Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 9.155483e+01
1 (restart 0) KSP residual norm 7.560587e+01
2 (restart 0) KSP residual norm 5.350513e+01
3 (restart 1) KSP residual norm 3.359118e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.542e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 3.669e-03 (norm(b) = 9.155e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 4.328329e+01
1 (restart 0) KSP residual norm 5.176884e+00
2 (restart 0) KSP residual norm 2.643262e+00
3 (restart 1) KSP residual norm 7.311450e-02
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.191e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.689e-03 (norm(b) = 4.328e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.654228e+01
1 (restart 0) KSP residual norm 2.470876e+01
2 (restart 0) KSP residual norm 1.929156e+01
3 (restart 1) KSP residual norm 1.585680e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.815e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 5.974e-03 (norm(b) = 2.654e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.883958e+01
1 (restart 0) KSP residual norm 2.513077e+01
2 (restart 0) KSP residual norm 1.667734e+01
3 (restart 1) KSP residual norm 1.766759e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.830e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 6.126e-03 (norm(b) = 2.884e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.437399e+01
1 (restart 0) KSP residual norm 2.136668e+01
2 (restart 0) KSP residual norm 1.101456e+01
3 (restart 1) KSP residual norm 1.470401e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.820e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 6.033e-03 (norm(b) = 2.437e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.322936e+01
1 (restart 0) KSP residual norm 1.508105e+01
2 (restart 0) KSP residual norm 2.701484e+00
3 (restart 1) KSP residual norm 1.939744e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.029e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 8.350e-03 (norm(b) = 2.323e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.838854e+01
1 (restart 0) KSP residual norm 1.748158e+01
2 (restart 0) KSP residual norm 1.322922e+01
3 (restart 1) KSP residual norm 1.401764e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.968e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 7.623e-03 (norm(b) = 1.839e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.768894e+01
1 (restart 0) KSP residual norm 2.925392e+01
2 (restart 0) KSP residual norm 1.883577e+01
3 (restart 1) KSP residual norm 3.743840e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.150e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 9.934e-03 (norm(b) = 3.769e+01)!

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 6.222283e+01
1 (restart 0) KSP residual norm 2.570920e+01
2 (restart 0) KSP residual norm 1.159447e+01
3 (restart 1) KSP residual norm 3.743351e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.819e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 6.016e-03 (norm(b) = 6.222e+01)!

  3 EPS nconv=6 first unconverged value (error) -5.03846e-05+0.00284044i (5.04194851e-03)

 Linear eigensolve converged (6 eigenpairs) due to CONVERGED_TOL; iterations 3
 Total number of linear systems solved: 39
 Total number of linear solver iterations: 114
 Found 6 converged eigenvalues (first = -1.642e-05+3.629e-01i)

Computing solution error estimates and performing postprocessing

m     Re{ω}/2π (GHz)     Im{ω}/2π (GHz)        Bkwd. Error         Abs. Error
=============================================================================
1      +3.136773e+00      +1.419088e-04      +7.453931e-09      +1.332296e-03
 Wrote mode 1 to disk
2      +7.182393e+00      +5.380575e-02      +1.006761e-06      +1.799511e-01
 Wrote mode 2 to disk
3      +7.984742e+00      +6.056005e-02      +1.045471e-06      +1.868715e-01
 Wrote mode 3 to disk
4      +9.637756e+00      +4.853371e-02      +1.024503e-06      +1.831260e-01
 Wrote mode 4 to disk
5      +9.940094e+00      +7.946123e-02      +1.765758e-06      +3.156232e-01
 Wrote mode 5 to disk
6      +1.069663e+01      +2.472286e-01      +8.803714e-07      +1.573643e-01
 Wrote mode 6 to disk

Completed 0 iterations of adaptive mesh refinement (AMR):
 Indicator norm = 4.003e-01, global unknowns = 209195
 Max. iterations = 0, tol. = 1.000e-02

Elapsed Time Report (s)           Min.        Max.        Avg.
==============================================================
Initialization                   3.397       3.417       3.405
Operator Construction            3.128       3.143       3.137
Linear Solve                     5.972       6.088       6.019
  Setup                          0.077       0.079       0.078
  Preconditioner                17.736      17.795      17.768
Eigenvalue Solve                 3.406       3.462       3.437
Div.-Free Projection            13.755      13.848      13.817
Estimation                       0.177       0.208       0.191
  Construction                   2.546       2.550       2.547
  Solve                         15.919      15.956      15.940
Postprocessing                   1.695       1.755       1.718
Disk IO                          9.162       9.169       9.165
--------------------------------------------------------------
Total                           77.313      77.328      77.322

Error in plotting: 'Data array (E_real) not present in this dataset.'

Reading the eigenmode data now

[35]:
def read_csv_to_dataframe(file_path):
    return pd.read_csv(file_path)

eigen_df = read_csv_to_dataframe(os.path.join(eigen_sim._output_data_dir, 'eig.csv'))
eigen_df.columns = eigen_df.columns.str.strip()
eigen_df["kappa (kHz)"] = eigen_df["Re{f} (GHz)"] / eigen_df["Q"] * 1e6
eigen_df
[35]:
m Re{f} (GHz) Im{f} (GHz) Q Error (Bkwd.) Error (Abs.) kappa (kHz)
0 1.0 3.136773 0.000142 11052.078980 7.453931e-09 0.001332 283.817505
1 2.0 7.182393 0.053806 66.745601 1.006761e-06 0.179951 107608.479305
2 3.0 7.984742 0.060560 65.926071 1.045471e-06 0.186871 121116.613403
3 4.0 9.637756 0.048534 99.290551 1.024503e-06 0.183126 97066.198247
4 5.0 9.940094 0.079461 62.548816 1.765758e-06 0.315623 158917.379265
5 6.0 10.696625 0.247229 21.638840 8.803714e-07 0.157364 494325.272753

From our requirements, we wanted a qubit frequency of 3.7 GHz and a cavity frequency of

[36]:
target_params["cavity_frequency_GHz"]
[36]:
6.98

From the simulations, it seems like mode 1 is the qubit mode (found to be 3.136 GHz) and mode 2 is the cavity mode (found to be 7.183 GHz) given their frequencies

Lets’ visualize all the eigenmodes in paraview to see if thats the case. Here are some screenshots from this toy example.

Mode 2

Mode 4

Mode 4

Mode 1: Qubit Mode

Mode 2: Cavity Mode?

Mode 3: Cavity Mode?

It seems like that indeed mode 1 is the qubit mode and mode 3 looks to be like the cavity mode (apologies for the bad quality of the images).

Of course, this simulation was done with really coarse hyperparameters (ran in 1.5 minutes on my 2021 Macbook Pro) so this results are somewhat promising!

EPR Calculations#

Since palace does automatic postprocessing of energy-participation ratios (EPRs) for circuit quantization and interface or bulk participation ratios for predicting dielectric loss, we can use this to do some quantum analysis from the eigenmode simulation when lumped inductive elements (i.e. josephson junctions) exist in the simulated geometry.

First, we need to retrieve the mode-port EPRs from the eigenmode simulation.

[37]:
mode_dict = eigen_sim.retrieve_mode_port_EPR_from_file(eigen_sim._output_data_dir)

#get particpation ratios and frequencies from the simulation
participation_ratios = mode_dict['mat_mode_port']
frequencies = mode_dict['eigenfrequencies']

We have identified the qubit and cavity modes from the eigenmode simulation as mode 3 and mode 4 respectively.

[38]:
qubit_idx = 0
cavity_idx = 2
[39]:
linear_qubit_freq = eigen_df['Re{f} (GHz)'][qubit_idx]*1e9
linear_res_freq = eigen_df['Re{f} (GHz)'][cavity_idx]*1e9
P_qubit = abs(participation_ratios[qubit_idx, 0])
P_cav = abs(participation_ratios[cavity_idx, 0])
[40]:
P_qubit, P_cav
[40]:
(0.9902988796, 5.021029524e-05)

Now, let’s calculate the qubit and cavity Hamiltonian parameters using these participation ratios.

[41]:
#Constants used for calculations
from scipy.constants import Planck, e, hbar
phi0 = hbar/(2*e)

#Josephson Energy (Ej) and linear inductance (Lj)
delta_super = (1.8e-4 / 2) * e
Lj = LJs[0]*1e-9
Ej = phi0**2 / Lj

#Normalize Participation Ratios
P_qubit_normalised = P_qubit / (P_qubit + P_cav)
P_cav_normalised = P_cav / (P_qubit + P_cav)

#Enter in Frequencies from Simulation
omega_qubit = 2 * np.pi * linear_qubit_freq
omega_res = 2 * np.pi * linear_res_freq

#phi zero-point fluctuations for qubit
phi_zpf_sq = P_qubit * hbar * 2 * omega_qubit  / (2*Ej)

#anharmonicity qubit (self kerr)
anharm_qubit = P_qubit**2 * hbar * omega_qubit**2 / (8*Ej)

#anharmonicity resonator (self kerr)
anharm_res = P_cav**2 * hbar * omega_res**2 / (8*Ej)

#Charging Energy (Ec)
Ec = anharm_qubit * hbar

#Total Capacitance
C_total = e**2 / (2*Ec)

#cross kerr - dispersive shit (chi)
cross_kerr = (P_qubit * P_cav * hbar * omega_qubit * omega_res) / (4*Ej)

#lamb-shift of qubit frequency
lamb_shift_qubit = anharm_qubit - cross_kerr/2

#lamb-shift of res frequency
lamb_shift_res = anharm_res - cross_kerr/2

#detuning, delta
delta = ((linear_res_freq - anharm_res/(2*np.pi)) - (linear_qubit_freq - anharm_qubit/(2*np.pi)))

#resonator-qubit coupling strength (g)
disp_shift_qubit = cross_kerr
g_rwa = np.sqrt(disp_shift_qubit * delta  * (1 + delta/anharm_qubit))

# coupling strength (g) from SQuADDS Paper
Delta = omega_res - omega_qubit      # rad/s
Sigma = omega_res + omega_qubit      # rad/s
alpha = -anharm_qubit                # rad/s (already angular)
chi = -disp_shift_qubit              # rad/s (already angular)
# Denominator (s/rad)
denom = (alpha / (Delta * (Delta - alpha))) - (alpha / (Sigma * (Sigma + alpha)))

# Convert to linear frequency in MHz (optional, for reporting)
g_rad = np.sqrt(chi / (2 * denom))     # rad/s
g_MHz = g_rad / (2 * np.pi * 1e6)    # MHz

Interesting to check what scqubits says about the Hamiltonian parameters computed using the simulation results.

[42]:
import scqubits as scq
from scqubits.core.transmon import Transmon

scq.set_units("GHz")

# Using scqubits to find the Josephson energy and charging energy using the qubit frequency and anharmonicity from EPR
qubit_freq_GHz = linear_qubit_freq/1e9 - lamb_shift_qubit/(2*np.pi*1e9)
qubit_anharm_GHz = (alpha*1e-9)/(2*np.pi)
EJ_scq, EC_scq = Transmon.find_EJ_EC(qubit_freq_GHz, qubit_anharm_GHz)


# Using scqubits to find the qubit frequency and anharmonicity now using the Josephson energy and charging energy from EP
EJ_GHz = Ej / (hbar * 2 * np.pi *  1e9)
EC_GHz = anharm_qubit  / (2*np.pi*1e9)
transmon = Transmon(EJ=EJ_GHz, EC=EC_GHz, ng=0, ncut=30)
qubit_freq_scq= transmon.E01()
anharm_qubit_scq = transmon.anharmonicity() * 1E3  # MHz

# Using scqubits to find the C_qubit capacitance

def C_qubit_from_Ec(Ec):
    """
    Calculate the capacitance (C_qubit) in fF from the charging energy (Ec) in GHz.
    """
    Ec_Joules = Ec * 1e9 * Planck
    Cs_SI = (e ** 2) / (2 * Ec_Joules)
    Cs_fF = Cs_SI * 1e15
    return Cs_fF

C_qubit_scq = C_qubit_from_Ec(EC_scq)
[43]:
hamiltonian_params = [
    ("Ej", Ej / (hbar * 2 * np.pi *  1e9), "GHz"),
    ("Ej (scqubits)", EJ_scq, "GHz"),
    ("Ec", anharm_qubit  / (2*np.pi*1e9), "GHz"),
    ("Ec (scqubits)", EC_scq, "GHz"),
    ("Ej/Ec", Ej/Ec, "unitless"),
    ("Ej/Ec (scqubits)", EJ_scq/EC_scq, "unitless"),
    ("Lj", Lj/1e-9, "nH"),
    ("C_qubit", C_total/1e-15, "fF"),
    ("C_qubit (scqubits)", C_qubit_scq, "fF"),
    ("C_qubit (from SQuADDS DB)", results["cross_to_claw"].values[0]+results["cross_to_ground"].values[0], "fF"),
    ("Participation Ratio Qubit", P_qubit, "unitless"),
    ("Participation Ratio Qubit (Normalized)", P_qubit_normalised, "unitless"),
    ("Participation Ratio Cavity", P_cav, "unitless"),
    ("Participation Ratio Cavity (Normalized)", P_cav_normalised, "unitless"),
    ("Linear Qubit Frequency", linear_qubit_freq/1e9, "GHz"),
    ("Qubit Frequency", linear_qubit_freq/1e9 - lamb_shift_qubit/(2*np.pi*1e9), "GHz"),
    ("Qubit Frequency (scqubits)", qubit_freq_scq, "GHz"),
    ("Qubit Frequency (from SQuADDS DB)", results["qubit_frequency_GHz"].values[0], "GHz"),
    ("Qubit Anharmonicity", anharm_qubit / (2*np.pi*1e6), "MHz"),
    ("Qubit Anharmonicity (scqubits)", -anharm_qubit_scq, "MHz"),
    ("Qubit Anharmonicity (from SQuADDS DB)", - results["anharmonicity_MHz"].values[0], "MHz"),
    ("Linear Cavity Frequency", linear_res_freq/1e9, "GHz"),
    ("Cavity Frequency", linear_res_freq/1e9 - lamb_shift_res/(2*np.pi*1e9), "GHz"),
    ("Cavity Anharmonicity", anharm_res / (2*np.pi*1e6), "MHz"),
    ("Dispersive Shift (chi)", cross_kerr/ (2*np.pi*1e6), "MHz"),
    ("Cavity-Qubit Coupling [Ref. SQuADDS], g", g_MHz, "MHz"),
    ("Cavity-Qubit Coupling [RWA], g", g_rwa/(2*np.pi*1e6), "MHz"),
    ("Detuning", delta/1e9, "GHz"),
    ("Flux_ZPF_squared", phi_zpf_sq, "unitless"),
]

# Create DataFrame
hamiltonian_df = pd.DataFrame(hamiltonian_params, columns=["Parameter", "Value", "Unit"])

# Function to format values
def format_float_six_decimal(val, idx):
    return f"{val:.6f}"

# Apply formatting
hamiltonian_df['Value'] = [
    format_float_six_decimal(val, idx) for idx, val in enumerate(hamiltonian_df['Value'])
]

print(hamiltonian_df.to_string(index=False))
                              Parameter      Value     Unit
                                     Ej  10.278024      GHz
                          Ej (scqubits)  11.401425      GHz
                                     Ec   0.117354      GHz
                          Ec (scqubits)   0.107476      GHz
                                  Ej/Ec  87.581095 unitless
                       Ej/Ec (scqubits) 106.083580 unitless
                                     Lj  15.903982       nH
                                C_qubit 165.057588       fF
                     C_qubit (scqubits) 180.228631       fF
              C_qubit (from SQuADDS DB) 107.321280       fF
              Participation Ratio Qubit   0.990299 unitless
 Participation Ratio Qubit (Normalized)   0.999949 unitless
             Participation Ratio Cavity   0.000050 unitless
Participation Ratio Cavity (Normalized)   0.000051 unitless
                 Linear Qubit Frequency   3.136773      GHz
                        Qubit Frequency   3.019434      GHz
             Qubit Frequency (scqubits)   2.984043      GHz
      Qubit Frequency (from SQuADDS DB)   3.662130      GHz
                    Qubit Anharmonicity 117.354370      MHz
         Qubit Anharmonicity (scqubits) 129.507341      MHz
  Qubit Anharmonicity (from SQuADDS DB) 205.109839      MHz
                Linear Cavity Frequency   7.984742      GHz
                       Cavity Frequency   7.984758      GHz
                   Cavity Anharmonicity   0.000002      MHz
                 Dispersive Shift (chi)   0.030292      MHz
Cavity-Qubit Coupling [Ref. SQuADDS], g  62.189165      MHz
         Cavity-Qubit Coupling [RWA], g  13.606631      MHz
                               Detuning   4.965323      GHz
                       Flux_ZPF_squared   0.302232 unitless

Drivenmodal Simulations#

Now, we show how to run Drivenmodal simulations to get the scattering parameters. Let’s use the same qubit-cavity geometry as the eigenmodal simulation for this.

[45]:
from SQDMetal.PALACE.Frequency_Driven_Simulation import PALACE_Driven_Simulation

#Eigenmode Simulation Options
user_defined_options = {
                 "mesh_refinement":  0,                             #refines mesh in PALACE - essetially divides every mesh element in half
                 "dielectric_material": "silicon",                  #choose dielectric material - 'silicon' or 'sapphire'
                 "solns_to_save": 4,                                #number of electromagnetic field visualizations to save
                 "solver_order": 1,                                 #increasing solver order increases accuracy of simulation, but significantly increases sim time
                 "solver_tol": 1.0e-3,                              #error residual tolerance foriterative solver
                 "solver_maxits": 3,                              #number of solver iterations
                 "mesh_max": 120e-3,                                #maxiumum element size for the mesh in mm
                 "mesh_min": 10e-3,                                 #minimum element size for the mesh in mm
                 "mesh_sampling": 130,                              #number of points to mesh along a geometry
                 "fillet_resolution":12,
                 "num_cpus": 10,                                      #number of CPU cores to use for simulation
                 "palace_dir":path_to_palace
                }

#Create the Palace Frequency Driven simulation
driven_sim = PALACE_Driven_Simulation(
    name='qubit-cavity-driven',                  #name of simulation
    metal_design=design,                              #feed in qiskit metal design
    sim_parent_directory="sims/",                     #choose directory where mesh file, config file and HPC batch file will be saved
    mode='simPC',                                     #choose simulation mode 'HPC' or 'simPC'
    meshing='GMSH',                                   #choose meshing 'GMSH' or 'COMSOL'
    user_options=user_defined_options,                #provide options chosen above
    view_design_gmsh_gui=False,                       #view design in GMSH gui
    create_files=True                                 #create mesh, config and HPC batch files
)
[46]:
from SQDMetal.Utilities.Materials import MaterialInterface

# Add metallic elements and ground plane
driven_sim.add_metallic(1, threshold=1e-10, fuse_threshold=1e-10)
driven_sim.add_ground_plane(threshold=1e-10)

# Fine-mesh the transmon cross qubit region
driven_sim.fine_mesh_in_rectangle(0.2875e-3, -1.2e-3, 0.63e-3, -1.72e-3, min_size=15e-6, max_size=120e-6)

# Add in the RF ports
driven_sim.create_port_CPW_on_Launcher('LP1', 20e-6)
driven_sim.create_port_CPW_on_Launcher('LP2', 20e-6)
driven_sim.create_port_JosephsonJunction('junction', L_J=LJs[0]*1e-9, C_J=10e-15)  # Guessing the C_J value

# Fine-mesh routed paths
driven_sim.fine_mesh_around_comp_boundaries(['feedline', 'resonator'], min_size=25e-6, max_size=250e-6)
driven_sim.fine_mesh_around_comp_boundaries(['xmon'], min_size=14e-6, max_size=75e-6)

# Setup EPR interfaces
driven_sim.setup_EPR_interfaces(
    metal_air=MaterialInterface('Aluminium-Vacuum'),
    substrate_air=MaterialInterface('Silicon-Vacuum'),
    substrate_metal=MaterialInterface('Silicon-Aluminium')
)

[47]:
# Set frequency sweep parameters (in GHz)
driven_sim.set_freq_values(
    startGHz=3,    # starting frequency in GHz
    endGHz=10,     # end frequency in GHz
    stepGHz=0.5    # frequency step size in GHz
)

[48]:
# Prepare and run simulation
driven_sim.prepare_simulation()
Directory 'qubit-cavity-driven' created

NOTE: If you are using a palace build that is from 2025, you will need to remove the Excitation key from the LumpedPort boundary condition in the sim_config.json file so please execute the following cell.

If you are using a palace build that is from 2024 or older, you should skip this cell.

[ ]:
import json

with open(driven_sim._sim_config, 'r') as file:
    sim_config_dict = json.load(file)

del sim_config_dict["Boundaries"]["LumpedPort"][0]["Excitation"]

with open(eigen_sim._sim_config, 'w') as file:
    json.dump(sim_config_dict, file, indent=4)
[49]:
results = driven_sim.run()
>> /opt/homebrew/bin/mpirun -n 10 /Users/shanto/LFL/palace/build/bin/palace-arm64.bin qubit-cavity-driven.json

_____________     _______
_____   __   \____ __   /____ ____________
____   /_/  /  __ ` /  /  __ ` /  ___/  _ \
___   _____/  /_/  /  /  /_/  /  /__/  ___/
  /__/     \___,__/__/\___,__/\_____\_____/

Git changeset ID: v0.13.0-117-g748660c
Running with 10 MPI processes
Device configuration: cpu
Memory configuration: host-std
libCEED backend: /cpu/self/xsmm/blocked

Added 2574 elements in 2 iterations of local bisection for under-resolved interior boundaries
Added 5333 duplicate vertices for interior boundaries in the mesh
Added 12701 duplicate boundary elements for interior boundaries in the mesh
Added 1550 boundary elements for material interfaces to the mesh
Finished partitioning mesh into 10 subdomains

Characteristic length and time scales:
 L₀ = 5.520e-03 m, t₀ = 1.841e-02 ns

Mesh curvature order: 1
Mesh bounding box:
 (Xmin, Ymin, Zmin) = (-2.760e-03, -2.440e-03, -2.800e-04) m
 (Xmax, Ymax, Zmax) = (+2.760e-03, +4.400e-04, +2.800e-04) m

Parallel Mesh Stats:

                minimum     average     maximum       total
 vertices          2786        3522        3859       35223
 edges            18749       20919       22124      209195
 faces            31110       32653       33699      326538
 elements         15011       15256       15457      152568
 neighbors            2           4           5

            minimum     maximum
 h      0.000513927   0.0271869
 kappa      1.01967     157.435

Configuring Robin absorbing BC (order 1) at attributes:
 13

Configuring Robin impedance BC for lumped ports at attributes:
 5: Rs = 6.667e+01 Ω/sq, n = (+0.0, +0.0, +1.0)
 6: Rs = 6.667e+01 Ω/sq, n = (+0.0, +0.0, -1.0)
 7: Rs = 6.667e+01 Ω/sq, n = (-0.0, +0.0, +1.0)
 8: Rs = 6.667e+01 Ω/sq, n = (+0.0, +0.0, -1.0)
 9: Ls = 5.725e-09 H/sq, Cs = 2.778e-14 F/sq, n = (+0.0, +0.0, +1.0)

Configuring lumped port circuit properties:
 Index = 1: R = 5.000e+01 Ω
 Index = 2: R = 5.000e+01 Ω
 Index = 3: L = 1.590e-08 H, C = 1.000e-14 F

Configuring lumped port excitation source term at attributes:
 5: Index = 1
 6: Index = 1

Configuring Dirichlet PEC BC at attributes:
 1-4

Computing frequency response for:
 Lumped port excitation specified on ports 1

Assembling system matrices, number of global unknowns:
 H1 (p = 1): 35223, ND (p = 1): 209195, RT (p = 1): 326538
 Operator assembly level: Partial
 Mesh geometries:
  Tetrahedron: P = 6, Q = 4 (quadrature order = 2)

Assembling multigrid hierarchy:
 Level 0 (p = 1): 209195 unknowns, 3111237 NNZ
 Level 0 (auxiliary) (p = 1): 35223 unknowns, 467972 NNZ

It 1/15: ω/2π = 3.000e+00 GHz (elapsed time = 2.91e-07 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 6.351240e-01
1 (restart 0) KSP residual norm 3.601434e-01
2 (restart 0) KSP residual norm 3.457708e-02
3 (restart 1) KSP residual norm 5.712683e-03
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.080e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 8.995e-03 (norm(b) = 6.351e-01)!

 Sol. ||E|| = 1.080985e+01 (||RHS|| = 6.351240e-01)
 Field energy E (2.658e-02 J) + H (8.606e-03 J) = 3.519e-02 J
 Updating solution error estimates
 S[1][1] = -6.783e-01-3.388e-01i, |S[1][1]| = -2.404e+00, arg(S[1][1]) = -1.535e+02
 S[2][1] = +2.911e-01-5.831e-01i, |S[2][1]| = -3.719e+00, arg(S[2][1]) = -6.347e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

 Wrote fields to disk at step 1

It 2/15: ω/2π = 3.500e+00 GHz (elapsed time = 1.14e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 9.903109e-02
1 (restart 0) KSP residual norm 8.059919e-02
2 (restart 0) KSP residual norm 1.326503e-02
3 (restart 1) KSP residual norm 5.781395e-03
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.983e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 7.802e-03 (norm(b) = 7.410e-01)!

 Sol. ||E|| = 9.294195e+00 (||RHS|| = 7.409780e-01)
 Field energy E (1.967e-02 J) + H (8.991e-03 J) = 2.866e-02 J
 Updating solution error estimates
 S[1][1] = -7.525e-01-2.548e-01i, |S[1][1]| = -1.998e+00, arg(S[1][1]) = -1.613e+02
 S[2][1] = +2.044e-01-5.429e-01i, |S[2][1]| = -4.729e+00, arg(S[2][1]) = -6.937e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 3/15: ω/2π = 4.000e+00 GHz (elapsed time = 1.69e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.008076e-01
1 (restart 0) KSP residual norm 7.244153e-02
2 (restart 0) KSP residual norm 2.058542e-02
3 (restart 1) KSP residual norm 6.419817e-03
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 1.964e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 7.581e-03 (norm(b) = 8.468e-01)!

 Sol. ||E|| = 8.579163e+00 (||RHS|| = 8.468320e-01)
 Field energy E (1.679e-02 J) + H (9.388e-03 J) = 2.618e-02 J
 Updating solution error estimates
 S[1][1] = -7.918e-01-1.988e-01i, |S[1][1]| = -1.762e+00, arg(S[1][1]) = -1.659e+02
 S[2][1] = +1.500e-01-5.324e-01i, |S[2][1]| = -5.144e+00, arg(S[2][1]) = -7.427e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 4/15: ω/2π = 4.500e+00 GHz (elapsed time = 2.42e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.021443e-01
1 (restart 0) KSP residual norm 6.477930e-02
2 (restart 0) KSP residual norm 2.157044e-02
3 (restart 1) KSP residual norm 1.044909e-02
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.222e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.097e-02 (norm(b) = 9.527e-01)!

 Sol. ||E|| = 7.907910e+00 (||RHS|| = 9.526860e-01)
 Field energy E (1.428e-02 J) + H (9.791e-03 J) = 2.407e-02 J
 Updating solution error estimates
 S[1][1] = -8.197e-01-1.373e-01i, |S[1][1]| = -1.606e+00, arg(S[1][1]) = -1.705e+02
 S[2][1] = +1.034e-01-5.178e-01i, |S[2][1]| = -5.547e+00, arg(S[2][1]) = -7.870e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 5/15: ω/2π = 5.000e+00 GHz (elapsed time = 3.04e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.039076e-01
1 (restart 0) KSP residual norm 6.272732e-02
2 (restart 0) KSP residual norm 5.587032e-02
3 (restart 1) KSP residual norm 2.058066e-02
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 2.689e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.944e-02 (norm(b) = 1.059e+00)!

 Sol. ||E|| = 7.378380e+00 (||RHS|| = 1.058540e+00)
 Field energy E (1.245e-02 J) + H (1.018e-02 J) = 2.263e-02 J
 Updating solution error estimates
 S[1][1] = -8.356e-01-7.813e-02i, |S[1][1]| = -1.523e+00, arg(S[1][1]) = -1.747e+02
 S[2][1] = +6.471e-02-5.062e-01i, |S[2][1]| = -5.842e+00, arg(S[2][1]) = -8.272e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

 Wrote fields to disk at step 5

It 6/15: ω/2π = 5.500e+00 GHz (elapsed time = 3.83e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.085018e-01
1 (restart 0) KSP residual norm 6.991534e-02
2 (restart 0) KSP residual norm 6.988851e-02
3 (restart 1) KSP residual norm 5.191527e-02
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 3.546e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 4.459e-02 (norm(b) = 1.164e+00)!

 Sol. ||E|| = 6.921427e+00 (||RHS|| = 1.164394e+00)
 Field energy E (1.097e-02 J) + H (1.020e-02 J) = 2.117e-02 J
 Updating solution error estimates
 S[1][1] = -8.341e-01-2.251e-02i, |S[1][1]| = -1.573e+00, arg(S[1][1]) = -1.785e+02
 S[2][1] = +3.688e-02-4.904e-01i, |S[2][1]| = -6.164e+00, arg(S[2][1]) = -8.570e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 7/15: ω/2π = 6.000e+00 GHz (elapsed time = 4.60e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 1.347054e-01
1 (restart 0) KSP residual norm 1.238462e-01
2 (restart 0) KSP residual norm 1.106825e-01
3 (restart 1) KSP residual norm 1.097831e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 4.421e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 8.643e-02 (norm(b) = 1.270e+00)!

 Sol. ||E|| = 6.235652e+00 (||RHS|| = 1.270248e+00)
 Field energy E (8.901e-03 J) + H (9.715e-03 J) = 1.862e-02 J
 Updating solution error estimates
 S[1][1] = -8.310e-01+3.706e-02i, |S[1][1]| = -1.599e+00, arg(S[1][1]) = +1.774e+02
 S[2][1] = +7.673e-03-4.604e-01i, |S[2][1]| = -6.737e+00, arg(S[2][1]) = -8.905e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 8/15: ω/2π = 6.500e+00 GHz (elapsed time = 5.18e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.011330e-01
1 (restart 0) KSP residual norm 1.985118e-01
2 (restart 0) KSP residual norm 1.821145e-01
3 (restart 1) KSP residual norm 1.661144e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 4.942e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.207e-01 (norm(b) = 1.376e+00)!

 Sol. ||E|| = 6.030714e+00 (||RHS|| = 1.376102e+00)
 Field energy E (8.322e-03 J) + H (1.012e-02 J) = 1.845e-02 J
 Updating solution error estimates
 S[1][1] = -8.530e-01+8.478e-02i, |S[1][1]| = -1.339e+00, arg(S[1][1]) = +1.743e+02
 S[2][1] = -3.345e-02-4.634e-01i, |S[2][1]| = -6.659e+00, arg(S[2][1]) = -9.413e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 9/15: ω/2π = 7.000e+00 GHz (elapsed time = 5.75e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.526932e-01
1 (restart 0) KSP residual norm 2.514240e-01
2 (restart 0) KSP residual norm 2.352636e-01
3 (restart 1) KSP residual norm 1.872347e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 5.018e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.263e-01 (norm(b) = 1.482e+00)!

 Sol. ||E|| = 6.063368e+00 (||RHS|| = 1.481956e+00)
 Field energy E (8.431e-03 J) + H (1.064e-02 J) = 1.907e-02 J
 Updating solution error estimates
 S[1][1] = -8.490e-01+1.257e-01i, |S[1][1]| = -1.328e+00, arg(S[1][1]) = +1.716e+02
 S[2][1] = -6.245e-02-4.702e-01i, |S[2][1]| = -6.478e+00, arg(S[2][1]) = -9.756e+01
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

 Wrote fields to disk at step 9

It 10/15: ω/2π = 7.500e+00 GHz (elapsed time = 6.41e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.703739e-01
1 (restart 0) KSP residual norm 2.442628e-01
2 (restart 0) KSP residual norm 2.237861e-01
3 (restart 1) KSP residual norm 1.848211e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 4.883e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.164e-01 (norm(b) = 1.588e+00)!

 Sol. ||E|| = 6.104483e+00 (||RHS|| = 1.587810e+00)
 Field energy E (8.570e-03 J) + H (1.135e-02 J) = 1.992e-02 J
 Updating solution error estimates
 S[1][1] = -8.184e-01+1.706e-01i, |S[1][1]| = -1.556e+00, arg(S[1][1]) = +1.682e+02
 S[2][1] = -9.212e-02-4.720e-01i, |S[2][1]| = -6.359e+00, arg(S[2][1]) = -1.010e+02
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 11/15: ω/2π = 8.000e+00 GHz (elapsed time = 6.98e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.648449e-01
1 (restart 0) KSP residual norm 2.529848e-01
2 (restart 0) KSP residual norm 2.470227e-01
3 (restart 1) KSP residual norm 2.132539e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 5.012e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.259e-01 (norm(b) = 1.694e+00)!

 Sol. ||E|| = 6.074015e+00 (||RHS|| = 1.693664e+00)
 Field energy E (8.485e-03 J) + H (1.086e-02 J) = 1.934e-02 J
 Updating solution error estimates
 S[1][1] = -7.818e-01+1.886e-01i, |S[1][1]| = -1.892e+00, arg(S[1][1]) = +1.664e+02
 S[2][1] = -1.115e-01-4.599e-01i, |S[2][1]| = -6.498e+00, arg(S[2][1]) = -1.036e+02
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 12/15: ω/2π = 8.500e+00 GHz (elapsed time = 7.59e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 2.984142e-01
1 (restart 0) KSP residual norm 2.575522e-01
2 (restart 0) KSP residual norm 2.376679e-01
3 (restart 1) KSP residual norm 2.322283e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 5.053e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.291e-01 (norm(b) = 1.800e+00)!

 Sol. ||E|| = 6.126870e+00 (||RHS|| = 1.799518e+00)
 Field energy E (8.574e-03 J) + H (1.221e-02 J) = 2.078e-02 J
 Updating solution error estimates
 S[1][1] = -7.212e-01+2.521e-01i, |S[1][1]| = -2.338e+00, arg(S[1][1]) = +1.607e+02
 S[2][1] = -1.542e-01-4.445e-01i, |S[2][1]| = -6.550e+00, arg(S[2][1]) = -1.091e+02
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 13/15: ω/2π = 9.000e+00 GHz (elapsed time = 8.20e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.080933e-01
1 (restart 0) KSP residual norm 3.057754e-01
2 (restart 0) KSP residual norm 2.924240e-01
3 (restart 1) KSP residual norm 2.864515e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 5.317e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.503e-01 (norm(b) = 1.905e+00)!

 Sol. ||E|| = 6.185118e+00 (||RHS|| = 1.905372e+00)
 Field energy E (8.678e-03 J) + H (1.174e-02 J) = 2.042e-02 J
 Updating solution error estimates
 S[1][1] = -7.057e-01+2.713e-01i, |S[1][1]| = -2.429e+00, arg(S[1][1]) = +1.590e+02
 S[2][1] = -1.719e-01-4.405e-01i, |S[2][1]| = -6.506e+00, arg(S[2][1]) = -1.113e+02
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

 Wrote fields to disk at step 13

It 14/15: ω/2π = 9.500e+00 GHz (elapsed time = 9.28e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 3.707691e-01
1 (restart 0) KSP residual norm 3.632131e-01
2 (restart 0) KSP residual norm 3.557204e-01
3 (restart 1) KSP residual norm 3.442652e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 5.552e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.712e-01 (norm(b) = 2.011e+00)!

 Sol. ||E|| = 6.305533e+00 (||RHS|| = 2.011226e+00)
 Field energy E (9.056e-03 J) + H (1.203e-02 J) = 2.109e-02 J
 Updating solution error estimates
 S[1][1] = -6.764e-01+3.036e-01i, |S[1][1]| = -2.599e+00, arg(S[1][1]) = +1.558e+02
 S[2][1] = -2.045e-01-4.389e-01i, |S[2][1]| = -6.299e+00, arg(S[2][1]) = -1.150e+02
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

It 15/15: ω/2π = 1.000e+01 GHz (elapsed time = 9.95e+01 s)

Residual norms for FGMRES solve
0 (restart 0) KSP residual norm 4.292106e-01
1 (restart 0) KSP residual norm 4.106243e-01
2 (restart 0) KSP residual norm 3.951131e-01
3 (restart 1) KSP residual norm 3.853653e-01
FGMRES solver did NOT converge in 3 iterations (avg. reduction factor: 5.667e-01)

--> Warning!
Linear solver did not converge, norm(Ax-b)/norm(b) = 1.820e-01 (norm(b) = 2.117e+00)!

 Sol. ||E|| = 6.533716e+00 (||RHS|| = 2.117080e+00)
 Field energy E (9.772e-03 J) + H (1.262e-02 J) = 2.240e-02 J
 Updating solution error estimates
 S[1][1] = -6.488e-01+3.379e-01i, |S[1][1]| = -2.716e+00, arg(S[1][1]) = +1.525e+02
 S[2][1] = -2.431e-01-4.430e-01i, |S[2][1]| = -5.928e+00, arg(S[2][1]) = -1.188e+02
 S[3][1] = +0.000e+00+0.000e+00i, |S[3][1]| = -inf, arg(S[3][1]) = +0.000e+00

Completed 0 iterations of adaptive mesh refinement (AMR):
 Indicator norm = 8.723e-01, global unknowns = 209195
 Max. iterations = 0, tol. = 1.000e-02

Elapsed Time Report (s)           Min.        Max.        Avg.
==============================================================
Initialization                   3.129       3.141       3.136
Operator Construction            8.549       8.879       8.721
Linear Solve                     3.889       3.961       3.926
  Setup                          2.885       3.214       3.040
  Preconditioner                43.063      43.134      43.099
Estimation                       0.528       0.618       0.578
  Construction                   2.416       2.418       2.417
  Solve                         38.133      38.194      38.168
Postprocessing                   2.555       2.632       2.584
Disk IO                          6.128       6.131       6.129
--------------------------------------------------------------
Total                          111.896     111.913     111.910

For an accurate solution, please increase meshing and reduce the tolerance.


Work In Progress ⏳#

We are studying the hyper-parameters needed to converge our simulations to that of Ansys/experimentally verified results with palace. Once that is done, we will update this tutorial with a more comprehensive guide and native API

License#

This code is a part of SQuADDS

Developed by Sadman Ahmed Shanto

This tutorial is written by Sadman Ahmed Shanto

© Copyright Sadman Ahmed Shanto & Eli Levenson-Falk 2025.

This code is licensed under the MIT License. You may obtain a copy of this license in the LICENSE.txt file in the root directory of this source tree.

Any modifications or derivative works of this code must retain thiscopyright notice, and modified files need to carry a notice indicatingthat they have been altered from the originals.