Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs_src/source/tutorials/arbitrary_dipole/Circuit_example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
D;-1,-2;0,-2;;E2, E3, E4
C;-2,-2;-1,-2;;C1
W;-2,-3;-2,-2;;
W;-1,-3;-1,-2;;
L;-2,-3;-1,-3;;L
C;0,-2;1,-2;;C2
W;0,-3;0,-2;;
W;1,-3;1,-2;;
L;0,-3;1,-3;;L
C;2,-2;3,-2;;C3
W;2,-3;2,-2;;
W;3,-3;3,-2;;
L;2,-3;3,-3;;L
G;4,-2;3,-2;;
W;1,-2;2,-2;;
G;-3,-2;-2,-2;;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
325 changes: 325 additions & 0 deletions docs_src/source/tutorials/arbitrary_dipole/SNAIL_example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simulate an arbitrary indictive dipole using qucat\n",
"\n",
"## 1 Generating the circuit\n",
"\n",
"This new features of qucat allows to insert an arbitrary purely inductive dipole, simplified at an arbitrary order. Only the labels must be provided.\n",
"\n",
"Here's what it looks like when constructing a circuit with the GUI :\n",
"\n",
"![circuit](Circuit_from_the_GUI.png)\n",
"\n",
"Using the general feature \"Dipole\" is only possible without specifying any energy : Only labels must be provided, so the values must be given when performing a specific calculation.\n",
"\n",
"![Help_GUI](Editor_help.png)\n",
"\n",
"Once printed, it will look like this :\n",
"\n",
"![printed_circuit](printed_circuit.png)\n",
"\n",
"\n",
"The diode-like form shows the orientation of the dipole.\n",
"\n",
"\n",
"The number of labels the dipole has corresponds to the order at which it is simulated : Here there are 3 labels, so it will take into account the fourth first orders, as qucat usually does : \n",
"\n",
"$$U_{dipole}(\\phi) = h(\\frac{E2}{2!}\\phi^2 + \\frac{E3}{3!}\\phi^3 + \\frac{E4}{4!}\\phi^4)$$\n",
"\n",
"In this expression, the $Ei$ are provided in Hertz.\n",
"\n",
"If this dipole is a Josephson element, we have, forgetting the constant term and expanding at order fourth :\n",
"\n",
"$$U_{J}(\\phi) = E_J(1 - \\cos\\phi) = \\frac{E_J}{2}\\phi^2 - \\frac{E_J}{4!}\\phi^4$$\n",
"\n",
"So in this case : $E2 = \\frac{E_J}{h}, E3 = 0, E4 = -\\frac{E_J}{h}$.\n",
"\n",
"Notes : \n",
"- The dipoles are polarized, since odd orders are non zero in general. The orientation matters.\n",
"- One cannot set an element to strictly zero to prevent qucat errors. Provide very negligible values.\n",
"\n",
"\n",
"\n",
"## 2 Hamiltonian\n",
"\n",
"Once the hamiltonian decomposed into eigenmodes, the hamiltonian of the circuit writes :\n",
"\n",
"$$ H = \\sum_m{\\hbar \\omega_m \\hat{a}^\\dagger_m \\hat{a}_m} + \\sum_j \\sum_{n\\geq 3}\\frac{\\partial^{n} U_j}{\\partial \\phi^{n}}|_0\\hat{\\phi}_j^n$$\n",
"\n",
"with :\n",
"- $\\hat{\\phi}_j$ being the phase across the j-th non linear element\n",
"- $m$ the modes of the circuit\n",
"- $\\omega_m/2\\pi$ the frequency of the $m$-th mode\n",
"- $\\hat{a}_m$ the annihilator of the $m$-th mode\n",
"- $U_j(\\phi)$ the inductive energy of the j-th non linear dipole, assuming its minimum is for $\\phi = 0$\n",
"\n",
"\n",
"Using $\\hat{\\phi}_j = \\sum_m \\phi_{zpf, m, j}\\hat{\\phi}_m = \\sum_m \\phi_{zpf, m, j}(\\hat{a}^\\dagger_m + \\hat{a}_m)$ :\n",
"\n",
"$$ H = \\sum_m{\\hbar \\omega_m \\hat{a}^\\dagger_m \\hat{a}_m} + \\sum_j \\sum_{n\\geq 3}\\frac{\\partial^{n} U_j}{\\partial \\phi^{n}}[\\sum_m \\phi_{zpf, m, j}(\\hat{a}^\\dagger_m + \\hat{a}_m)]^n$$\n",
"\n",
"\n",
"At fourth order, following qucat formalism (applying rotating wave approximation) and adding the third order term:\n",
"\n",
"$$ H = \\hbar\\sum_m \\big[( \\omega_m - \\sum_{n}\\frac{\\chi_{mn}}{2})\\hat{a}_m^\\dagger\\hat{a}_m\n",
"-\\frac{A_m}{2} \\hat{a}_m^\\dagger \\hat{a}_m^\\dagger \\hat{a}_m \\hat{a}_m \n",
"-\\sum_{n}\\chi_{mn}\\hat{a}_m^\\dagger \\hat{a}_m \\hat{a}_n^\\dagger \\hat{a}_n\\big] \n",
"+ \\sum_{m, n, o}(\\gamma_{mno}^* \\hat{a}_m^\\dagger \\hat{a}_n^\\dagger \\hat{a}_o + \\gamma_{mno} \\hat{a}_m \\hat{a}_n \\hat{a}_o^\\dagger)$$\n",
"\n",
"The modified version of qucat returns also the mixing terms $\\gamma_{mno}$. Note that only the terms with $m\\neq n, n\\neq o, m\\neq o$ are likely to conserve the energy.\n",
"\n",
"For further orders, I added a function returning the full hamiltonian as a sympy expression. The simplifications using the rotating wawe approximation for example can then be perfomed afterwards.\n",
"\n",
"## Example : the SNAIL\n",
"\n",
"The SNAIL is a dipole containing three little Josephson juntions on one side, and one big on the other side :\n",
"\n",
"<img src=\"SNAIL_scheme.png\" width = \"500\"/>\n",
"\n",
"*SNAIL scheme taken from N. E. Frattini, V. V. Sivak, A. Lingenfelter, S. Shankar et M. H. Devoret : Optimizing the Nonlinearity and Dissipation of a SNAIL Parametric Amplifier for Dynamic Range. Physical Review Applied, 10(5):1–17, 2018.*\n",
"\n",
"Its inductive energy writes :\n",
"\n",
"$$U_{SNAIL}(\\phi) = -E_J(\\alpha \\cos\\phi + 3 \\cos \\frac{\\phi_0-\\phi}{3})$$\n",
"\n",
"It depends on :\n",
"- the flux bias in its loop\n",
"- a characteristic Josphson energy E_J\n",
"- a characteristic coeeficient $\\alpha$\n",
"\n",
"Having $\\phi_0$, $E_J$ and $\\alpha$, one can find the minimum of this inductive energy and develop it around it : The developpement will give the coeficient to feed qucat with :\n",
"\n",
"$$U_{SNAIL}|_{\\alpha, E, phi_{ext}}(\\phi) = \\frac{E2}{2}(\\phi-\\phi_{min})^2 + \\frac{E3}{6}(\\phi-\\phi_{min})^3 + \\frac{E4}{24}(\\phi-\\phi_{min})^4$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from scipy.constants import *\n",
"import matplotlib.pyplot as plt\n",
"from scipy.optimize import *\n",
"import numpy as np\n",
"import sympy as sp\n",
"import qucat as qc\n",
"\n",
"\n",
"## Parameters for the circuit\n",
"order = 4 #order at which the SNAIL will be expanded\n",
"alpha = 0.12\n",
"phi_0 = h/(2*e) #the flux quantum\n",
"L = 1e-8 #the Jospehson inductance of the small junctions\n",
"E_J = 1/h*phi_0**2/(4*pi)**2/L #the Josephson energy of the small junctions, in Hz\n",
"C1 = 10e-14 #capacities of the circuit\n",
"C2 = 15e-14\n",
"C3 = 20e-14\n",
"\n",
"\n",
"\n",
"#We use sympy to create the derivatives of the energy \n",
"phi = sp.Symbol(\"phi\")\n",
"a = sp.Symbol(\"a\")\n",
"E = sp.Symbol(\"E\")\n",
"phi_ext = sp.Symbol(\"phi_ext\")\n",
"\n",
"U_sym = -E*(a*sp.cos(phi) + 3*sp.cos((phi_ext-phi)/3))\n",
"dnU_sym =[sp.diff(U_sym, phi, i) for i in range(order+1)]#Symbolic expression for the derivatives\n",
"dnU = [sp.lambdify([phi, E, a, phi_ext], c) for c in dnU_sym] #creates the python functions for the derivatives:\n",
"#dnU[i](E, a, phi_ext, phi)\n",
"\n",
"\n",
"def make_dict(E, a, phi_ext): #constructs the dictionnary to give as keyword arguments\n",
" labels = {\"C1\":C1, \"C2\":C2, \"C3\":C3, \"L\":L}\n",
" phi_min = (minimize(dnU[0], 11, method = 'L-BFGS-B' , bounds = [(-1, 7*np.pi)],args = (1, alpha, phi_ext)).x)[0]%(6*np.pi) #The point from which the potential will be expanded\n",
" for i,c in enumerate(dnU[2::]):\n",
" labels[\"E\"+str(i+2)] = E*c(1, a, phi_ext, phi_min)\n",
" return labels\n",
"\n",
"def make_dict_vect(E, a, phi_ext): #same function but vectorized, to sweep phi_ext\n",
" labels = {\"C1\":[C1 for c in phi_ext], \n",
" \"C2\":[C2 for c in phi_ext], \n",
" \"C3\":[C3 for c in phi_ext], \n",
" \"L\":[L for c in phi_ext]}\n",
" for i, c in enumerate(dnU[2::]): #initialisation of the lists\n",
" labels[\"E\"+str(i+2)] = []\n",
"\n",
" phi_min = [0]\n",
"\n",
" for c in phi_ext:\n",
" phi_min.append((minimize(dnU[0], 11, method = 'L-BFGS-B' , bounds = [(-1, 7*np.pi)],args = (1, alpha, c)).x)[0]%(6*np.pi))\n",
" phi_min.pop(0) #I struggled with the optimization, these parameters work for this example.\n",
" \n",
" for i,c in enumerate(phi_min):\n",
" for j, d in enumerate(dnU[2::]):\n",
" labels[\"E\"+str(j+2)] = labels[\"E\"+str(j+2)]+[d(c, E, a, phi_ext[i])]\n",
" return labels"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"At this point, one can simply need to construct the circuit (the one given in 'Generating the circuit\", with every element being given a label, not a value :"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"circuit = qc.GUI(\"Circuit_example.txt\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's check the evolution of the derivatives at the minimum as a function of $\\phi_{ext}$ :"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"phi_exts = np.linspace(0,6*np.pi, 1000)\n",
"\n",
"labels = make_dict_vect(E_J, alpha, phi_exts) #labels is a dictionnary where each key corresponds to a list of values\n",
"\n",
"plt.plot(phi_exts, np.array(labels[\"E2\"])/1e9, label = \"E2\")\n",
"plt.plot(phi_exts, np.array(labels[\"E3\"])/1e9, label = \"E3\")\n",
"plt.plot(phi_exts, np.array(labels[\"E4\"])/1e9, label = \"E4\")\n",
"plt.legend()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The unbiased SNAIL has no third order term since it's has a parity in the flux.\n",
"Let's look at the frequencies, given by E2 :"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"freqs = circuit.eigenfrequencies(**labels)/1e9\n",
"\n",
"plt.xlabel(r\"$\\phi/_{ext}\\pi}$\")\n",
"plt.ylabel(\"Eigenfrequencies (GHz)\")\n",
"plt.title(\"Eigenfrequencies as a function of $\\phi_{ext}$\")\n",
"[plt.plot(phi_exts/np.pi, c) for c in freqs]\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"They follow the evolution of E2, which is expected.\n",
"\n",
"Let's look at the three waves mixing term :"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"three_waves = circuit.three_waves(0, 1, 2, **labels)/1e6 #In MHz\n",
"\n",
"plt.xlabel(r\"$\\phi/\\pi}$\")\n",
"plt.ylabel(\"Three waves mixing term (MHz)\")\n",
"plt.title(\"Three waves mixing term (MHz) as a function of the imposed phase\")\n",
"plt.plot(phi_exts/np.pi, three_waves)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It has the same shape as the E3 term.\n",
"\n",
"And now, the self-Kerr terms : "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"kerr_coeffs = circuit.kerr(**labels)/1e6 # in MHz\n",
"\n",
"\n",
"plt.xlabel(r\"$\\phi/\\pi}$\")\n",
"plt.ylabel(\"Self Kerr coefficient (MHz)\")\n",
"plt.title(\"Self Kerr coefficients as a function of the exterior phase\")\n",
"plt.legend()\n",
"[plt.plot(phi_exts/np.pi, kerr_coeffs[i, i], label = \"Mode \"+ str(i)) for i in range(len(kerr_coeffs))]\n",
"plt.legend()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can clearly see the existence of the sweet spot, point where all the Kerr terms vanish, but the three waves mixing term still exists, allowing to make a parametric amplifier without beeing limited by the Kerr terms, cf *SNAIL scheme taken from N. E. Frattini, V. V. Sivak, A. Lingenfelter, S. Shankar et M. H. Devoret : Optimizing the Nonlinearity and Dissipation of a SNAIL Parametric Amplifier for Dynamic Range. Physical Review Applied, 10(5):1–17, 2018.*\n",
"\n",
"The other features of qucat apply otherwise : the f_k_A_chi function, getting the full hamiltonian with qutip. It is now possible to get the hamiltonian with sympy :"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"circuit.hamiltonian_sym(**make_dict(E_J, alpha, np.pi/7), modes = 'all') "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that the expression isn't simplified, and uses the bosonic operators from the sympy.physics.secondquant library. To simplify it (normal ordering for example), one needs to further analyse it by themselves, I didn't found any built-in function to do this with bosonic operators (it exists for fermionic operators though).\n",
"\n",
"The Keywords arguments are the same as for the hamiltonian function that works with qutip. However, to further Taylor expand the hamiltonian, one should have specified the corresponding number of labels for each arbitray dipole in the circuit. In our example, we cannot go further than the fourth order, unless we decide to provide more labels.\n",
"\n",
"One can also, for example, select the modes to be taken into account."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 0 additions & 4 deletions src/_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3529,13 +3529,11 @@ def __init__(self, master, component):
if isinstance(self.component,C):
info_text = 'Specify label and/or capacitance (in units of Farad)'
self.value_string = 'Capacitance'
info_text += '\nPut the label between []: [label]'

elif isinstance(self.component,J):
self.value_string = 'Inductance'
info_text = 'Specify label and/or Josephson inductance (in units of Henry)'
info_text += '\nNote that L = (hbar/2/e)**2/[Josephson Energy in Joules]'
info_text += '\nPut the label between []: [label]'

elif isinstance(self.component,D):
self.value_string = 'Energy'
Expand All @@ -3544,11 +3542,9 @@ def __init__(self, master, component):
elif isinstance(self.component,L):
self.value_string = 'Inductance'
info_text = 'Specify label and/or inductance (in units of Henry)'
info_text += '\nPut the label between []: [label]'
elif isinstance(self.component,R):
self.value_string = 'Resistance'
info_text = 'Specify label and/or resistance (in units of Ohm)'
info_text += '\nPut the label between []: [label]'


# Entry field strings
Expand Down
Loading