<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Flux Noise Mask Design
General Notes
Step1:  CPW
We want to use the same cpw dimensions for resonator and feedline/purcell filter cpw's so the kinetic inductance correction is the same for everything.
Step2:  $\lambda/4$ readout resonators
IMPAs from Google will be good in the 4-6GHz range.  We will aim for resonators near 6GHz, but have a spread from 5-6GHz on the mask.  They should be spread every 30MHz or so.
Step3:  Qubit parameters
From Ted Thorbeck's notes
Step4:  Feedline with and without crossovers
Step5:  Inductive Coupling
From [1], we have the dephasing of a qubit
Step6:  Purcell Filter
Do we even need a purcell filter? [3]
Without purcell filter
Step7:  Loss from XY line
From Thorbeck's notes, we have
$R_p = R_s(1+Q_s^2)$ and $C_p = C_s\left(\frac{Q_s^2}{1+Q_s^2}\right)$
where $Q_s = \frac{1}{\omega R_s C_s}$
and the "s" and "p" subscript refer to just the coupling capacitor and Z0 of the line in a series or parallel configuration.  Combining this with the normal LC of the qubit, we can find the loss
<ASSISTANT_TASK:>
Python Code:
qubits = []
for i in range(3):
    q = qubit.Qubit('Transmon')
    q.C_g = 3.87e-15
    q.C_q = 75.1e-15
    q.C_resToGnd = 79.1e-15
    qubits.append(q)
q = qubit.Qubit('OCSQubit')
q.C_g = 2.94e-15
q.C_q = 48.5e-15
q.C_resToGnd = 51.5e-15
qubits.append(q)
Explanation: Flux Noise Mask Design
General Notes:
 * Looking at the chip left to right, top to bottom, we have Q1-Q4.
 * Q4 is the charge sensitive qubit.  All others are normal transmons. 
Still to do:
 * simulate mutual   
Problems with mask:
 * One of the XY (Q2) lines is messed up
 * capacitances change resonator frequencies so nothing matches
 * Alex thinks flux bias line might be bad
 * Resonators need to be moved closer (Z0 -> Z0^2)
 * Should probably change the test pattern to have less substrate contribution
 * Purcell filter changes resonator coupling, so Q was wrong.
Transmon Selected params:
+    w = 34, l_c = 90, w_c = 150:
    + C_q = 75.6fF
    + C_g = 3.39fF
    + C_resToGnd = 79.1fF
+    d_xy = 80: C_xy = 99.5fF  
Charge Sensitive Selected params:
+    w = 14, l_c = 90, w_c = 200:
    + C_q = 48.5fF
    + C_g = 2.94fF
    + C_resToGnd = 107fF
+    d_xy = 50: C_xy = 95.5fF
End of explanation
cpw = cpwtools.CPW(material='al', w=10., s=7.)
print cpw
Explanation: CPW
We want to use the same cpw dimensions for resonator and feedline/purcell filter cpw's so the kinetic inductance correction is the same for everything.
End of explanation
l_curve = 2*pi*50/4
coupling_length = 287
tot_length = l_curve*(1+1+2+2+2+2) + 2*1000 + 1156 + 350 + 500 + coupling_length # this coupling length ranges from 45-150 depending on desired Qc.  
                                                                                 # Plan for 45, can always trombone down
L4 = cpwtools.QuarterLResonator(cpw, tot_length)
print('The frequency is brought down significantly by the capacitance through to ground through the qubit, ' +
      'as well as the self-capacitance of the coupling cap to ground.  These capacitances pull down the transmon ' +
      'frequency more, so we will set Q3 to have no extension, and set the other qubit frequencies around it.')
print('Bare resonator frequency = {:.3f} GHz'.format(L4.fl()/1e9))
print
def L4FromQubit(q):
    L4 = cpwtools.QuarterLResonator(cpw, tot_length)
    seriesCap = q.C_g*q.C_q/(q.C_g+q.C_q)
    L4.addCapacitiveCoupling('g', seriesCap, Z0 = 0)
    L4.addCapacitiveCoupling('c_coupler', q.C_resToGnd, Z0 = 0)
    return L4
    
