Source code for qiskit_metal.analyses.hamiltonian.transmon_analytics

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
This code calculates the energy eigenvalues of the transmon qubit cooper pair box
as a function of the offset charge and plots the corresponding results.

Key References:
    - J. Koch et al. "Charge-insensitive qubit design derived from the Cooper pair box"
      Phys. Rev. A. 76, 042319 (2007).

"""

import numpy as np
import matplotlib.pyplot as plt

from qiskit_metal.analyses.hamiltonian.transmon_CPB_analytic import mathieu_level

__all__ = ["kidx", "kidx_raw", "plot_eigenvalues", "transmon_eigenvalue"]


[docs] def kidx_raw(m, my_ng): """ This function calculates the integers which correct sort the eigenstates and eigenenergies of the solution to Mathieu's equation. Args: m (int): The energy level of the qubit (m=0,1,2,3,etc.) my_ng (float): the offset charge of the Josephjunction island (in units of 2e) Returns: float: the calculated index """ if my_ng == 0: return m + 1.0 - ((m + 1.0) % 2.0) return ( m + 1.0 - ((m + 1.0) % 2.0) + 2.0 * my_ng * ((-1.0) ** (m - 0.5 * (np.sign(my_ng) - 1.0))) )
[docs] def kidx(m, my_ng): """ This function is a placeholder which performs an additional modulo operation with an offset of ng=0.5, but is not necessary when only integer values of kidxRAW(m, my_ng) are used. If non-integer values of kidxRAW are used, then the modulo operation below needs to be updated to include the offset. Args: m (int): The energy level of the qubit (m=0,1,2,3,etc.) ng (float): the offset charge of the Josephjunction island (in units of 2e) Returns: float: the calculated energy eigenvalue, after an ng=0.5 offset. """ return kidx_raw(m, my_ng)
# define the Josephson to charging energy ratio E_J / E_C RATIO = 1.0 # define the charing energy E_C = 1.0
[docs] def transmon_eigenvalue(m, my_ng, Ej=None, Ec=None): """ This function calculate the energy eigenvalue of the transmon qubit for a given energy level (m) and offset charge (my_ng), from Mathieu characteristic values (Koch et al. Eq. 2.11), via :func:`~qiskit_metal.analyses.hamiltonian.transmon_CPB_analytic.mathieu_level`: even levels use the even (``a``) and odd levels the odd (``b``) characteristic value at integer order, and non-integer orders (any ``my_ng`` other than 0 or 1/2 modulo 1) are computed from the Hill matrix. Args: m (int): The energy level of the qubit (m=0,1,2,3,etc.) my_ng (float): the offset charge of the Josephjunction island (in units of 2e) Ej (float): Josephson energy. Defaults to ``RATIO * E_C`` (module constants). Ec (float): Charging energy. Defaults to the module constant ``E_C``. Returns: float: the calculated energy eigenvalue. """ if Ec is None: Ec = E_C if Ej is None: Ej = RATIO * Ec return mathieu_level(m, my_ng, Ej, Ec)
# extremely coarse grid: only three points from -0.5 to 0.5. This so that only integer values # of the index are used in the calculation of the Mathieu characteristic value. ng = np.linspace(-0.5, 0.5, 3) # ng is periodic extending from -2 to 2: ng_periodic = np.linspace(-2.0, 2.0, 9) # define energies between (-0.5, 0.5) as empty lists. E0 = [] E1 = [] E2 = [] E3 = [] # define periodic energies between (-2.0, 2.0) E0_periodic = [None] * 9 E1_periodic = [None] * 9 E2_periodic = [None] * 9 E3_periodic = [None] * 9 # calculate the energies for m=0,1,2 at each value of offset charge for i in ng: E0.append(transmon_eigenvalue(0, i)) E1.append(transmon_eigenvalue(1, i)) E2.append(transmon_eigenvalue(2, i)) E3.append(transmon_eigenvalue(3, i)) # define the periodic eigen energies based on the values between (-0.5,0.5) for i in range(len(E0_periodic)): E0_periodic[0] = E0[1] E0_periodic[1] = E0[0] E1_periodic[0] = E1[1] E1_periodic[1] = E1[0] E2_periodic[0] = E2[1] E2_periodic[1] = E2[0] E3_periodic[0] = E3[1] E3_periodic[1] = E3[0] if i > 1: E0_periodic[i] = E0_periodic[i - 2] E1_periodic[i] = E1_periodic[i - 2] E2_periodic[i] = E2_periodic[i - 2] E3_periodic[i] = E3_periodic[i - 2]
[docs] def plot_eigenvalues(): """ This function actually creates the plot(s) of eigenvalues as a function of offset charge. No arguments need to be passed. Returns: A plot of the eigenvalues as a function of offset charge. """ # plot the PERIODIC eigen energies between (-2.0, 2.0) plt.plot(ng_periodic, E0_periodic, "k") # m=0 plt.plot(ng_periodic, E1_periodic, "r") # m=1 plt.plot(ng_periodic, E2_periodic, "b") # m=2 plt.plot(ng_periodic, E3_periodic, "m") # m=3 plt.xlabel("Offset Charge [ng]") plt.ylabel("Energy E_m[ng]")