Worked Examples =============== This page introduces the main ways to use ``pygenstates``. The examples are adapted from the worked notebooks in the repository's `examples `_ folder. The solver can be applied to a variety of systems, but several examples use circuit QED notation because that is one of the motivating applications. The continuous solver represents Hamiltonians of the form .. math:: \left[-\sum_i k_{ii}\frac{\partial^2}{\partial x_i^2} -\sum_{im} \left(-k_{c,i,nm}\frac{d}{dx_i}+v_{c,i,nm}x_i\right) |n\rangle\langle m|+\mathrm{h.c.} For example: .. code-block:: python k_coup = [ {(0, 1): E01_phi, (1, 2): E12_phi}, # derivative couplings along axis 0 {(0, 2): E02_theta}, # derivative couplings along axis 1 ] v_coup = [ {(0, 1): V01_phi}, {}, ] For derivative couplings, the conjugate partner is filled with the sign needed to produce a Hermitian total derivative operator. For position couplings, the conjugate partner is filled in the usual Hermitian way. The full coupled wavefunction returned by the solver has components :math:`\Psi_i(\phi)=\langle \phi,i|\Psi\rangle`, subject to the normalization :math:`\int\sum_i|\Psi_i(\phi)|^2\,d\phi=1`. With :math:`\hbar=1`, the oscillator level spacing for this convention is :math:`2\sqrt{E_CE_L}`. The example below chooses ``E_q`` to match that spacing and uses a weak derivative coupling ``E_g``. .. code-block:: python hbar = 1.0 GHz = 1.0 E_C = hbar * (2 * np.pi * 2.0 * GHz) E_L = hbar * (2 * np.pi * 6.0 * GHz) E_g = hbar * (2 * np.pi * 0.05 * GHz) omega_osc = 2.0 * np.sqrt(E_C * E_L) / hbar E_q = hbar * omega_osc H1 = np.array([ [0.0, 0.0], [0.0, E_q], ]) vals_c, vecs_c, xlists_c = eg.Ceigensolver( lambda x: E_L * x**2, H1, N=[801], domain=[(-4, 4)], k_diag=[E_C], k_coup=E_g, Enum=6, which="SA", ) x = xlists_c[0] component_weight = np.sum(np.abs(vecs_c)**2, axis=2) * (x[1] - x[0]) print("Coupled eigenvalues:", np.real(vals_c)) print("Discrete component weights:", component_weight) .. figure:: _static/examples/advanced_cell4_plot1.png :alt: Coupled oscillator and two-level eigenstate components. :width: 90% The two discrete components of several coupled eigenstates, shifted by their eigenvalues. .. figure:: _static/examples/advanced_cell4_plot2.png :alt: Bar chart of discrete-basis participation for coupled eigenstates. :width: 75% Component weights show how much each eigenstate occupies each discrete basis level. Coupled Josephson Junctions and Mixed Derivatives ------------------------------------------------- The standard solver supports mixed spatial derivative terms through ``k_cross``. Mixed derivative terms are not present for a single particle in ordinary Cartesian coordinates, but they are useful for coupled generalized momenta, such as in circuit-QED phase coordinates. For two coupled Josephson junction phases, one possible Hamiltonian is: .. figure:: _static/examples/coupled_junctions.png :alt: Circuit diagram for two coupled Josephson junctions. :width: 85% Circuit model for two coupled Josephson junctions. .. math:: H=-E_{C,0}\frac{\partial^2}{\partial \phi_0^2} -E_{C,1}\frac{\partial^2}{\partial \phi_1^2} -E_g\frac{\partial^2}{\partial \phi_0\partial \phi_1} +U(\phi_0,\phi_1), with .. math:: U(\phi_0,\phi_1)=E_{J,0}\left(1-\sin\phi_0\right) +E_{J,1}\left(1-\sin\phi_1\right). Here :math:`E_{C,i}=2e^2/C_i` and :math:`E_g\approx 4e^2 C_g/(C_0C_1)` for :math:`C_g\ll C_0,C_1`. The diagonal kinetic terms are passed with ``k_diag`` and the mixed derivative is represented with ``k_cross={(0, 1): E_g}``. The tuple ``(0, 1)`` indicates the coordinate pair :math:`(\phi_0,\phi_1)`. .. code-block:: python E_C0 = 2 * np.pi * 10.0 E_C1 = 2 * np.pi * 10.0 E_J0 = 2 * np.pi * 2.0 E_J1 = 2 * np.pi * 2.0 E_g = 2 * np.pi * 0.05 def U_phase(phi0, phi1): return E_J0 * (1 - np.sin(phi0)) + E_J1 * (1 - np.sin(phi1)) vals_phase, vecs_phase, phase_lists = eg.eigensolver( U_phase, N=[121, 121], domain=[(-np.pi, 2*np.pi), (-np.pi, 2*np.pi)], k_diag=[E_C0, E_C1], k_cross={(0, 1): E_g}, Enum=5, method="finite_difference", which="SA", ) print("Eigenvalues:", vals_phase) .. figure:: _static/examples/advanced_cell6_plot1.png :alt: Two-phase potential and eigenfunction for coupled Josephson junctions. :width: 100% The Josephson potential and the lowest eigenfunction from a 2D solve with a mixed derivative term. .. figure:: _static/examples/advanced_cell6_plot2.png :alt: Lowest eigenvalues for the coupled phase problem. :width: 75% Lowest eigenvalues from the coupled phase problem. Backend Comparison with the Airy Problem ---------------------------------------- The available backend names can be inspected programmatically: .. code-block:: python print(eg.available_methods()) The default method is ``"finite_difference"``. The ``"FEM"`` backend uses ``scikit-fem`` and supports one-, two-, and three-dimensional problems. The finite-difference backend supports arbitrary dimension, subject to the memory and runtime cost of the resulting sparse matrix. The Airy problem, .. math:: H=-k\frac{d^2}{dx^2}+|x|, is a useful comparison because the decaying solutions are Airy functions. Even states are fixed by zeros of :math:`\mathrm{Ai}'`, and odd states are fixed by zeros of :math:`\mathrm{Ai}`. This gives an analytic reference for comparing the finite-difference and finite-element backends. Discontinuous or non-differentiable potentials can reduce finite-difference accuracy, especially when high-precision eigenvectors are required. The FEM backend provides an alternative discretization that can behave better near non-smooth points. .. code-block:: python U_abs = lambda x: np.abs(x) common = dict( U=U_abs, N=[801], domain=[(-12, 12)], k_diag=[1], Enum=5, which="SA", ) vals_fd, vecs_fd, xlists_fd = eg.eigensolver( method="finite_difference", **common, ) vals_fem, vecs_fem, xlists_fem = eg.eigensolver( method="FEM", intorder=None, **common, ) print("Finite difference:", vals_fd) print("FEM: ", vals_fem) .. figure:: _static/examples/advanced_cell9_plot1.png :alt: Finite-difference Airy eigenfunctions shifted by eigenvalue. :width: 90% Finite-difference eigenfunctions for :math:`U(x)=|x|`, shifted by their eigenvalues. .. figure:: _static/examples/advanced_cell9_plot2.png :alt: Airy eigenvector error comparison for finite difference and FEM. :width: 90% Eigenvector error against the analytic Airy solution for finite difference and FEM. The full notebooks include the plotting setup and analytic-comparison helper functions used to generate these figures.