L4 = L4FromQubit(qubits[2])
f0 = L4.fl()
for i,q in enumerate(qubits):
    L4 = L4FromQubit(q)
    length = L4.setLengthFromFreq(f0 + 0.04e9*[-2, -1, 0, 1][i])
    q.C_r = L4.C()
    q.omega_r = L4.wl()
    q.omega_q = 2*pi*(f0-1e9)
    print("{}: l = {:.2f}um  f_l = {:.3f}GHz  C_r = {:.2f}fF  extension = {:.2f}um".format(
        q.name, 1e6*q.res_length, L4.fl()/1e9, 1e15*L4.C(), (1e6*length - tot_length)/2))
Explanation: $\lambda/4$ readout resonators
IMPAs from Google will be good in the 4-6GHz range.  We will aim for resonators near 6GHz, but have a spread from 5-6GHz on the mask.  They should be spread every 30MHz or so.
End of explanation
qb = deepcopy(qubits[2])
g = 2*pi*50e6     # qubit-resonator coupling in Hz
print('Range of C_q on the mask:')
print "C_q = 30fF: E_c = {:.2f}MHz".format( qb.E_c(30e6)/(2*pi*hbar)*1e15 )
print "C_q = 95fF: E_c = {:.2f}MHz".format( qb.E_c(95e6)/(2*pi*hbar)*1e15 )
print
print('Ideal:')
print "Transmon:          E_c = 250MHz: C_sigma = C_q + C_g = {:.2f}fF".format( e**2/2/250e6/(2*pi*hbar)*1e15 )
print "Charge Sensitive:  E_c = 385MHz: C_sigma = C_q + C_g = {:.2f}fF".format( e**2/2/385e6/(2*pi*hbar)*1e15 )
# With caps chosen from the mask:
for q in qubits:
    print "{}:  C_q = {:.2f}fF  E_c = {:.2f}MHz  E_j = {:.2f}GHz  alpha = {:.2f}MHz  g = {:.2f}MHz  C_g = {:.2f}fF".format(
        q.name, 1e15*q.C_q, -q.E_c()/(2*pi*hbar)/1e6, q.E_j()/2/pi/hbar/1e9, q.alpha(q.E_c(),q.E_j())/(2*pi)/1e6, g/2/pi/1e6, 1e15*q.cap_g(g))
# We choose the closest g capacitance from the mask
for q in qubits:
    print "{}:  C_g = {:.2f}fF  g = {:.2f}MHz  Chi_0/2pi = {:.2f}MHz  Chi/2pi = {:.2f}MHz  Q_r = {:.0f}  kappa = {:.2f}MHz  1/kappa = {:.0f}ns  I_c={:.2f}nA  n_crit={:.0f}".format(
        q.name, 1e15*q.cap_g(q.g()), q.g()/2/pi/1e6, 1e-6*q.Chi_0()/2/pi, 1e-6*q.Chi()/2/pi, q.Q_r(), q.omega_r/q.Q_r()*1e-6/2/pi, q.Q_r()/q.omega_r*1e9, q.I_c()*1e9, ((q.omega_q-q.omega_r)/2/q.g())**2)
delta = 380e-6; #2\Delta/e in V
Jc = 1e8*673e-9 # A/cm^2
nJJs = [2,1,1,2]
for i,q in enumerate(qubits):
    print("{}:  I_c = {:.2f}nA  R_N = {:.2f}k  width = {} x {:.3f}nm".format(q.name, q.I_c()*1e9, 1e-3*pi/4*delta/q.I_c(), nJJs[i], 1e9*q.I_c()/(1e4*Jc)/100e-9/nJJs[i] ))
for q in qubits:
    print "{}: Ej/Ec = {:.3f}  Charge dispersion = {:.3f}MHz".format(q.name, q.E_j()/q.E_c(), q.charge_dispersion()/2/pi/hbar/1e6)
# What variation in C_g should be included on mask for the C_q variation we have?
for C_q_ in [85e-15, 29e-15, e**2/2/250e6]:
    for g_ in [2*pi*25e6, 2*pi*50e6, 2*pi*200e6]:
        qb.C_q = C_q_
        print "C_q = {:.2f}fF  g = {:.2f}MHz  C_g = {:.2f}fF".format(
            1e15*C_q_, g_/2/pi/1e6, 1e15*qb.cap_g(g_))
