Extra features and tips#

Regroup external fluxes#

The Circuit instance generates a spanning tree, by default, for all the superconducting loops present in the circuit. In case the user prefers to use a different configuration of loops, the user can provide the list of branches with which external fluxes are grouped. Once, the closure branches are set, spanning tree is given by the set of all branches of the Circuit which do not contain the closure branches, thereby defining a custom spanning tree. Once that is done, user can then choose dynamic flux grouping for time dependent external fluxes.

Grouping of external flux variables with specific circuit branches is not unique in the case of time-independent flux. The user can provide the list of branches with which external fluxes are grouped. (Splitting flux between multiple branches is currently not supported.)

[31]:
zero_pi.branches
[31]:
[Branch(JJ, 1, 2, id_str: 0),
 Branch(JJ, 3, 4, id_str: 1),
 Branch(L, 2, 3, id_str: 2),
 Branch(L, 4, 1, id_str: 3),
 Branch(C, 1, 3, id_str: 4),
 Branch(C, 2, 4, id_str: 5)]
[32]:
closure_branches = [zero_pi.branches[3]]
zero_pi.configure(closure_branches=closure_branches, use_dynamic_flux_grouping=True)

Customize variable transformations#

It is possible to carry out variable transformations with a user-defined transformation matrix. For example, if we want to work with a more commonly seen set of variables for zero-pi circuit:

[ ]:
zero_pi = scq.Circuit(zp_yaml, from_file=False, ext_basis="harmonic")
[34]:
trans_mat = np.array([[ -1,  -1,  1,  1],
                       [ 1,  1,  1,  1],
                       [ 1,  -1, -1,  1],
                       [ -1,  1,  -1,  1]])*0.5
zero_pi.configure(transformation_matrix=trans_mat)
zero_pi.variable_transformation()
[34]:
$\displaystyle \left[ φ_{1} = 0.5 θ_{3} + 0.5 θ_{4} - 0.5 θ_{1} - 0.5 θ_{2}, \ φ_{2} = 0.5 θ_{1} + 0.5 θ_{2} + 0.5 θ_{3} + 0.5 θ_{4}, \ φ_{3} = 0.5 θ_{1} + 0.5 θ_{4} - 0.5 θ_{2} - 0.5 θ_{3}, \ φ_{4} = 0.5 θ_{2} + 0.5 θ_{4} - 0.5 θ_{1} - 0.5 θ_{3}\right]$
[35]:
zero_pi.sym_hamiltonian()
[35]:
$\displaystyle \left(40.0 Q_{2}^{2} + 0.03996 n_{1}^{2} + 0.03996 n_{g1}^{2} + 0.04 Q_{3}^{2} + 0.07992 n_{1} n_{g1}\right) - \left(- 0.008 θ_{2}^{2} - 0.008 θ_{3}^{2} + EJ \cos{\left(θ_{1} + θ_{2} \right)} + EJ \cos{\left((2πΦ_{1}) + θ_{2} - 1.0 θ_{1} \right)}\right)$

Options for automatic variable transformation#

  • After the periodic, frozen and free variables are identified, the transformation matrix is completed by adding on a set of linearly-independent vectors. This heuristic method for generating the transformation matrix may not always provide the “ideal” or expected choice of variables.

  • As an alternative, missing column vectors in the transformation matrix may be filled by suitable canonical basis vectors (drawn from the identity matrix). This choice is made by setting basis_completion="canonical" when creating the Circuit object. (The default is "heuristic".)

Handling large circuits#

  • For large circuits, the Hilbert space dimension grows exponentially with cutoffs. Numerical diagonalization is therefore challenging for large cutoffs, both in terms of runtime and memory. It is recommended to start diagonalization with small cutoffs, and gradually increase them as needed. This applies to both the direct and hierarchical diagonalization methods.

  • For hierarchical diagonalization: as diagonalization for systems with three or more variables takes much longer than for smaller systems, it is recommended to try and group less than three nodes for each subsystem, and build a hierarchy of subsystems.

  • Note that convergence of the eigenergies for large circuits can differ significantly according to the variable transformation used. It is advisable to (i) try changing the basis_completion option, (ii) define a custom transformation matrix, or (iii) add/remove the reference ground node in the YAML description of the circuit.