Bases, truncation, and convergence#

[1]:
import scqubits as scq
import numpy as np

zp_yaml = """# zero-pi
branches:
- ["JJ", 1,2, EJ = 10, 20]
- ["JJ", 3,4, EJ, 20]
- ["L", 2,3, 0.008]
- ["L", 4,1, 0.008]
- ["C", 1,3, 0.02]
- ["C", 2,4, 0.02]
"""

zero_pi = scq.Circuit(zp_yaml, from_file=False)

Basis choices#

For periodic degrees of freedom scqubits employs the discrete charge basis.

For extended degrees of freedom two choices are available: - ext_basis = "discretized" (default) Discretizes the variables for extended degrees of freedom. - ext_basis = "harmonic"Employs the harmonic-oscillator basis for th extended degrees of freedom (taking the potential to be the one arising from the geometric inductance).

For instance, the following would switch the treatment of the extended degrees of freedom to using harmonic-oscillator basis:

zero_pi = scq.Circuit(zp_yaml, from_file=False, ext_basis="harmonic")

Truncation, cutoffs and convergence#

Each variable index comes with a cutoff for basis truncation. The corresponding attribute names can be listed like this:

[2]:
zero_pi.cutoff_names
[2]:
['cutoff_n_1', 'cutoff_ext_2', 'cutoff_ext_3']

These cutoffs must be varied by the user to ensure convergence. We distinguish two cutoff types:

Cutoffs for periodic degrees of freedom:#

  • cutoff_n_<i> - use all the integer charge states in the range [-cutoff_n_<i>, cutoff_n_<i>] for the periodic degree of freedom \(i\).

Cutoffs for extended degrees of freedom:#

  • cutoff_ext_<i> - the meaning of this cutoff differs according to the choice of basis, specified via ext_basis upon initialization of the Circuit instance.

    • ext_basis = "discretized": For discretization of \(\theta_i\), cutoff_ext_<i> sets the number of points used to in the “spatial” range given by the attribute discretized_phi_range.

    • ext_basis = "harmonic": When using the harmonic oscillator basis, cutoff_ext_<i> sets the number of harmonic oscillator states admitted to the basis set for the extended degree of freedom \(i\).

[3]:
zero_pi.cutoff_n_1 = 5
zero_pi.cutoff_ext_2 = 10
zero_pi.cutoff_ext_3 = 10

All the discretized variable ranges can be viewed as:

[4]:
zero_pi.discretized_phi_range
[4]:
{2: (-18.84955592153876, 18.84955592153876), 3: (-18.84955592153876, 18.84955592153876)}

These are the default range settings \([-6\pi, 6\pi]\); discretized variable ranges can be changed with

[5]:
zero_pi.set_discretized_phi_range(var_indices=(2,3), phi_range=(-6*np.pi, 6*np.pi))

Example: eigenenergies#

Now, we can call eigenvals() to obtain low-lying eigenenergies of the circuit Hamiltonian:

[6]:
zero_pi.eigenvals()
[6]:
array([-13.25816395, -13.25645441, -13.24363991, -13.24193037,
       -12.134373  , -12.13436007])

Increasing the above cutoff values reveals that these eigenvalues have not converged yet. Increasing cutoff values increases the Hilbert space dimension and, thus, increases memory requirements and runtime. A strategy that can help mitigate this problem is the use of Hierarchical diagonalization.

Chosing basis states for each of the subsystems#

It is also possible to chose a basis states for each of the subsystems independently. We start with defining a particular circuit

[14]:
full_yaml = f"""branches:
- [JJ, 0, 1, 10, 2.5]
- [L, 2, 1, 0.5]
- [L, 0 , 2 , 10]
### coupling element
- [C, 2, 3, 5]
### tunable resonator
- [JJ, 0, 3, 50, 2]
- [C, 3, 4, 0.5]
- [L, 4, 0, 8]
"""
circ = scq.Circuit(full_yaml, from_file=False, ext_basis="discretized")