Explanation: Qubit parameters
From Ted Thorbeck's notes:
$E_c = \frac{e^2}{2C}$, $E_c/\hbar=\alpha=\text{anharmonicity}$
$E_J = \frac{I_o \Phi_0}{2 \pi} $
$\omega_q = \sqrt{8E_JE_c}/\hbar $
$g = \frac{1}{2} \frac{C_g}{\sqrt{(C_q+C_g)(C_r+C_g)}}\sqrt{\omega_r\omega_q}$  
We want g in the range 25-200MHz for an ideal anharmonicity $\alpha$=250MHz
End of explanation
cpw.setKineticInductanceCorrection(False)
print cpw
cpwx = cpwtools.CPWWithBridges(material='al', w=1e6*cpw.w, s=1e6*cpw.s, bridgeSpacing = 250, bridgeWidth = 3, t_oxide=0.16)
cpwx.setKineticInductanceCorrection(False)
print cpwx
Explanation: Feedline with and without crossovers
End of explanation
d = 5
MperL = inductiveCoupling.inductiveCoupling.CalcMutual(cpw.w*1e6, cpw.w*1e6, cpw.s*1e6, cpw.s*1e6, d, 10*cpw.w*1e6)[0]
for q in qubits:
    M = 1/(np.sqrt(q.Q_r()*pi/8/cpw.z0()**2)*q.omega_r)
    print "{}  M = {:.2f}pH  coupling length = {:.2f}um".format(q.name, M*1e12, M/MperL*1e6)
for q in [3000,6000,9000,15000,21000,27000,33000]:
    print "Q_c={}  l_c={:.2f}".format(q,1/(np.sqrt(q*pi/8/cpw.z0()**2)*qubits[2].omega_r)/MperL*1e6)
Explanation: Inductive Coupling
From [1], we have the dephasing of a qubit:
$\Gamma_\phi = \eta\frac{4\chi^2}{\kappa}\bar{n}$, where $\eta=\frac{\kappa^2}{\kappa^2+4\chi^2}$, $\bar{n}=\left(\frac{\Delta}{2g}\right)^2$
$\Gamma_\phi = \frac{4\chi^2\kappa}{\kappa^2+4\chi^2}\left(\frac{\Delta}{2g}\right)^2$
To maximize the efficiency of readout, we want to maximize the rate of information leaving the system (into the readout chain), or equivilently, maximize dephasing.
$\partial_\kappa\Gamma_\phi = 0 = -\frac{4\chi^2(\kappa^2-4\chi^2)}{(\kappa^2+4\chi^2)^2}$ when $2\chi=\kappa$.
$2\chi = \kappa_r = \omega_r/Q_r$
$ Q_{r,c} = \frac{8Z_0^2}{\pi(\omega M)^2}$  [2]
We want a $Q_c$ of 3k-30k  
[1] Yan et al. The flux qubit revisited to enhance coherence and reproducibility. Nature Communications, 7, 1–9. http://doi.org/10.1038/ncomms12964
[2] Matt Beck's Thesis, p.39
End of explanation
l_curve = 2*pi*50/4
tot_length = l_curve*(1+2+2+2+1)*2 + 4*750 + 2569 + 4*450 + 2*106
purcell = cpwtools.HalfLResonator(cpw,tot_length)
purcell.addCapacitiveCoupling('in', 40e-15)
purcell.addCapacitiveCoupling('out', 130e-15)
print( "f_max = {:.3f}GHz  Q_in = {:.2f}  Q_out = {:.2f}".format( 1e-9*purcell.fl(), purcell.Qc('in'), purcell.Qc('out') ) )
purcell.l = (tot_length + 503*4)*1e-6
print( "f_min = {:.3f}GHz  Q_in = {:.2f}  Q_out = {:.2f}".format( 1e-9*purcell.fl(), purcell.Qc('in'), purcell.Qc('out') ) )
print
print('The measured purcell filter (no crossovers) seems to be 150-200MHz below expected.  This has been accounted for below.')
f0 = (qubits[1].omega_r + qubits[2].omega_r)/2/2/pi
purcell.setLengthFromFreq(f0 + 175e6)   # The measured purcell filter (no crossovers) seems to be 150-200MHz below expected.
print "f = {:.2f}GHz  l = {:.3f}um  offset = {:.3f}um  Q_in = {:.2f}  Q_out = {:.2f}".format( 1e-9*purcell.fl(), purcell.l*1e6, (purcell.l*1e6-tot_length)/4, purcell.Qc('in'), purcell.Qc('out') )
print "V_out/V_in =", (purcell.Qc('in')/purcell.Qc('out'))**0.5
print "{:.2f}% power lost through input".format( 100*purcell.Ql()/purcell.Qc('in') )
print "{:.2f}% power lost through output".format( 100*purcell.Ql()/purcell.Qc('out') )
print "{:.2f}% power lost internally".format( 100*purcell.Ql()/purcell.Qint() )
print
print "The purcell filter frequency goes up by 310MHz when crossovers are added:"
purcellx = deepcopy(purcell)
purcellx.cpw = cpwx
print "f = {:.2f}GHz  l = {:.3f}um  Q_in = {:.2f}  Q_out = {:.2f}".format( 1e-9*purcellx.fl(), purcellx.l*1e6, purcellx.Qc('in'), purcellx.Qc('out') )
print "Purcell Filter FWHM = {:.2f}MHz".format(2*pi*f0/purcell.Ql()/2/pi/1e6)
print "Purcell Filter Q_l = {:.2f}".format(purcell.Ql())
print
for q in qubits:
    kappa_r = q.omega_r/q.Q_r()
    Delta = q.omega_q - q.omega_r
    print "{}: T1 limit (no purcell) = {:.2f}us  T1 limit (purcell) = {:.2f}us".format(
        q.name, (Delta/q.g())**2/kappa_r * 1e6, (Delta/q.g())**2 * (q.omega_r/q.omega_q) * (2*Delta/q.omega_r*purcell.Ql())**2/kappa_r * 1e6 )
