class VNA_Pwr_Lyzer(VNA_Lyzer): base_name="vna_pwr_lyzer" pwr=Array().tag(unit="dBm", label="Power", sub=True) pwr_ind=Int() frq_ind=Int() yok_ind=Int() swp_type=Enum("pwr_first", "yoko_first") def _default_read_data(self): return read_data #def _observe_pwr_ind(self, change): # reset_property(self, "Magcom") @tag_property(sub=True) def Magcom(self): if self.filter_type=="None": Magcom=self.MagcomData elif self.filter_type=="Fit": return self.MagAbsFit else: Magcom=self.MagcomFilt[self.indices, :, :] if self.bgsub_type=="Complex": return self.bgsub(Magcom) return Magcom[:, :, self.pwr_ind] #array([[self.fft_filter_full(m, n, Magcom) for n in range(len(self.yoko))] for m in range(len(self.pwr))]).transpose() @private_property def MagcomFilt(self): if self.filt.filter_type=="FIR": return array([[self.filt.fir_filter(self.MagcomData[:,n,m]) for n in self.flat_flux_indices] for m in range(len(self.pwr))]).transpose() return array([[self.filt.fft_filter(self.MagcomData[:,n,m]) for n in self.flat_flux_indices] for m in range(len(self.pwr))]).transpose() @tag_property( sub=True) def MagAbsFilt_sq(self): return absolute(self.MagcomFilt[:, :, self.pwr_ind])**2 @private_property def fit_params(self): if self.fitter.fit_params is None: self.fitter.full_fit(x=self.flux_axis[self.flat_flux_indices], y=self.MagAbsFilt_sq, indices=self.flat_indices, gamma=self.fitter.gamma) if self.calc_p_guess: self.fitter.make_p_guess(self.flux_axis[self.flat_flux_indices], y=self.MagAbsFilt_sq, indices=self.flat_indices, gamma=self.fitter.gamma) return self.fitter.fit_params @private_property def MagAbsFit(self): return sqrt(self.fitter.reconstruct_fit(self.flux_axis[self.flat_flux_indices], self.fit_params))
class Coil_Lyzer(TA88_Lyzer): current = Array().tag(unit="V", plot=True, label="Current", sub=True)
class Sat_Qubit(Qubit): atten = Float(83.0) phi_arr = Array() pwr_arr = Array() def _default_phi_arr(self): return linspace(0.2, 0.3, 101) def _default_pwr_arr(self): return linspace(-50.0, 0, 31) gamma = Float(38.0e6) gamma_el = Float(0.750e6) gamma_phi = Float(0.0) T = Float(0.03) N_dim = Int(8) fd = Float(4.5e9) N_gamma = SProperty() @N_gamma.getter def _get_N_gamma(self, fd, T): return 1.0 / (exp(h * fd / (k * T)) - 1.0) @private_property def a_op(self): return destroy(self.N_dim) @private_property def a_dag(self): return self.a_op.dag() @private_property def tdiag(self): return Qobj(diag(range(0, 2 * self.N_dim, 2))) #dephasing operator, tdiag c_ops = SProperty().tag(sub=True) @c_ops.getter def _get_c_ops(self, gamma, N_gamma, a_op, a_dag, tdiag, gamma_phi): rate1 = gamma * (1 + N_gamma) rate2 = gamma * N_gamma return [sqrt(rate1) * a_op, sqrt(rate2) * a_dag, gamma_phi * tdiag] @private_property def nvec(self): return arange(self.N_dim) @private_property def fdvec(self): return self.nvec * self.fd @private_property def Ecvec(self): return -self.Ec * (6.0 * self.nvec**2 + 6.0 * self.nvec + 3.0) / 12.0 @private_property def pwr_lin(self): pwr_fridge = self.pwr_arr - self.atten return 0.001 * 10**(pwr_fridge / 10.0) @private_property def Omega_arr(self): pwr_fridge = self.pwr_arr - self.atten return sqrt(0.001 * 10**(pwr_fridge / 10.0) / (h * a.fd)) * sqrt(2 * self.gamma_el) @private_property def value_grid(self): value_grid = array(meshgrid(self.phi_arr, self.Omega_arr)) return zip(value_grid[0, :, :].flatten(), value_grid[1, :, :].flatten()) funcer = Callable() # @private_property # def funcer(self): # def find_expect2(vg): #phi=0.1, Omega_vec=3.0): # phi, Omega=vg#.shape # Omega_vec=-0.5j*(Omega*a.a_dag - conj(Omega)*a.a_op) # # Ej = a.Ejmax*absolute(cos(pi*phi)) #Josephson energy as function of Phi. # # wTvec = (-Ej + sqrt(8.0*Ej*a.Ec)*(a.nvec+0.5)+a.Ecvec)/h #\omega_m # # wT = wTvec-a.fdvec #rotating frame of gate drive \omega_m-m*\omega_\gate # transmon_levels = Qobj(diag(wT[range(a.N_dim)])) # H=transmon_levels +Omega_vec #- 0.5j*(Omega_true*adag - conj(Omega_true)*a) # final_state = steadystate(H, a.c_ops) #solve master equation # # return expect( a.a_op, final_state) #expectation value of relaxation operator # #Omega=\alpha\sqrt{2\Gamma_10} where |\alpha|^2=phonon flux=number of phonons per second # #Omega=2\alpha\sqrt{\gamma} where |\alpha|^2=phonon flux=number of phonons per second # # return find_expect @private_property def fexpt(self): fexpt = parallel_map(self.funcer, self.value_grid, progress_bar=True) return reshape(fexpt, (len(self.pwr_arr), len(self.phi_arr)))
class Lyzer(LyzerBase): base_name="lyzer" frequency=Array().tag(unit="GHz", plot=True, label="Frequency", sub=True) yoko=Array().tag(unit="V", plot=True, label="Yoko", sub=True) #pwr=Array().tag(unit="V", plot=True, label="Yoko", sub=True) #frq2=Array().tag(unit="V", plot=True, label="Yoko", sub=True) Magcom=Array().tag(sub=True) probe_pwr=Float().tag(label="Probe power", read_only=True, display_unit="dBm/mW") on_res_ind=Int() start_ind=Int() stop_ind=Int() filt_center=Int() filt_halfwidth=Int() indices=List() port_name=Unicode('S21') VNA_name=Unicode("RS VNA") @tag_property() def filt_start_ind(self): return self.filt_center-self.filt_halfwidth+1 @tag_property() def filt_end_ind(self): return self.filt_center+self.filt_halfwidth#-1 fit_func=Callable(lorentzian).tag(private=True) read_data=Callable(read_data).tag(sub=True) fit_type=Enum("fq", "yoko") @tag_property(plot=True, sub=True) def fq(self): return self.qdt._get_fq(Ej=self.Ej, Ec=self.qdt.Ec) @tag_property(sub=True) def ls_f(self): #return array([f-self.qdt._get_Lamb_shift(f=f) for f in self.frequency]) return array([sqrt(f*(f-2*self.qdt._get_Lamb_shift(f=f))) for f in self.frequency]) @tag_property(sub=True) def voltage_from_flux_par(self): Ej=self.qdt._get_Ej_get_fq(fq=self.ls_f) flux_d_flux0=self.qdt._get_flux_over_flux0_get_Ej(Ej=Ej) #flux_d_flux0=arccos(Ej/Ejmax)#-pi/2 #flux_d_flux0=append(flux_d_flux0, -arccos(Ej/Ejmax)) #flux_d_flux0=append(flux_d_flux0, -arccos(Ej/Ejmax)+pi) #flux_d_flux0=append(flux_d_flux0, arccos(Ej/Ejmax)-pi) return self.qdt._get_voltage(flux_over_flux0=flux_d_flux0, offset=self.offset, flux_factor=self.flux_factor) @tag_property(sub=True) def voltage_from_flux_par2(self): Ej=self.qdt._get_Ej_get_fq(fq=self.ls_f) fdf0=self.qdt._get_flux_over_flux0_get_Ej(Ej=Ej) flux_d_flux0=append(fdf0, -fdf0) flux_d_flux0=append(flux_d_flux0, -fdf0+pi) flux_d_flux0=append(flux_d_flux0, fdf0-pi) freq=append(self.frequency, self.frequency) freq=append(freq, freq) return freq, self.qdt._get_voltage(flux_over_flux0=flux_d_flux0, offset=self.offset, flux_factor=self.flux_factor) @tag_property(sub=True) def ls_flux_par(self): return self.qdt._get_ls_flux_parabola(voltage=self.yoko, offset=self.offset, flux_factor=self.flux_factor) @tag_property(plot=True, sub=True) def Ej(self): return self.qdt._get_Ej(Ejmax=self.qdt.Ejmax, flux_over_flux0=self.flux_over_flux0) @tag_property(sub=True) def flux_over_flux0(self): return self.qdt._get_flux_over_flux0(voltage=self.yoko, offset=self.offset, flux_factor=self.flux_factor) def _default_indices(self): return range(len(self.frequency)) #return [range(81, 120+1), range(137, 260+1), range(269, 320+1), range(411, 449+1)]#, [490]]#, [186]] def fft_filter(self, n): myifft=fft.ifft(self.Magcom[:,n]) myifft[self.filt_end_ind:-self.filt_end_ind]=0.0 if self.filt_start_ind!=0: myifft[:self.filt_start_ind]=0.0 myifft[-self.filt_start_ind:]=0.0 return fft.fft(myifft) @tag_property(plot=True, sub=True) def MagdB(self): return 10.0*log10(self.MagAbs) @tag_property(plot=True, sub=True) def MagAbs(self): return absolute(self.Magcom) @tag_property(plot=True, sub=True) def MagAbsFilt(self): return absolute(self.MagcomFilt)#.transpose()-absolute(self.MagcomFilt[:,0])).transpose() @tag_property(plot=True, sub=True) def MagdBFilt(self): return 10.0*log10(self.MagAbsFilt) @tag_property(plot=True, sub=True) def MagcomFilt(self): #return array([fft_filter4(self.Magcom[:,n], self.filt_center) for n in range(len(self.yoko))]).transpose() return array([fft_filter3(self.Magcom[:,n], self.filt_start_ind, self.filt_end_ind) for n in range(len(self.yoko))]).transpose() @tag_property(sub=True) def MagAbsFit(self): if self.fit_type=="yoko": return sqrt(array([self.fit_func(self.yoko, fp) for fp in self.fit_params])) return sqrt(array([self.fit_func(self.fq, fp) for fp in self.fit_params])) @tag_property(sub=True) def MagdBFit(self): return 10*log10(self.MagAbsFit) @tag_property(sub=True) def fit_params(self): return self.full_fano_fit(self.fq) @plots def widths_plot(self, pl=None): scatter(self.frequency[self.indices]/1e9, absolute([fp[0] for fp in self.fit_params]), plotter=pl) line(self.frequency/1e9, self.qdt._get_coupling(self.frequency), plotter=pl, color="red") return pl @plots def center_plot(self, pl=None): line(self.frequency[self.indices]/1e9, array([fp[1] for fp in self.fit_params]), plotter=pl) line(self.frequency/1e9, self.ls_f, plotter=pl, color="red", linewidth=1.0) return pl @plots def heights_plot(self, pl=None): pl, pf=line(self.frequency[self.indices]/1e9, array([fp[3]-fp[2] for fp in self.fit_params])) return pl @plots def background_plot(self, pl=None): pl, pf=line(self.frequency[self.indices]/1e9, array([fp[2]+fp[3] for fp in self.fit_params])) line(self.frequency[self.indices]/1e9, self.MagAbsFilt_sq[self.indices,0], plotter=pl, color="red") return pl def magabs_colormesh(self): pl, pf=colormesh(self.yoko, self.frequency/1e9, self.MagAbs, plotter="magabs_{}".format(self.name)) pl.set_ylim(min(self.frequency/1e9), max(self.frequency/1e9)) pl.set_xlim(min(self.yoko), max(self.yoko)) pl.xlabel="Yoko (V)" pl.ylabel="Frequency (GHz)" return pl def ifft_plot(self): p, pf=line(absolute(fft.ifft(self.Magcom[:,self.on_res_ind])), plotter="ifft_{}".format(self.name), plot_name="onres_{}".format(self.on_res_ind),label="i {}".format(self.on_res_ind), color="red") line(absolute(fft.ifft(self.Magcom[:,self.start_ind])), plotter=p, linewidth=1.0, plot_name="strt {}".format(self.start_ind), label="i {}".format(self.start_ind)) line(absolute(fft.ifft(self.Magcom[:,self.stop_ind])), plotter=p, linewidth=1.0, plot_name="stop {}".format(self.stop_ind), label="i {}".format(self.stop_ind)) return p def hann_ifft_plot(self): on_res=log10(absolute(hann_ifft(self.Magcom[:,self.on_res_ind]))) strt=log10(absolute(hann_ifft(self.Magcom[:,self.start_ind]))) stop=log10(absolute(hann_ifft(self.Magcom[:,self.stop_ind]))) p, pf=line(on_res, plotter="hann_ifft_{}".format(self.name), color="red", plot_name="onres_{}".format(self.on_res_ind),label="i {}".format(self.on_res_ind)) line(strt, plotter=p, linewidth=1.0, plot_name="strt {}".format(self.start_ind), label="i {}".format(self.start_ind)) line(stop, plotter=p, linewidth=1.0, plot_name="stop {}".format(self.stop_ind), label="i {}".format(self.stop_ind)) filt=filt_prep(len(on_res), self.filt_start_ind, self.filt_end_ind) top=max([amax(on_res), amax(strt), amax(stop)]) line(filt*top, plotter=p, color="green") return p def filt_compare(self, ind): p, pf=line(self.frequency, self.MagdB[:, ind], label="MagAbs (unfiltered)", plotter="filtcomp_{}".format(self.name)) line(self.frequency, self.MagdBFilt[:, ind], label="MagAbs (filtered)", plotter=p) @plots def ls_magabsfilt_colormesh(self, pl=None): colormesh(self.flux_over_flux0[10:-10], self.ls_f[10:-10]/1e9, self.MagAbsFilt[10:-10, 10:-10], plotter=pl)#"magabsfilt_{}".format(self.name)) return pl @plots def magabsfilt_colormesh(self, pl=None, xlabel="$\Phi/\Phi_0$", ylabel="Frequency (GHz)"): colormesh(self.flux_over_flux0[10:-10], self.frequency[10:-10]/1e9, self.MagAbsFilt[10:-10, 10:-10], #plot_name="magabsfiltf_{}".format(self.name), plotter=pl, xlabel=xlabel, ylabel=ylabel) return pl @plots def ls_magabsfit_colormesh(self, pl=None, xlabel="$\Phi/\Phi_0$", ylabel="Frequency (GHz)"): colormesh(self.flux_over_flux0[10:-10], self.ls_f[self.indices][10:-10]/1e9, self.MagAbsFit[10:-10, 10:-10], plotter=pl, xlabel=xlabel, ylabel=ylabel) @plots def magabsfit_colormesh(self, pl=None, xlabel="$\Phi/\Phi_0$", ylabel="Frequency (GHz)"): colormesh(self.flux_over_flux0[10:-10], self.frequency[self.indices][10:-10]/1e9, self.MagAbsFit[10:-10, 10:-10], plotter=pl, xlabel=xlabel, ylabel=ylabel) @plots def flux_line(self, pl=None, xlabel="$\Phi/\Phi_0$", ylabel="Frequency (GHz)"): xmin, xmax, ymin, ymax=pl.x_min, pl.x_max, pl.y_min, pl.y_max line(self.flux_over_flux0[10:-10], self.fq[10:-10]/1e9, plotter=pl, xlabel=xlabel, ylabel=ylabel) pl.x_min, pl.x_max, pl.y_min, pl.y_max=xmin, xmax, ymin, ymax pl.xlabel="$\Phi/\Phi_0$" pl.ylabel="Frequency (GHz)" return pl def magphasefilt_colormesh(self): phase=angle(self.Magcom[10:-10, 10:-10]) #phasefilt=array([unwrap(phase[:,n], discont=5.5) for n in range(phase.shape[1])]) phase=(phase.transpose()-phase[:,0]).transpose() phasefilt=unwrap(phase, discont=1.5, axis=1) #phasefilt=phasefilt-phasefilt[0, :] pl, pf=colormesh(self.flux_over_flux0[10:-10], self.frequency[10:-10]/1e9, phasefilt, plotter="magphasefilt_{}".format(self.name)) #print self.voltage_from_flux_par2[0].shape,self.voltage_from_flux_par2[1].shape #line(self.voltage_from_flux_par2[0]/1e9, self.voltage_from_flux_par2[1], plotter=p) #print max(self.voltage_from_flux_par), min(self.voltage_from_flux_par) pl.xlabel="Yoko (V)" pl.ylabel="Frequency (GHz)" return pl def magabsfilt2_colormesh(self): p, pf=colormesh(self.frequency[10:-10]/1e9, self.yoko[10:-10], self.MagAbsFilt.transpose()[10:-10, 10:-10], plotter="magabsfilt2_{}".format(self.name)) print self.voltage_from_flux_par2[0].shape,self.voltage_from_flux_par2[1].shape line(self.voltage_from_flux_par2[0]/1e9, self.voltage_from_flux_par2[1], plotter=p) #print max(self.voltage_from_flux_par), min(self.voltage_from_flux_par) p.xlabel="Yoko (V)" p.ylabel="Frequency (GHz)" return p def magdBfilt_colormesh(self): return colormesh(self.yoko, self.frequency/1e9, self.MagdBFilt, plotter="magdBfilt_{}".format(self.name), xlabel="Yoko (V)", ylabel="Frequency (GHz)") def magdBfiltbgsub_colormesh(self): return colormesh(self.yoko, self.frequency/1e9, (self.MagdBFilt.transpose()-self.MagdBFilt[:, self.start_ind]).transpose(), plotter="magdBfiltbgsub_{}".format(self.name), xlabel="Yoko (V)", ylabel="Frequency (GHz)") @tag_property(plot=True, sub=True) def MagAbsFilt_sq(self): return (self.MagAbsFilt)**2 def full_fano_fit(self, fq): log_debug("started fano fitting") fit_params=[self.fano_fit(n, fq) for n in self.indices] #fit_params=array(zip(*fit_params)) log_debug("ended fano fitting") return fit_params def full_fano_fit2(self): MagAbsFilt_sq=self.MagAbsFilt**2 return full_fano_fit(self.fit_func, self.p_guess, MagAbsFilt_sq, self.fq, indices=self.indices) #fit_params=[full_fano_fit(self.fit_func, self.p_guess, MagAbsFilt_sq[n, :], self.fq) for n in self.indices] #fit_params=array(zip(*fit_params)) #return fit_params def full_fano_fit3(self): MagAbsFilt_sq=self.MagAbsFilt**2 return full_fit(lorentzian2, self.p_guess, MagAbsFilt_sq, self.fq, indices=self.indices) def plot_widths(self, plotter=None): fit_params=self.full_fano_fit() scatter(fit_params[0, :], absolute(fit_params[1, :]), color="red", label=self.name, plot_name="widths_{}".format(self.name), plotter=plotter) def resid_func(self, p, y, x): """residuals of fitting function""" return y-self.fit_func(x, p) def fano_fit(self, n, fq): dat=self.MagAbsFilt_sq[n, :] datamax=max(dat) datamin=min(dat) if self.fit_type=="yoko": p_guess=[0.2, self.yoko[self.on_res_ind], datamax-datamin, dat[0]] pbest= leastsq(self.resid_func, p_guess, args=(dat, self.yoko), full_output=1) else: p_guess=[self.qdt._get_coupling(self.frequency[n]), self.ls_f[n], datamax-datamin, dat[0]] pbest= leastsq(self.resid_func, p_guess, args=(dat, fq), full_output=1) best_parameters = pbest[0] return (best_parameters[0], best_parameters[1], best_parameters[2], best_parameters[3])
class Sat_Qubit(Qubit): atten = Float(83.0) phi_arr = Array() pwr_arr = Array() frq_arr = Array() do_ls = Bool(True) harm_osc = Bool(False) Np = Int(9) f0 = Float(5.30001e9) def _default_phi_arr(self): return linspace(0.35, 0.4, 2 * 150) * pi def _default_pwr_arr(self): return linspace(-50.0, 0, 31) def _default_frq_arr(self): return linspace(3.5e9, 7.5e9, 51) gamma = Float(38.0e6) gamma_el = Float(0.750e6) gamma_phi = Float(0.0) T = Float(0.03) N_dim = Int(8) fd = Float(4.5e9) Zc = Float(50.0) Ic = Float(112.0e-9) def _get_fTvec(self, phi, gamma, Delta, fd, Psaw): C = self.Ct * (1.0 + 2.0 * Delta / fd) + self.Cc Ec = e**2 / (2 * C) Ecvec = -Ec * (6.0 * self.nvec**2 + 6.0 * self.nvec + 3.0) / 12.0 Isq = 0.0 * 4.0 * gamma * 2.0 * (self.Cc + self.Ct) * Psaw * 1 #+0.0j if Isq < self.Ic**2: Ej = self.Ejmax * absolute(cos(phi)) * sqrt( 1.0 - Isq / self.Ic**2) #Josephson energy as function of Phi. else: Ej = 0.0 #print sqrt(Isq) if self.harm_osc: return sqrt(8.0 * Ej * Ec) * (self.nvec + 0.5) / h return (-Ej + sqrt(8.0 * Ej * Ec) * (self.nvec + 0.5) + Ecvec) / h #\omega_m #return 0.0*(-Ej + 1.0*sqrt(8.0*Ej*self.Ec)*(self.nvec+0.5)+self.Ecvec)/h #\omega_m def _get_X(self, f, f0, Np): return Np * pi * (f - f0) / f0 def _get_GammaDelta(self, gamma, fd, f0, Np): if not self.do_ls: return gamma, 0.0 X = self._get_X(f=fd, f0=f0, Np=Np) Delta = gamma * (sin(2 * X) - 2 * X) / (2 * X**2) Gamma = gamma * (sin(X) / X)**2 return Gamma, Delta Gamma_C = SProperty() @Gamma_C.getter def _get_Gamma_C(self, fd, Cc, Ct, Zc): return 2 * pi * (Zc * Cc**2 * fd**2) / (4 * (Cc + Ct)) N_gamma = SProperty() @N_gamma.getter def _get_N_gamma(self, fd, T): return 1.0 / (exp(h * fd / (k * T)) - 1.0) @private_property def a_op(self): return destroy(self.N_dim) @private_property def a_dag(self): return self.a_op.dag() @private_property def tdiag(self): return Qobj(diag(range(0, 2 * self.N_dim, 2))) #dephasing operator, tdiag c_ops = SProperty().tag(sub=True) @c_ops.getter def _get_c_ops(self, gamma, N_gamma, a_op, a_dag, tdiag, gamma_phi): rate1 = gamma * (1 + N_gamma) rate2 = gamma * N_gamma return [sqrt(rate1) * a_op, sqrt(rate2) * a_dag, gamma_phi * tdiag] @private_property def nvec(self): return arange(self.N_dim) @private_property def fdvec(self): return self.nvec * self.fd @private_property def Ecvec(self): return -self.Ec * (6.0 * self.nvec**2 + 6.0 * self.nvec + 3.0) / 12.0 @private_property def pwr_lin(self): pwr_fridge = self.pwr_arr - self.atten return 0.001 * 10**(pwr_fridge / 10.0) @private_property def Omega_arr(self): return sqrt(self.pwr_lin / h * 2.0) #pwr_fridge=self.pwr_arr-self.atten #return sqrt(0.001*10**(pwr_fridge/10.0)/(h*a.fd))*sqrt(2*self.gamma_el) @private_property def value_grid(self): value_grid = array(meshgrid(self.phi_arr, self.frq_arr)) #value_grid=array(meshgrid(self.phi_arr, self.Omega_arr)) return zip(value_grid[0, :, :].flatten(), value_grid[1, :, :].flatten()) funcer = Callable() funcer2 = Callable() @private_property def value_grid2(self): value_grid = array(meshgrid(self.phi_arr, self.pwr_arr)) return zip(value_grid[0, :, :].flatten(), value_grid[1, :, :].flatten()) power_plot = Bool(True) acoustic_plot = Bool(True) @private_property def fexpt(self): self.power_plot = False fexpt = parallel_map(self.funcer, self.value_grid, progress_bar=True) return reshape(fexpt, (len(self.frq_arr), len(self.phi_arr))) @private_property def fexpt2(self): self.power_plot = True fexpt = parallel_map(self.funcer, self.value_grid2, progress_bar=True) #print shape(self.value_grid2) #print self.pwr_arr.shape #print self.phi_arr.shape #print shape(fexpt) return reshape(fexpt, (len(self.pwr_arr), len(self.phi_arr))) def find_expect(self, vg, pwr, fd): if self.power_plot: phi, pwr = vg else: phi, fd = vg pwr_fridge = pwr - self.atten lin_pwr = 0.001 * 10**(pwr_fridge / 10.0) Omega = sqrt(lin_pwr / h * 2.0) gamma, Delta = self._get_GammaDelta(fd=fd, f0=self.f0, Np=self.Np, gamma=self.gamma) g_el = self._get_Gamma_C(fd=fd) wTvec = self._get_fTvec(phi=phi, gamma=gamma, Delta=Delta, fd=fd, Psaw=lin_pwr) if self.acoustic_plot: Om = Omega * sqrt(gamma / fd) else: Om = Omega * sqrt(g_el / fd) wT = wTvec - fd * self.nvec #rotating frame of gate drive \omega_m-m*\omega_\gate transmon_levels = Qobj(diag(wT[range(self.N_dim)])) rate1 = (gamma + g_el) * (1.0 + self.N_gamma) rate2 = (gamma + g_el) * self.N_gamma c_ops = [sqrt(rate1) * self.a_op, sqrt(rate2) * self.a_dag ] #, sqrt(rate3)*self.a_op, sqrt(rate4)*self.a_dag] Omega_vec = -0.5j * (Om * self.a_dag - conj(Om) * self.a_op) H = transmon_levels + Omega_vec final_state = steadystate(H, c_ops) #solve master equation fexpt = expect(self.a_op, final_state) #expectation value of relaxation operator #return fexpt if self.acoustic_plot: return 1.0 * gamma / Om * fexpt else: return 1.0 * sqrt(g_el * gamma) / Om * fexpt
class VNA_Lyzer(Lyzer): base_name = "vna_lyzer" def _default_read_data(self): return read_data filter_type = Enum("None", "FFT", "FIR", "Fit") bgsub_type = Enum("None", "Complex", "Abs", "dB") flux_axis_type = Enum("yoko", "flux", "fq") freq_axis_type = Enum("f", "ls_f") time_axis_type = Enum("points", "time", "fft_points") calc_p_guess = Bool(False) show_quick_fit = Bool(True) def _observe_filter_type(self, change): if self.filter_type == "FIR": self.filt.filter_type = "FIR" elif self.filter_type == "FFT": self.filt.filter_type = "FFT" @tag_property(sub=True) def flux_axis(self): if self.flux_axis_type == "yoko": return self.yoko elif self.flux_axis_type == "flux": return self.flux_over_flux0 / pi elif self.flux_axis_type == "fq": return self.fq / 1e9 @tag_property(sub=True) def freq_axis(self): if self.flux_axis_type == "ls_f": return self.ls_f / 1e9 return self.frequency / 1e9 @t_property() def flux_axis_label(self): return { "yoko": "Yoko (V)", "flux": r"$\Phi/\Phi_0$", "fq": "Qubit Frequency (GHz)" }[self.flux_axis_type] @t_property() def freq_axis_label(self): return { "f": "Frequency (GHz)", "ls_f": "LS Frequency (GHz)" }[self.freq_axis_type] @tag_property(sub=True) def time_axis(self): if self.time_axis_type == "time": return self.ifft_time / 1e-6 elif self.time_axis_type == "points": return arange(len(self.frequency)) elif self.time_axis_type == "fft_points": return self.filt.fftshift(arange(len(self.frequency))) @t_property() def time_axis_label(self): return { "time": "Time (us)", "points": "Points", "fft_points": "FFT Points" }[self.time_axis_type] frequency = Array().tag(unit="GHz", plot=True, label="Frequency", sub=True) yoko = Array().tag(unit="V", plot=True, label="Yoko", sub=True) MagcomData = Array().tag(sub=True, desc="raw data in compex form") probe_pwr = Float().tag(label="Probe power", read_only=True, display_unit="dBm/mW") on_res_ind = Int() start_ind = Int() stop_ind = Int() flux_indices = List() def _default_flux_indices(self): return [range(len(self.yoko))] @tag_property(sub=True) def flat_flux_indices(self): return [n for ind in self.flux_indices for n in ind] fit_indices = List() def _default_fit_indices(self): return [range(len(self.frequency))] @tag_property(sub=True) def flat_indices(self): return [n for ind in self.fit_indices for n in ind] end_skip = Int(0) @tag_property(sub=True) def indices(self): if self.filter_type == "Fit": return self.flat_indices #[n for ind in self.fit_indices for n in ind] elif self.filter_type in ("FFT", "Fir"): return range(self.end_skip, len(self.frequency) - self.end_skip) return range(len(self.frequency)) port_name = Unicode('S21') VNA_name = Unicode("RS VNA") filt = Typed(Filter, ()) fitter = Typed(LorentzianFitter, ()) bgsub_start_ind = Int(0) bgsub_stop_ind = Int(1) bgsub_axis = Int(1) @tag_property(plot=True, sub=True) def fq(self): return self.qdt._get_fq(Ej=self.Ej, Ec=self.qdt.Ec) @tag_property(sub=True) def ls_f(self): #return array([f-self.qdt._get_Lamb_shift(f=f) for f in self.frequency]) return array([ sqrt(f * (f - 2 * self.qdt._get_Lamb_shift(f=f))) for f in self.frequency ]) @tag_property(sub=True) def voltage_from_flux_par(self): Ej = self.qdt._get_Ej_get_fq(fq=self.ls_f) flux_d_flux0 = self.qdt._get_flux_over_flux0_get_Ej(Ej=Ej) return self.qdt._get_voltage(flux_over_flux0=flux_d_flux0, offset=self.offset, flux_factor=self.flux_factor) def voltage_from_frequency(self, frq): ls_f = array( [sqrt(f * (f - 2 * self.qdt._get_Lamb_shift(f=f))) for f in frq]) Ej = self.qdt._get_Ej_get_fq(fq=ls_f) flux_d_flux0 = self.qdt._get_flux_over_flux0_get_Ej(Ej=Ej) return self.qdt._get_voltage(flux_over_flux0=-flux_d_flux0 + pi, offset=self.offset, flux_factor=self.flux_factor) @tag_property(sub=True) def voltage_from_flux_par2(self): Ej = self.qdt._get_Ej_get_fq(fq=self.ls_f) fdf0 = self.qdt._get_flux_over_flux0_get_Ej(Ej=Ej) flux_d_flux0 = append(fdf0, -fdf0) flux_d_flux0 = append(flux_d_flux0, -fdf0 + pi) flux_d_flux0 = append(flux_d_flux0, fdf0 - pi) freq = append(self.frequency, self.frequency) freq = append(freq, freq) return freq, self.qdt._get_voltage(flux_over_flux0=flux_d_flux0, offset=self.offset, flux_factor=self.flux_factor) @tag_property(sub=True) def ls_flux_par(self): return self.qdt._get_ls_flux_parabola(voltage=self.yoko, offset=self.offset, flux_factor=self.flux_factor) @tag_property(plot=True, sub=True) def Ej(self): return self.qdt._get_Ej(Ejmax=self.qdt.Ejmax, flux_over_flux0=self.flux_over_flux0) @tag_property(sub=True) def flux_over_flux0(self): return self.qdt._get_flux_over_flux0(voltage=self.yoko, offset=self.offset, flux_factor=self.flux_factor) @tag_property(plot=True, sub=True) def MagdB(self): if self.bgsub_type == "dB": return self.bgsub(10.0 * log10(absolute(self.Magcom))) return 10.0 * log10(self.MagAbs) def bgsub(self, arr): return bgsub2D(arr, self.bgsub_start_ind, self.bgsub_stop_ind, self.bgsub_axis) @tag_property(plot=True, sub=True) def MagAbs(self): if self.bgsub_type == "dB": return 10.0**(self.MagdB / 10.0) magabs = absolute(self.Magcom) if self.bgsub_type == "Abs": return self.bgsub(magabs) return magabs @tag_property(plot=True, sub=True) def MagAbs_sq(self): return (self.MagAbs)**2 @tag_property(plot=True, sub=True) def Phase(self): return angle(self.Magcom) return unwrap(angle(self.Magcom).transpose() - angle(self.Magcom)[:, 0], discont=6, axis=0).transpose() #return ( self.bgsub(angle(self.Magcom)) + pi) % (2 * pi ) - pi return self.bgsub(angle(self.Magcom)) @tag_property(sub=True) def Magcom(self): if self.filter_type == "None": Magcom = self.MagcomData elif self.filter_type == "Fit": Magcom = self.MagAbsFit else: Magcom = self.MagcomFilt[self.indices, :] if self.bgsub_type == "Complex": return self.bgsub(Magcom) return Magcom @tag_property(sub=True) def ifft_time(self): return self.filt.ifft_x(self.frequency) @private_property def MagcomFilt(self): if self.filt.filter_type == "FIR": return array([ self.filt.fir_filter(self.MagcomData[:, n]) for n in self.flat_flux_indices ]).transpose() return array([ self.filt.fft_filter(self.MagcomData[:, n]) for n in self.flat_flux_indices ]).transpose() @tag_property(plot=True, sub=True) def MagAbsFilt_sq(self): return absolute(self.MagcomFilt)**2 @private_property def fit_params(self): if self.fitter.fit_params is None: self.fitter.full_fit(x=self.flux_axis[self.flat_flux_indices], y=self.MagAbsFilt_sq, indices=self.flat_indices, gamma=self.fitter.gamma) if self.calc_p_guess: self.fitter.make_p_guess( self.flux_axis[self.flat_flux_indices], y=self.MagAbsFilt_sq, indices=self.flat_indices, gamma=self.fitter.gamma) return self.fitter.fit_params @private_property def MagAbsFit(self): return sqrt( self.fitter.reconstruct_fit(self.flux_axis[self.flat_flux_indices], self.fit_params)) def widths_plot(self, **kwargs): process_kwargs(self, kwargs, pl="widths_{0}_{1}_{2}".format(self.filter_type, self.bgsub_type, self.name)) pl = scatter(self.freq_axis[self.flat_indices], absolute([fp[0] for fp in self.fit_params]), **kwargs) if self.show_quick_fit: if self.flux_axis_type == "fq": #line(self.freq_axis[self.indices], self.qdt._get_coupling(f=self.frequency[self.indices])/1e9, plotter=pl, color="red") line(self.freq_axis[self.indices], self.qdt._get_fFWHM(f=self.frequency[self.indices])[2] / 2.0 / 1e9, plotter=pl, color="red") elif self.flux_axis_type == "yoko": line( self.freq_axis[self.indices], self.qdt._get_VfFWHM(f=self.frequency[self.indices])[2] / 2.0, pl=pl, color="red" ) #self.voltage_from_frequency(self.qdt._get_coupling(self.frequency)), plotter=pl, color="red") else: line( self.freq_axis[self.indices], self.qdt._get_fluxfFWHM(f=self.frequency[self.indices])[2] / 2.0, pl=pl, color="red" ) #self.voltage_from_frequency(self.qdt._get_coupling(self.frequency)), plotter=pl, color="red") if self.fitter.p_guess is not None: line( self.freq_axis[self.flat_indices], array([pg[0] for pg in self.fitter.p_guess]), pl=pl, color="green" ) #self.voltage_from_frequency(self.qdt._get_coupling(self.frequency)), plotter=pl, color="red") return pl def center_plot(self, **kwargs): process_kwargs(self, kwargs, pl="center_{0}_{1}_{2}".format(self.filter_type, self.bgsub_type, self.name)) pl = scatter(self.freq_axis[self.flat_indices], array([fp[1] for fp in self.fit_params]), **kwargs) if self.show_quick_fit: if self.flux_axis_type == "fq": line(self.freq_axis[self.indices], self.ls_f[self.indices] / 1e9, plotter=pl, color="red", linewidth=1.0) elif self.flux_axis_type == "yoko": line(self.freq_axis[self.indices], self.qdt._get_Vfq0(f=self.frequency[self.indices]), plotter=pl, color="red", linewidth=1.0) else: line(self.freq_axis, self.qdt._get_fluxfq0(f=self.frequency), plotter=pl, color="red", linewidth=1.0) if self.fitter.p_guess is not None: line( self.freq_axis[self.indices], array([pg[1] for pg in self.fitter.p_guess]), pl=pl, color="green", linewidth=1.0 ) #self.voltage_from_frequency(self.qdt._get_coupling(self.frequency)), plotter=pl, color="red") return pl def heights_plot(self, pl=None): pl = line(self.freq_axis[self.flat_indices], array([fp[2] for fp in self.fit_params]), pl=pl) if self.show_quick_fit: if self.fitter.p_guess is not None: line( self.freq_axis[self.flat_indices], array([pg[2] for pg in self.fitter.p_guess]), pl=pl, color="green", linewidth=1.0 ) #self.voltage_from_frequency(self.qdt._get_coupling(self.frequency)), plotter=pl, color="red") return pl def background_plot(self, pl=None): pl = line(self.freq_axis[self.flat_indices], array([fp[2] + fp[3] for fp in self.fit_params]), pl=pl) line(self.freq_axis[self.indices], self.MagAbsFilt_sq[self.indices, 0], plotter=pl, color="red", linewidth=1.0, alpha=0.5) if self.show_quick_fit: if self.fitter.p_guess is not None: line(self.freq_axis[self.flat_indices], array([pg[2] + pg[3] for pg in self.fitter.p_guess]), pl=pl, color="green", linewidth=0.5) return pl def magabs_colormesh(self, **kwargs): process_kwargs(self, kwargs, pl="magabs_{0}_{1}_{2}".format(self.filter_type, self.bgsub_type, self.name)) if self.filter_type == "Fit": flux_axis = self.flux_axis[self.flat_flux_indices] freq_axis = self.freq_axis[self.indices] start_ind = 0 for ind in self.fit_indices: pl = colormesh(flux_axis, self.freq_axis[ind], self.MagAbs[start_ind:start_ind + len(ind), :], **kwargs) start_ind += len(ind) elif self.filter_type == "None": flux_axis = self.flux_axis freq_axis = self.freq_axis pl = colormesh(self.flux_axis, self.freq_axis, self.MagAbs, **kwargs) else: flux_axis = self.flux_axis[self.flat_flux_indices] freq_axis = self.freq_axis[self.indices] pl = colormesh(flux_axis, freq_axis, self.MagAbs, **kwargs) if isinstance(pl, tuple): pl, pf = pl else: pf = None if pl.auto_ylim: pl.set_ylim(min(freq_axis), max(freq_axis)) if pl.auto_xlim: pl.set_xlim(min(flux_axis), max(flux_axis)) pl.xlabel = kwargs.pop("xlabel", self.flux_axis_label) pl.ylabel = kwargs.pop("ylabel", self.freq_axis_label) if pf is None: return pl return pl, pf def magdB_colormesh(self, **kwargs): process_kwargs(self, kwargs, pl="magdB_{0}_{1}_{2}".format(self.filter_type, self.bgsub_type, self.name)) if self.filter_type == "Fit": flux_axis = self.flux_axis[self.flat_flux_indices] freq_axis = self.freq_axis[self.indices] start_ind = 0 for ind in self.fit_indices: pl = colormesh(flux_axis, self.freq_axis[ind], self.MagdB[start_ind:start_ind + len(ind), :], **kwargs) start_ind += len(ind) elif self.filter_type == "None": flux_axis = self.flux_axis freq_axis = self.freq_axis pl = colormesh(self.flux_axis, self.freq_axis, self.MagdB, **kwargs) else: flux_axis = self.flux_axis[self.flat_flux_indices] freq_axis = self.freq_axis[self.indices] pl = colormesh(flux_axis, freq_axis, self.MagdB, **kwargs) if isinstance(pl, tuple): pl, pf = pl else: pf = None if pl.auto_ylim: pl.set_ylim(min(freq_axis), max(freq_axis)) if pl.auto_xlim: pl.set_xlim(min(flux_axis), max(flux_axis)) pl.xlabel = kwargs.pop("xlabel", self.flux_axis_label) pl.ylabel = kwargs.pop("ylabel", self.freq_axis_label) if pf is None: return pl return pl, pf def phase_colormesh(self, **kwargs): process_kwargs(self, kwargs, pl="phase_{0}_{1}_{2}".format(self.filter_type, self.bgsub_type, self.name)) if self.filter_type == "Fit": start_ind = 0 for ind in self.fit_indices: pl = colormesh(self.flux_axis, self.freq_axis[ind], self.Phase[start_ind:start_ind + len(ind), :], **kwargs) start_ind += len(ind) else: pl = colormesh(self.flux_axis, self.freq_axis[self.indices], self.Phase, **kwargs) pl.set_ylim(min(self.freq_axis[self.indices]), max(self.freq_axis[self.indices])) pl.set_xlim(min(self.flux_axis), max(self.flux_axis)) pl.xlabel = kwargs.pop("xlabel", self.flux_axis_label) pl.ylabel = kwargs.pop("ylabel", self.freq_axis_label) return pl def ifft_plot(self, **kwargs): process_kwargs(self, kwargs, pl="hannifft_{0}_{1}_{2}".format( self.filter_type, self.bgsub_type, self.name)) on_res = absolute( self.filt.window_ifft(self.Magcom[:, self.on_res_ind])) strt = absolute(self.filt.window_ifft(self.Magcom[:, self.start_ind])) stop = absolute(self.filt.window_ifft(self.Magcom[:, self.stop_ind])) pl = line(self.time_axis, self.filt.fftshift(on_res), color="red", plot_name="onres_{}".format(self.on_res_ind), label="{:.4g}".format(self.flux_axis[self.on_res_ind]), **kwargs) line(self.time_axis, self.filt.fftshift(strt), pl=pl, linewidth=1.0, color="purple", plot_name="strt {}".format(self.start_ind), label="{:.4g}".format(self.flux_axis[self.start_ind])) line(self.time_axis, self.filt.fftshift(stop), pl=pl, linewidth=1.0, color="blue", plot_name="stop {}".format(self.stop_ind), label="{:.4g}".format(self.flux_axis[self.stop_ind])) self.filt.N = len(on_res) filt = self.filt.freqz #filt=filt_prep(len(on_res), self.filt_start_ind, self.filt_end_ind) top = max([amax(on_res), amax(strt), amax(stop)]) line(self.time_axis, filt * top, plotter=pl, color="green", label="wdw") pl.xlabel = kwargs.pop("xlabel", self.time_axis_label) pl.ylabel = kwargs.pop("ylabel", "Mag abs") return pl def ifft_plot_time(self, **kwargs): process_kwargs(self, kwargs, pl="hannifft{0}{1}_{2}".format(self.filter_type, self.bgsub_type, self.name)) on_res = absolute( self.filt.window_ifft(self.MagcomData[:, self.on_res_ind])) strt = absolute( self.filt.window_ifft(self.MagcomData[:, self.start_ind])) stop = absolute( self.filt.window_ifft(self.MagcomData[:, self.stop_ind])) self.filt.N = len(on_res) pl = line(self.ifft_time / 1e-6, self.filt.fftshift(on_res), color="red", plot_name="onres_{}".format(self.on_res_ind), label="i {}".format(self.on_res_ind), **kwargs) line(self.ifft_time / 1e-6, self.filt.fftshift(strt), pl=pl, linewidth=1.0, plot_name="strt {}".format(self.start_ind), label="i {}".format(self.start_ind)) line(self.ifft_time / 1e-6, self.filt.fftshift(stop), pl=pl, linewidth=1.0, plot_name="stop {}".format(self.stop_ind), label="i {}".format(self.stop_ind)) filt = self.filt.freqz #filt=filt_prep(len(on_res), self.filt_start_ind, self.filt_end_ind) top = max([amax(on_res), amax(strt), amax(stop)]) line(self.ifft_time / 1e-6, filt * top, plotter=pl, color="green") pl.xlabel = kwargs.pop("xlabel", "Time (us)") pl.ylabel = kwargs.pop("ylabel", "Time (us)") return pl def MagdB_cs(self, pl, ind): pl, pf = line(self.frequency, self.MagdB[:, ind], label="MagAbs (unfiltered)", plotter="filtcomp_{}".format(self.name)) line(self.frequency, self.MagdBFilt[:, ind], label="MagAbs (filtered)", plotter=pl) return pl def filt_compare(self, ind, **kwargs): process_kwargs(self, kwargs, pl="filtcomp_{0}_{1}_{2}".format( self.filter_type, self.bgsub_type, self.name)) self.filter_type = "None" pl = line(self.frequency, self.MagdB[:, ind], label="MagAbs (unfiltered)", **kwargs) self.filter_type = "FFT" line(self.frequency, self.MagdB[:, ind], label="MagAbs (filtered)", plotter=pl) return pl
class Qubit(Agent): """Theoretical description of qubit""" base_name="qubit" Cc=Float(1e-15).tag(desc="coupling capacitance", unit="fF") qubit_type=Enum("transmon", "scb") dephasing=Float(0.0).tag(unit="GHz") dephasing_slope=Float(0.0) @private_property def view_window(self): return QubitView(agent=self) superconductor=Enum("Al").tag(label="material") def _observe_superconductor(self, change): if self.superconductor=="Al": self.Delta=Delta_Al Tc=Float(Tc_Al).tag(desc="Critical temperature of superconductor", unit="K", label="Critical temperature") Delta=SProperty().tag(label="Gap", tex_str=r"$\Delta(0)$", unit="ueV", desc="BCS superconducting gap, 200 ueV for Al", reference="BCS", expression=r"$\Delta(0)=1.764 k_B T_c$") @Delta.getter def _get_Delta(self, Tc): """BCS theory superconducting gap""" return 1.764*kB*Tc @Delta.setter def _get_Tc(self, Delta): return Delta/(1.764*kB) loop_width=Float(1.0e-6).tag(desc="loop width of SQUID", unit="um", label="loop width") loop_height=Float(1.0e-6).tag(desc="loop height of SQUID", unit="um", label="loop height") loop_area=SProperty().tag(desc="Area of SQUID loop", unit="um^2", expression="$width \times height$", comment="Loop width times loop height", label="loop area") @loop_area.getter def _get_loop_area(self, loop_width, loop_height): return loop_width*loop_height Ct=Float(1.3e-13).tag(desc="shunt capacitance", unit="fF", tex_str=r"$C_q$") Rn=Float(5.0e3).tag(desc="Normal resistance of SQUID", unit="kOhm", label="DC Junction resistance", expression=r"$R_N$") Ic=SProperty().tag(desc="critical current of SQUID, Ambegaokar Baratoff formula", unit="nA", label="Critical current", expression=r"$I_C=\pi \Delta/(2e R_N)$") @Ic.getter def _get_Ic(self, Rn, Delta): """Ic*Rn=pi*Delta/(2.0*e) #Ambegaokar Baratoff formula""" return pi*Delta/(2.0*e)/Rn @Ic.setter def _get_Rn(self, Ic, Delta): """Ic*Rn=pi*Delta/(2.0*e) #Ambegaokar Baratoff formula""" return pi*Delta/(2.0*e)/Ic Ejmax=SProperty().tag(desc="""Max Josephson Energy""", unit="hGHz", expression=r'$E_{Jmax}=\hbar I_C/2e$', label="Max Josephson energy")#, unit_factor=1.0e9*h) @Ejmax.getter def _get_Ejmax(self, Ic): """Josephson energy""" return hbar*Ic/(2.0*e) @Ejmax.setter def _get_Ic_get_Ejmax(self, Ejmax): """inverse Josephson energy""" return Ejmax*(2.0*e)/hbar Ec=SProperty().tag(desc="Charging Energy", unit="hGHz", label="Charging energy", expression=r"$E_C=e^2/2 C_t$")#, unit_factor=1.0e9*h) @Ec.getter def _get_Ec(self, Ct, Cc): """Charging energy""" return e**2/(2.0*(Ct+Cc)) @Ec.setter def _get_Ct(self, Ec, Cc): """inverse charging energy""" return e**2/(2.0*Ec)-Cc @Ec.setter def _get_Ejmax_get_Ec(self, Ec, EjmaxdivEc): return EjmaxdivEc*Ec EjmaxdivEc=SProperty().tag(desc="Maximum Ej over Ec", label=r"Maximum $E_J$ over $E_C$", expression=r"$E_{Jmax}/E_C$") @EjmaxdivEc.getter def _get_EjmaxdivEc(self, Ejmax, Ec): return Ejmax/Ec Ej=SProperty().tag(unit="hGHz", label="Josephson energy", expression=r"$E_J=E_{Jmax}|\cos(\Phi/\Phi_0)|$") @Ej.getter def _get_Ej(self, Ejmax, flux_over_flux0): return Ejmax*absolute(cos(flux_over_flux0)) #*pi @Ej.setter def _get_flux_over_flux0_get_Ej(self, Ej, Ejmax): return arccos(Ej/Ejmax)#/pi EjdivEc=SProperty().tag(desc="Ej over Ec", label="Ej over Ec", expression=r"$E_J/E_C$") @EjdivEc.getter def _get_EjdivEc(self, Ej, Ec): return Ej/Ec fq_approx_max=SProperty().tag(unit="GHz", label="fq approx max", desc="qubit frequency using approximate transmon formula", expression=r"$f_{qmax} \approx (\sqrt{8E_{Jmax} E_C}-E_C)/h$") @fq_approx_max.getter def _get_fq_approx_max(self, Ejmax, Ec): return self._get_fq_approx(Ej=Ejmax, Ec=Ec) fq_approx=SProperty().tag(unit="GHz", expression=r"$f_q \approx (\sqrt{8E_J E_C}-E_C)/h$") @fq_approx.getter def _get_fq_approx(self, Ej, Ec): return (sqrt(8.0*Ej*Ec)-Ec)/h fq_max=SProperty().tag(unit="GHz", label="fq max", expression=r"$f_{qmax}$") @fq_max.getter def _get_fq_max(self, Ejmax, Ec, qubit_type, ng, Nstates): return self._get_fq(Ej=Ejmax, Ec=Ec, qubit_type=qubit_type, ng=ng, Nstates=Nstates) fq=SProperty().tag(desc="""Operating frequency of qubit""", unit="GHz", expression=r"$f_q$") @fq.getter def _get_fq(self, Ej, Ec, qubit_type, ng, Nstates): E0, E1=self._get_energy_levels(Ej=Ej, Ec=Ec, n_energy=2, qubit_type=qubit_type, ng=ng, Nstates=Nstates) return (E1-E0)/h @fq.setter def _get_Ej_get_fq(self, fq, Ec): """h*fq=sqrt(8.0*Ej*Ec) - Ec""" return ((h*fq+Ec)**2)/(8.0*Ec) L=SProperty().tag(label="Kinetic inductance of SQUID", expression=r"$L$") @L.getter def _get_L(self, fq, Ct): return 1.0/(Ct*(2*pi*fq)**2) anharm=SProperty().tag(desc="absolute anharmonicity", unit="GHz") @anharm.getter def _get_anharm(self, Ej, Ec, qubit_type, ng, Nstates): E0, E1, E2=self._get_energy_levels(Ej=Ej, Ec=Ec, n_energy=3, qubit_type=qubit_type, ng=ng, Nstates=Nstates) return (E2-E1)/h-(E1-E0)/h fq2=SProperty().tag(desc="""20 over 2 freq""", unit="GHz", expression = r"$f_{20}/2$") @fq2.getter def _get_fq2(self, Ej, Ec, qubit_type, ng, Nstates): E0, E1, E2=self._get_energy_levels(Ej=Ej, Ec=Ec, n_energy=3, qubit_type=qubit_type, ng=ng, Nstates=Nstates) return (E2-E0)/h/2.0 voltage=Float().tag(unit="V", desc="Yoko voltage on coil") offset=Float(0.09).tag(unit="V", desc="offset of flux in volts") flux_factor=Float(0.195).tag(desc="converts voltage to flux") flux_factor_beta=Float().tag(desc="linear dependenc on magnetic field") flux_over_flux0=SProperty().tag(expression=r"$\Phi/\Phi_0=$(voltage-offset)fluxfactor", unit="pi") @flux_over_flux0.getter def _get_flux_over_flux0(self, voltage, offset, flux_factor, flux_factor_beta): return (voltage-offset)*flux_factor#/(1.0-flux_factor_beta*(voltage-offset)) #return (voltage-offset)*flux_factor @flux_over_flux0.setter def _get_voltage(self, flux_over_flux0, offset, flux_factor, flux_factor_beta): #return flux_over_flux0/flux_factor*(1-flux_factor_beta/flux_factor*flux_over_flux0)+offset #return flux_over_flux0/flux_factor+offset+sign(flux_over_flux0)*flux_factor_beta*flux_over_flux0**2 #return flux_over_flux0/flux_factor+offset+flux_factor_beta*flux_over_flux0**3 return flux_over_flux0/flux_factor+offset flux_parabola=SProperty() @flux_parabola.getter def _get_flux_parabola(self, voltage, offset, flux_factor, Ejmax, Ec, qubit_type, ng, Nstates): flx_d_flx0=self._get_flux_over_flux0(voltage=voltage, offset=offset, flux_factor=flux_factor) qEj=self._get_Ej(Ejmax=Ejmax, flux_over_flux0=flx_d_flx0) return self._get_fq(Ej=qEj, Ec=Ec, qubit_type=qubit_type, ng=ng, Nstates=Nstates)#, fq2(qEj, Ec) #freq_arr=Array().tag(desc="array of frequencies to evaluate over") f=Float(4.4e9).tag(label="Operating frequency", desc="what frequency is being stimulated/measured", unit="GHz") flux_from_fq=SProperty().tag(sub=True) @flux_from_fq.getter def _get_flux_from_fq(self, fq, Ct, Ejmax): Ec=self._get_Ec(Ct=Ct) Ej=self._get_Ej_get_fq(fq=fq, Ec=Ec) return self._get_flux_over_flux0_get_Ej(Ej=Ej, Ejmax=Ejmax) voltage_from_flux_par=SProperty().tag(sub=True) @voltage_from_flux_par.getter def _get_voltage_from_flux_par(self, fq, Ct, Ejmax, offset, flux_factor): #Ec=self._get_Ec(Ct=Ct) #Ej=self._get_Ej_get_fq(fq=fq, Ec=Ec) flux_d_flux0=self._get_flux_from_fq(fq, Ct, Ejmax) #self._get_flux_over_flux0_get_Ej(Ej=Ej, Ejmax=Ejmax) return self._get_voltage(flux_over_flux0=flux_d_flux0, offset=offset, flux_factor=flux_factor) voltage_from_flux_par_many=SProperty().tag(sub=True) @voltage_from_flux_par_many.getter def _get_voltage_from_flux_par_many(self, fq, Ct, Ejmax, offset, flux_factor, flux_factor_beta): #Ec=self._get_Ec(Ct=Ct) #Ej=self._get_Ej_get_fq(fq=f, Ec=Ec) fdf0=self._get_flux_from_fq(fq, Ct, Ejmax) #self._get_flux_over_flux0_get_Ej(Ej=Ej, Ejmax=Ejmax) #fdf0=self._get_flux_over_flux0_get_Ej(Ej=Ej, Ejmax=Ejmax) flux_d_flux0=append(fdf0, -fdf0) flux_d_flux0=append(flux_d_flux0, -fdf0+pi*(1+flux_factor_beta)) flux_d_flux0=append(flux_d_flux0, fdf0-pi*(1+flux_factor_beta)) freq=append(fq, fq) freq=append(freq, freq) return freq/1e9, self._get_voltage(flux_over_flux0=flux_d_flux0, offset=offset, flux_factor=flux_factor) def detuning(self, fq_off): return 2.0*pi*(self.fq - fq_off) def transmon_energy(self, Ej, Ec, m): return -Ej+sqrt(8.0*Ej*Ec)*(m+0.5) - (Ec/12.0)*(6.0*m**2+6.0*m+3.0) transmon_energy_levels=SProperty().tag(sub=True) @transmon_energy_levels.getter def _get_transmon_energy_levels(self, Ej, Ec, n_energy): return [self.transmon_energy(Ej, Ec, m) for m in range(n_energy)] n_energy=Int(3) ng=Float(0.5).tag(desc="charge on gate line", log=False) Nstates=Int(50).tag(desc="number of states to include in mathieu approximation. More states is better approximation") order=Int(3) EkdivEc=Array().tag(unit2="Ec", sub=True) energy_levels=SProperty().tag(sub=True) @energy_levels.getter def _get_energy_levels(self, Ej, Ec, n_energy, qubit_type, ng, Nstates): if qubit_type=="scb": return self._get_scb_energy_levels(Ej=Ej, Ec=Ec, n_energy=n_energy, ng=ng, Nstates=Nstates) return self._get_transmon_energy_levels(Ej=Ej, Ec=Ec, n_energy=n_energy) def indiv_EkdivEc(self, EjdivEc, n_energy, ng, Nstates): """calculates energies assuming float values given""" NL=2*Nstates+1 A=zeros((NL, NL)) for b in range(0,NL): A[b, b]=4.0*(b-Nstates-ng)**2 if b!=NL-1: A[b, b+1]= -EjdivEc/2.0 if b!=0: A[b, b-1]= -EjdivEc/2.0 #w,v=eig(A) w=eigvalsh(A) return w[0:n_energy] scb_energy_levels=SProperty().tag(sub=True) @scb_energy_levels.getter def _get_scb_energy_levels(self, Ej, Ec, n_energy, ng, Nstates): if isinstance(Ej, float): Ej=array([Ej]) if isinstance(ng, float): ng=[ng] EjdivEc=Ej/Ec energies=Ec*squeeze([[self.indiv_EkdivEc(EjdivEc=ejc, n_energy=n_energy, ng=ng_s, Nstates=Nstates) for ejc in EjdivEc] for ng_s in ng]) return [spl.transpose() for spl in split(energies.transpose(), n_energy)] #energies=squeeze(energies) NL=2*Nstates+1 A=zeros((NL, NL)) for b in range(0,NL): A[b, b]=4.0*Ec*(b-Nstates-ng)**2 if b!=NL-1: A[b, b+1]= -Ej/2.0 if b!=0: A[b, b-1]= -Ej/2.0 #w,v=eig(A) w=eigvalsh(A) return w[0:n_energy] def update_EkdivEc(self, ng, Ec, Ej, Nstates, order): """calculates transmon energy level with N states (more states is better approximation) effectively solves the mathieu equation but for fractional inputs (which doesn't work in scipy.special.mathieu_a)""" # if type(ng) not in (int, float): # d=zeros((order, len(ng))) # elif type(Ec) not in (int, float): # d=zeros((order, len(Ec))) # elif type(Ej) not in (int, float): # d=zeros((order, len(Ej))) if type(ng) in (int, float): ng=array([ng]) d1=[] d2=[] d3=[] Ej=Ej/Ec Ec=1.0#/4.0 for a in ng: NL=2*Nstates+1 A=zeros((NL, NL)) for b in range(0,NL): A[b, b]=4.0*Ec*(b-Nstates-a)**2 if b!=NL-1: A[b, b+1]= -Ej/2.0 if b!=0: A[b, b-1]= -Ej/2.0 #w,v=eig(A) w=eigvalsh(A) d=w[0:order] # d1.append(min(w))#/h*1e-9) # w=delete(w, w.argmin()) # d2.append(min(w))#/h*1e-9) # w=delete(w, w.argmin()) # d3.append(min(w))#/h*1e-9) return array([array(d1), array(d2), array(d3)]).transpose() def sweepEc(): Ecarr=Ej/EjoverEc E01a=sqrt(8*Ej*Ecarr)-Ecarr data=[] for Ec in Ecarr: d1, d2, d3= EkdivEc(ng=ng, Ec=Ec, Ej=Ej, N=50) E12=d3[0]-d2[0] E01=d2[0]-d1[0] anharm2=(E12-E01)#/E01 data.append(anharm2) Ctr=e**2/(2.0*Ecarr*h*1e9) return E01a, Ctr, data, d1, d2, d3
class Qubit(Agent): """Theoretical description of qubit""" base_name="qubit" #def _default_main_params(self): # return ["ft", "f0", "lbda0", "a", "g", "eta", "Np", "ef", "W", "Ct", # "material", "Dvv", "K2", "vf", "epsinf", # "Rn", "Ic", "Ejmax", "Ej", "Ec", "EjmaxdivEc", "EjdivEc", # "fq", "fq_max", "fq_max_full", "flux_over_flux0", "G_f0", "G_f", # "ng", "Nstates", "EkdivEc"] superconductor=Enum("Al") def _observe_superconductor(self, change): if self.superconductor=="Al": self.Delta=Delta_Al Tc=Float(Tc_Al).tag(desc="Critical temperature of superconductor", unit="K") Delta=SProperty().tag(label="Gap", tex_str=r"$\Delta(0)$", unit="ueV", desc="Superconducting gap 200 ueV for Al", reference="BCS", expression=r"$1.764 k_B T_c$") @Delta.getter def _get_Delta(self, Tc): """BCS theory superconducting gap""" return 1.764*kB*Tc @Delta.setter def _get_Tc(self, Delta): return Delta/(1.764*kB) loop_width=Float(1.0e-6).tag(desc="loop width of SQUID", unit="um", label="loop width") loop_height=Float(1.0e-6).tag(desc="loop height of SQUID", unit="um", label="loop height") loop_area=SProperty().tag(desc="Area of SQUID loop", unit="um^2", expression="$width \times height$", comment="Loop width times loop height", label="loop area") @loop_area.getter def _get_loop_area(self, loop_width, loop_height): return loop_width*loop_height C=Float(1.0e-13).tag(desc="shunt capacitance", unit="fF", tex_str=r"$C_q$") Rn=Float(10.0e3).tag(desc="Normal resistance of SQUID", unit="kOhm", label="DC Junction resistance", tex_str=r"$R_n$") Ic=SProperty().tag(desc="critical current of SQUID", unit="nA", label="Critical current", tex_str=r"$I_C$") @Ic.getter def _get_Ic(self, Rn, Delta): """Ic*Rn=pi*Delta/(2.0*e) #Ambegaokar Baratoff formula""" return pi*Delta/(2.0*e)/Rn @Ic.setter def _get_Rn(self, Ic, Delta): """Ic*Rn=pi*Delta/(2.0*e) #Ambegaokar Baratoff formula""" return pi*Delta/(2.0*e)/Ic Ejmax=SProperty().tag(desc="""Max Josephson Energy""", unit="hGHz")#, unit_factor=1.0e9*h) @Ejmax.getter def _get_Ejmax(self, Ic): """Josephson energy""" return hbar*Ic/(2.0*e) @Ejmax.setter def _get_Ic_get_Ejmax(self, Ejmax): """inverse Josephson energy""" return Ejmax*(2.0*e)/hbar Ec=SProperty().tag(desc="Charging Energy", unit="hGHz")#, unit_factor=1.0e9*h) @Ec.getter def _get_Ec(self, C): """Charging energy""" return e**2/(2.0*C) @Ec.setter def _get_C(self, Ec): """inverse charging energy""" return e**2/(2.0*Ec) @Ec.setter def _get_Ejmax_get_Ec(self, Ec, EjmaxdivEc): return EjmaxdivEc*Ec EjmaxdivEc=SProperty().tag(desc="Maximum Ej over Ec") @EjmaxdivEc.getter def _get_EjmaxdivEc(self, Ejmax, Ec): return Ejmax/Ec Ej=SProperty().tag(unit="hGHz") @Ej.getter def _get_Ej(self, Ejmax, flux_over_flux0): return Ejmax*absolute(cos(flux_over_flux0)) #*pi @Ej.setter def _get_flux_over_flux0_get_Ej(self, Ej, Ejmax): return arccos(Ej/Ejmax)#/pi EjdivEc=SProperty().tag(desc="Ej over Ec") @EjdivEc.getter def _get_EjdivEc(self, Ej, Ec): return Ej/Ec fq_approx_max=SProperty().tag(unit="GHz", label="fq max") @fq_approx_max.getter def _get_fq_approx_max(self, Ejmax, Ec): return self._get_fq_approx(Ej=Ejmax, Ec=Ec) fq_approx=SProperty() @fq_approx.getter def _get_fq_approx(self, Ej, Ec): return (sqrt(8.0*Ej*Ec)-Ec)/h fq_max=SProperty().tag(unit="hGHz", label="fq max full") @fq_approx.getter def _get_fq_max(self, Ejmax, Ec): return self._get_fq(Ej=Ejmax, Ec=Ec) fq=SProperty().tag(desc="""Operating frequency of qubit""", unit="GHz") @fq.getter def _get_fq(self, Ej, Ec): E0, E1=self._get_transmon_energy_levels(Ej=Ej, Ec=Ec, n_energy=2) return (E1-E0)/h @fq.setter def _get_Ej_get_fq(self, fq, Ec): """h*fq=sqrt(8.0*Ej*Ec) - Ec""" return ((h*fq+Ec)**2)/(8.0*Ec) L=SProperty() @L.getter def _get_L(self, fq, C): return 1.0/(C*(2*pi*fq)**2) anharm=SProperty().tag(desc="absolute anharmonicity", unit="hGHz") @anharm.getter def _get_anharm(self, Ej, Ec): E0, E1, E2=self._get_transmon_energy_levels(Ej=Ej, Ec=Ec, n_energy=3) return (E2-E1)/h-(E1-E0)/h fq2=SProperty().tag(desc="""20 over 2 freq""", unit="GHz") @fq2.getter def _get_fq2(self, Ej, Ec): E0, E1, E2=self._get_transmon_energy_levels(Ej=Ej, Ec=Ec, n_energy=3) return (E2-E0)/h/2.0 voltage=Float().tag(unit="V") offset=Float(0.09).tag(unit="V") flux_factor=Float(0.195) flux_over_flux0=SProperty() @flux_over_flux0.getter def _get_flux_over_flux0(self, voltage, offset, flux_factor): return (voltage-offset)*flux_factor @flux_over_flux0.setter def _get_voltage(self, flux_over_flux0, offset, flux_factor): return flux_over_flux0/flux_factor+offset flux_parabola=SProperty() @flux_parabola.getter def _get_flux_parabola(self, voltage, offset, flux_factor, Ejmax, Ec): flx_d_flx0=self._get_flux_over_flux0(voltage=voltage, offset=offset, flux_factor=flux_factor) qEj=self._get_Ej(Ejmax=Ejmax, flux_over_flux0=flx_d_flx0) return self._get_fq(Ej=qEj, Ec=Ec)#, fq2(qEj, Ec) #freq_arr=Array().tag(desc="array of frequencies to evaluate over") f=Float(4.4e9).tag(desc="Operating frequency, e.g. what frequency is being stimulated/measured") voltage_from_flux_par=SProperty().tag(sub=True) @voltage_from_flux_par.getter def _get_voltage_from_flux_par(self, f, C, Ejmax, offset, flux_factor): Ec=self._get_Ec(C=C) Ej=self._get_Ej_get_fq(fq=f, Ec=Ec) flux_d_flux0=self._get_flux_over_flux0_get_Ej(Ej=Ej, Ejmax=Ejmax) return f/1e9, self._get_voltage(flux_over_flux0=flux_d_flux0, offset=offset, flux_factor=flux_factor) voltage_from_flux_par_many=SProperty().tag(sub=True) @voltage_from_flux_par_many.getter def _get_voltage_from_flux_par_many(self, f, C, Ejmax, offset, flux_factor): Ec=self._get_Ec(C=C) Ej=self._get_Ej_get_fq(fq=f, Ec=Ec) fdf0=self._get_flux_over_flux0_get_Ej(Ej=Ej, Ejmax=Ejmax) flux_d_flux0=append(fdf0, -fdf0) flux_d_flux0=append(flux_d_flux0, -fdf0+pi) flux_d_flux0=append(flux_d_flux0, fdf0-pi) freq=append(f, f) freq=append(freq, freq) return freq/1e9, self._get_voltage(flux_over_flux0=flux_d_flux0, offset=offset, flux_factor=flux_factor) def detuning(self, fq_off): return 2.0*pi*(self.fq - fq_off) def transmon_energy(self, Ej, Ec, m): return -Ej+sqrt(8.0*Ej*Ec)*(m+0.5) - (Ec/12.0)*(6.0*m**2+6.0*m+3.0) transmon_energy_levels=SProperty().tag(sub=True) @transmon_energy_levels.getter def _get_transmon_energy_levels(self, Ej, Ec, n_energy): #Ej=EjdivEc*Ec return [self.transmon_energy(Ej, Ec, m) for m in range(n_energy)] n_energy=Int(3) def indiv_EkdivEc(self, ng, Ec, Ej, Nstates, order): NL=2*Nstates+1 A=zeros((NL, NL)) for b in range(0,NL): A[b, b]=4.0*Ec*(b-Nstates-a)**2 if b!=NL-1: A[b, b+1]= -Ej/2.0 if b!=0: A[b, b-1]= -Ej/2.0 w,v=eig(A) print w, v #for n in range(order): ng=Float(0.5).tag(desc="charge on gate line") Nstates=Int(50).tag(desc="number of states to include in mathieu approximation. More states is better approximation") order=Int(3) EkdivEc=Array().tag(unit2="Ec", sub=True) def update_EkdivEc(self, ng, Ec, Ej, Nstates, order): """calculates transmon energy level with N states (more states is better approximation) effectively solves the mathieu equation but for fractional inputs (which doesn't work in scipy.special.mathieu_a)""" # if type(ng) not in (int, float): # d=zeros((order, len(ng))) # elif type(Ec) not in (int, float): # d=zeros((order, len(Ec))) # elif type(Ej) not in (int, float): # d=zeros((order, len(Ej))) if type(ng) in (int, float): ng=array([ng]) d1=[] d2=[] d3=[] Ej=Ej/Ec Ec=1.0#/4.0 for a in ng: NL=2*Nstates+1 A=zeros((NL, NL)) for b in range(0,NL): A[b, b]=4.0*Ec*(b-Nstates-a)**2 if b!=NL-1: A[b, b+1]= -Ej/2.0 if b!=0: A[b, b-1]= -Ej/2.0 #w,v=eig(A) w=eigvalsh(A) d=w[0:order] # d1.append(min(w))#/h*1e-9) # w=delete(w, w.argmin()) # d2.append(min(w))#/h*1e-9) # w=delete(w, w.argmin()) # d3.append(min(w))#/h*1e-9) return array([array(d1), array(d2), array(d3)]).transpose() def sweepEc(): Ecarr=Ej/EjoverEc E01a=sqrt(8*Ej*Ecarr)-Ecarr data=[] for Ec in Ecarr: d1, d2, d3= EkdivEc(ng=ng, Ec=Ec, Ej=Ej, N=50) E12=d3[0]-d2[0] E01=d2[0]-d1[0] anharm2=(E12-E01)#/E01 data.append(anharm2) Ctr=e**2/(2.0*Ecarr*h*1e9) return E01a, Ctr, data, d1, d2, d3