and see its internal structure

[16]:
circ.info()
$H=\left(40.0 n_{1}^{2} + 40.0 n_{g1}^{2} + 22.0 Q_{4}^{2} + 9.5 Q_{2}^{2} + 11.5 Q_{3}^{2} + 80.0 n_{1} n_{g1} + 11.0 Q_{2} Q_{3} + 44.0 Q_{4} n_{1} + 44.0 Q_{4} n_{g1} - 24.0 Q_{3} Q_{4} - 20.0 Q_{2} Q_{4} - 26.0 Q_{3} n_{1} - 26.0 Q_{3} n_{g1} - 38.0 Q_{2} n_{1} - 38.0 Q_{2} n_{g1}\right) + \left(5.0 θ_{4}^{2} + 10.0 θ_{2}^{2} + 9.0 θ_{3}^{2} - 10.0 \cos{\left(θ_{2} + θ_{3} + θ_{4} - 1.0 (2πΦ_{1}) \right)} - 50.0 \cos{\left(θ_{1} + θ_{2} + θ_{3} - 1.0 (2πΦ_{1}) \right)} + 10.0 θ_{3} θ_{4} - 10.0 θ_{2} θ_{4} - 18.0 θ_{2} θ_{3}\right)$
Operators (flux, charge) - cutoff: Discrete Charge Basis: $(θ1, n1) - 5$, Discretized Phi basis: $(θ2, Q2) - 30$, $(θ3, Q3) - 30$, $(θ4, Q4) - 30$,
External fluxes (symbol, default value): $(Φ1, 0.0)$,
Offset charges (symbol, default value): $(ng1, 0.0)$,

we can now adjust the hierarchy of diefferent degrees of freedom, while defining a particular basis set for each

[17]:
circ = scq.Circuit(full_yaml, from_file=False, ext_basis="discretized")
trans_mat = np.array([[1, 0, 0, 0],
                      [0, 1, 0, 0],
                      [0, 0, 1, 0],
                      [0, 0, 0, 1]])
circ.configure(transformation_matrix=trans_mat, closure_branches=[circ.branches[0], circ.branches[-1]]) # chosing a transformation matrix, and closure branches for the two loops.
circ._configure(system_hierarchy=[[[1], [2]], [3, 4]], subsystem_trunc_dims=[[10, [10, 10]], 20], ext_basis=[["harmonic", "discretized"], "discretized"])

and see the updated circuit detailed information

[18]:
circ.info()
$H=\left(8.0 n_{3}^{2} + 8.0 n_{g3}^{2} + 10.0 Q_{1}^{2} + 10.0 Q_{4}^{2} + 28.0 Q_{2}^{2} + 16.0 Q_{2} Q_{4} + 16.0 Q_{2} n_{3} + 16.0 Q_{2} n_{g3} + 16.0 Q_{4} n_{3} + 16.0 Q_{4} n_{g3} + 16.0 n_{3} n_{g3}\right) + \left(0.25 θ_{1}^{2} + 4.0 θ_{4}^{2} + 5.25 θ_{2}^{2} - 10.0 \cos{\left((2πΦ_{1}) + θ_{1} \right)} - 50.0 \cos{\left(θ_{3} \right)} - 0.5 θ_{1} θ_{2}\right)$
Operators (flux, charge) - cutoff: Discrete Charge Basis: $(θ3, n3) - 5$, Discretized Phi basis: $(θ2, Q2) - 30$, $(θ4, Q4) - 30$, Harmonic oscillator basis: $(θ1, Q1) - 30$,
External fluxes (symbol, default value): $(Φ1, 0.0)$, $(Φ2, 0.0)$,
Offset charges (symbol, default value): $(ng3, 0.0)$,
System hierarchy: [[[1], [2]], [3, 4]]
Truncated Dimensions: [[10, [10, 10]], 20]