Explanation: Purcell Filter
Do we even need a purcell filter? [3]
Without purcell filter: $\kappa_r T_1 \le \left(\frac{\Delta}{g}\right)^2$
With purcell filter: $\kappa_r T_1 \le \left(\frac{\Delta}{g}\right)^2 \left(\frac{\omega_r}{\omega_q}\right) \left(\frac{2\Delta}{\omega_r/Q_{pf}}\right)^2$
$\kappa_r = \omega_r/Q_r$  
With the readout resonators spaced ~30MHz appart, we need a bandwidth of at least 4*30MHz=120MHz.
We have a range of readout resonators from 5-6GHz.  
[3] Jeffrey et al. Fast accurate state measurement with superconducting qubits. Physical Review Letters, 112(19), 1–5. http://doi.org/10.1103/PhysRevLett.112.190504
End of explanation
C_q = qubits[2].C_q
L_q = 1/(qubits[2].omega_q**2 * C_q)
R_s = 50
C_s = 0.1e-15
Q_s = 1/(qubits[2].omega_q * R_s * C_s)
R_p = R_s*(1 + Q_s**2)
C_p = C_s * Q_s**2/(1 + Q_s**2)
omega = 1/np.sqrt((C_q+C_p)*L_q)
Q_xy = omega*R_p*(C_q+C_p)
print("f: {:.3f}GHz --> {:.3f}GHz".format( 1e-9/np.sqrt(C_q*L_q)/2/pi, 1e-9*omega/2/pi))
print("Q = {:.2f}".format(Q_xy))
print("1/kappa = {:.2f}us".format(1e6*Q_xy/omega))
Explanation: Loss from XY line
From Thorbeck's notes, we have
$R_p = R_s(1+Q_s^2)$ and $C_p = C_s\left(\frac{Q_s^2}{1+Q_s^2}\right)$
where $Q_s = \frac{1}{\omega R_s C_s}$
and the "s" and "p" subscript refer to just the coupling capacitor and Z0 of the line in a series or parallel configuration.  Combining this with the normal LC of the qubit, we can find the loss
End of explanation
<END_TASK>