Basic Magnetostatic Simulation of a Flux Line

Qiskit Metal Design

[1]:
%reload_ext autoreload
%autoreload 2

import qiskit_metal as metal
from qiskit_metal import designs, draw
from qiskit_metal import MetalGUI, Dict, Headings
import pyEPR as epr
from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround
from qiskit_metal.qlibrary.tlines.meandered import RouteMeander
from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket
#
from SQDMetal.Comps.Xmon import Xmon
from SQDMetal.Comps.Capacitors import CapacitorGapPinStretch
from SQDMetal.Comps.Wires import WireTaperPinStretch, WirePinStretch
from SQDMetal.Comps.FluxLines import FluxLineTPin
from SQDMetal.Comps.Junctions import JunctionDolanPinStretch

design = designs.DesignPlanar({}, True)
design.chips.main.size['size_x'] = '400um'
design.chips.main.size['size_y'] = '400um'

Xmon(design, 'leXmon', options=Dict(pos_x=0, pos_y=0,
                                    vBar_width='24um', hBar_width='24um', vBar_gap='16um', hBar_gap='16um',
                                    cross_width='144um', cross_height='144um',
                                    gap_up='24um', gap_left='0um', gap_right='24um'))

FluxLineTPin(design, 'flux_line_T', options=Dict(ref_comp='leXmon', ref_pin='right',
                                                 width=f'100um',
                                                 trace_width=f'8um',
                                                 trace_gap=f'12um',pin_dist='24um'))
WireTaperPinStretch(design, 'flux_ln_taper', options=Dict(pin_inputs={'start_pin': {'component': 'flux_line_T', 'pin': 'a'}},
                                                   trace_width=f'20um', trace_gap=f'28um', taper_length='50um'))
WirePinStretch(design, 'flux_ln_wire', options=Dict(pin_inputs=Dict(start_pin=Dict(component=f'flux_ln_taper',pin='a')),
                                                    dist_extend='54um', trace_width=f'20um', trace_gap=f'28um'))
CapacitorGapPinStretch(design, f'capProng', options=Dict(cpw_width=f'20um',
                                            pin_inputs=Dict(start_pin=Dict(component=f'leXmon',pin='left')),
                                            dist_extend='120um',
                                            cap_width=f'50um',
                                            cap_gap='3um',
                                            gnd_width='1um',
                                            len_diag='0um', len_flat=f'50um',
                                            side_gap=f'10um', init_pad='10um'
                                            ))

############################
JunctionDolanPinStretch(design, 'junction', options=Dict(pin_inputs=Dict(start_pin=Dict(component=f'flux_line_T',pin='t')),
                                                         dist_extend='25um',
                                                         finger_width='0.4um', t_pad_size='0.385um',
                                                         squid_width='5.4um', prong_width='0.9um',
                                                         layer=2));
############################


# gui = MetalGUI(design)
# gui.rebuild()
# gui.autoscale()

The idea is to run this through a shadow-evaporated Josephson junction (notice that 'junction' is in layer 2). So let’s quickly do the PVD simulation to ensure that there is an enclosed loop:

[2]:
from SQDMetal.Utilities.PVD_Shadows import PVD_Shadows
%matplotlib inline
design.chips['main']['evaporations'] = Dict(
    layer2=Dict(
        bottom_layer='200nm',
        top_layer='100nm',
        undercut='200nm',
        pvd1 = Dict(
        angle_phi = '0',
        angle_theta = '-45',
        metal_thickness = '20nm'
        ),
        pvd2 = Dict(
        angle_phi = '0',
        angle_theta = '45'
        )
    )
)
pvdSh = PVD_Shadows(design)
pvdSh.plot_layer(2,'separate', plot_mask=True)
../_images/examples_Palace_Magnetostatic_Example_3_0.png

We can extract the largest interior area for surface flux integration

[3]:
int_area = pvdSh.get_shadow_largest_interior_for_component('junction')[1]
int_area
[3]:
../_images/examples_Palace_Magnetostatic_Example_5_0.svg

Magnetostatic Simulation

Now to run the Palace simulation (make sure to update the path to the Palace binary first)

[ ]:
from SQDMetal.PALACE.Inductance_Simulation import PALACE_Inductance_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'
                "solver_order": 2,                                 #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": 200,                              #number of solver iterations
                "fillet_resolution":12,                            #number of vertices per quarter turn on a filleted path
                "palace_dir":"~/spack/opt/spack/linux-ubuntu24.04-zen2/gcc-13.3.0/palace-develop-36rxmgzatchgymg5tcbfz3qrmkf4jnmj/bin/palace",#"PATH/TO/PALACE/BINARY",
                "num_cpus": 16
                }

#Create the Palace Eigenmode simulation
mag_sim = PALACE_Inductance_Simulation(name ='Test1',                                              #name of simulation
                                        metal_design = design,                                      #feed in qiskit metal design
                                        sim_parent_directory = "",                                  #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
                                        create_files = True)                                        #create mesh and config files

#add in metals from the first layer
mag_sim.add_metallic(1)
mag_sim.add_metallic(2, evap_mode=None)

#add ground plane into simulation
mag_sim.add_ground_plane()

#Create a lumped element port for the Josephson junction and assign Jospehson inductance and junction capacitance
# mag_sim.create_port_JosephsonJunction('Q1', L_J = 11e-9, C_J = 0e-15)
mag_sim.create_current_source_with_Uclip_on_Route('flux_ln_wire', 'end')

mag_sim.add_integration_area(int_area)

#Fine mesh the qubit and resonator - min_size/max_size is the min/max mesh element size
mag_sim.fine_mesh_components(['junction', 'flux_ln_wire', 'flux_ln_taper'], min_size=5e-6, max_size=50e-6, taper_dist_min=20e-6, metals_only=True)
# mag_sim.fine_mesh_along_path(qObjName='readout', dist_resolution=10e-6, min_size=12e-6, max_size=150e-6, taper_dist_min=10e-6)

#Prepare the simulation files - mesh file (.msh) and config file (.json)
mag_sim.prepare_simulation()
[5]:
mag_sim.open_mesh_gmsh()
[ ]:
flux_per_amp = mag_sim.run()

The returned value is the flux per Ampere. We can normalise it to flux quanta for 1mA to get a reasonable estimate of the flux-tunability:

[8]:
flux_per_amp / 2.067833848e-15 * 0.001
[8]:
array([[0.02227944]])
[ ]: