#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Mar 19 18:14:08 2019
Unit and variable conversions.
@author: Zlatko Minev
"""
from __future__ import (absolute_import, # Python 2.7 and 3 compatibility
division, print_function)
import numpy as np
import pandas as pd
from numpy import sqrt
from .basic import CalcsBasic
from .constants import (Planck, e_el, elementary_charge, fluxQ, hbar, pi, ħ, π,
ϕ0)
[docs]class Convert():
'''
Static container class for conversions of units and variables.
TEST CONVERSION:
.. code-block:: python
from pyEPR.toolbox.conversions import Convert
Lj_nH, Cs_fF = 11, 60
Convert.transmon_print_all_params(Lj_nH, Cs_fF);
'''
# Known SI prefixed
_prefix = {'y': -24, # yocto
'z': -21, # zepto
'a': -18, # atto
'f': -15, # femto
'p': -12, # pico
'n': -9, # nano
'u': -6, # micro
'm': -3, # mili
'c': -2, # centi
'd': -1, # deci
' ': 0,
'k': 3, # kilo
'M': 6, # mega
'G': 9, # giga
'T': 12, # tera
'P': 15, # peta
'E': 18, # exa
'Z': 21, # zetta
'Y': 24, # yotta
}
# Known SI units
_SI_units = ['H', # Henries
'F', # Farads
'Hz', # Hertz
'Ohm', # Ohms
'Ω', # Ohms
'Wb' # Webers
'J', # Joules
'A' # Amps
]
[docs] @staticmethod
def toSI(number, from_units: str):
r"""
Convert from SI unit prefix to regular SI units
If the from_units is ' ' or not in the prefix list,
then the unit is assumed to be
"""
if from_units in Convert._SI_units:
from_units = ' '
# else: we assume that the first letter is a prefix
return number*(10**Convert._prefix.get(from_units[0]))
[docs] @staticmethod
def fromSI(number, from_units: str):
r"""Convert a number with SI units, such as fF to F.
Arguments:
number {[numeric]} -- number
from_units {str} -- string
Returns:
numeric number, with units expanded
"""
if from_units in Convert._SI_units:
from_units = ' '
# else: we assume that the first letter is a prefix
return number*(10**(-Convert._prefix.get(from_units[0])))
@staticmethod
def _convert_num(out_func, in_num, in_units, out_units):
in_num = 1.0*in_num # to float
# convert units of input number
in_num = Convert.toSI(in_num, in_units)
out_num = out_func(in_num) # Assume func processes all in SI units
out_num = Convert.fromSI(out_num, out_units)
return out_num
[docs] @staticmethod
def Ej_from_Lj(Lj, units_in='nH', units_out='MHz'):
r'''
Josephson Junction energy from Josephson inductance.
Returns in MHz
:math:`E_j = \phi_0^2 / L_J`
'''
return Convert._convert_num(
# Plank to go from Joules to Hz
lambda _Lj: Planck**-1 * (ϕ0**2)/_Lj,
Lj, units_in, units_out)
[docs] @staticmethod
def Lj_from_Ej(Ej, units_in='MHz', units_out='nH'):
r'''
Josephson Junction ind from Josephson energy in MHZ.
Returns in units of nano Henries by default
:math:`E_j = \phi_0^2 / L_J`
'''
return Convert._convert_num(
lambda _x: (ϕ0**2.)/(_x*Planck), # Plank to go from Joules to Hz
Ej, units_in, units_out)
[docs] @staticmethod
def Ic_from_Lj(Lj, units_in='nH', units_out='nA'):
r'''
Josephson Junction crit. curr from Josephson inductance.
:math:`E_j = \phi_0^2 / L_J = \phi_0 I_C`
'''
return Convert._convert_num(
lambda _x: ϕ0/_x, # Plank to go from Joules to Hz
Lj, units_in, units_out)
[docs] @staticmethod
def Lj_from_Ic(Lj, units_in='nA', units_out='nH'):
r'''
Josephson Junction crit. curr from Josephson inductance.
:math:`E_j = \phi_0^2 / L_J = \phi_0 I_C`
'''
return Convert._convert_num(
lambda _x: ϕ0/_x, # Plank to go from Joules to Hz
Lj, units_in, units_out)
[docs] @staticmethod
def Ec_from_Cs(Cs, units_in='fF', units_out='MHz'):
r'''
Charging energy :math:`4E_c n^2`, where :math:`n=Q/2e`
Returns in MHz
:math:`E_{C}=\frac{e^{2}}{2C}J`
'''
return Convert._convert_num(
# Plank to go from Joules to Hz
lambda _x: Planck**-1 * (e_el**2.)/(2.*_x),
Cs, units_in, units_out)
[docs] @staticmethod
def Cs_from_Ec(Ec, units_in='MHz', units_out='fF'):
r'''
Charging energy :math:`4E_c n^2`, where :math:`n=Q/2e`
Returns in SI units, in Farads.
:math:`E_{C}=\frac{e^{2}}{2C}J`
'''
return Convert._convert_num(
# Plank to go from Joules to Hz
lambda _x: (e_el**2.)/(2.*_x*Planck),
Ec, units_in, units_out)
[docs] @staticmethod
def ZPF_from_LC(L, C):
r'''
Input units assumed to be identical
Returns Phi ZPF in and Q_ZPF in NOT reduced units, but SI
'''
Z = sqrt(L/C)
return (sqrt(hbar*Z/2.), sqrt(hbar/(2.*Z))) # Phi , Q
[docs] @staticmethod
def ZPF_from_EPR(hfss_freqs, hfss_epr_, hfss_signs, hfss_Ljs,
Lj_units_in='H', to_df=False):
r"""
Parameters:
Can be either Pandas or numpy arrays.
hfss_freqs : HFSS Freqs. (standard units: GHz, but these will cancel with Ejs) (list/Series)
hfss_epr : EPR ratio matrix, dim = M x J (2D array/DataFrame)
hfss_signs : Sign matrix, dim = M x J (2D array/DataFrame)
hfss_Ljs : Assumed in Henries (see Lj_units_in). (list/Series)
Lj_units_in : Default 'H' for Henries. Can change here.
Returns:
M x J matrix of reduced ZPF; i.e., scaled by reduced flux quantum.
type: np.array
and a tuple of matrices.
Example use:
ϕzpf, (Ωm, Ej, Pmj, Smj) = Convert.ZPF_from_EPR(hfss_freqs, hfss_epr, hfss_signs, hfss_Ljs, to_df=True)
"""
hfss_freqs, hfss_epr, hfss_signs, hfss_Ljs = map(
np.array, (hfss_freqs, hfss_epr_, hfss_signs, hfss_Ljs))
Ωd = np.diagflat(hfss_freqs)
Ej = Convert.Ej_from_Lj(
hfss_Ljs, units_in=Lj_units_in, units_out='GHz')
Ej = np.diagflat(Ej)
ϕzpfs = CalcsBasic.epr_to_zpf(hfss_epr, hfss_signs, Ωd, Ej)
if to_df:
ϕzpfs = pd.DataFrame(
ϕzpfs, columns='ϕ'+hfss_epr_.columns.values, index=hfss_epr_.index)
return ϕzpfs, (Ωd, Ej, hfss_epr, hfss_signs)
[docs] @staticmethod
def Omega_from_LC(L, C):
r'''
Calculate the resonant *angular* frequency
'''
return sqrt(1./(L*C))