def NqpfromQi(S21data, uselowtempapprox=True, lbd0=0.092, kb=86.17, N0=1.72e4, kbTD=37312.0): '''Calculates the number of quasiparticles from the measured temperature dependence of Qi. Returns temperatures in K, along with the calculated quasiparticle numbers. If uselowtempapprox, the complex impedence is calculated directly with a low temperature approximation, else it\'s calculated with the cinduct function in kidcalc (slow).''' ak_ = ak(S21data) hw = S21data[:, 5] * 2 * np.pi * 6.582e-4 * 1e-6 d = S21data[0, 25] kbTc = S21data[0, 21] * kb kbT = S21data[:, 1] * kb D0 = 1.76 * kbTc if uselowtempapprox: beta_ = beta(lbd0, d, D0, D0, kbT[0]) def minfunc(kbT, s2s1, hw, D0): xi = hw / (2 * kbT) return np.abs(np.pi/4*((np.exp(D0/kbT)-2*np.exp(-xi)*i0(xi))/\ (np.sinh(xi)*k0(xi)))-s2s1) Nqp = np.zeros(len(kbT)) for i in range(len(kbT)): s2s1 = S21data[i, 4] * (ak_ * beta_) / 2 res = minisc(minfunc, args=(s2s1, hw[i], D0), bounds=(0, kbTc), method='bounded') kbTeff = res.x Nqp[i] = S21data[0, 14] * nqp(kbTeff, D0, N0) return kbT / kb, Nqp else: def minfunc(kbT, s2s1, hw, N0, kbTc, kbTD): D_ = D(kbT, N0, kbTc, kbTD) s1, s2 = cinduct(hw, D_, kbT) return np.abs(s2s1 - s2 / s1) Nqp = np.zeros(len(kbT)) for i in range(len(kbT)): D_0 = D(kbT[i], N0, kbTc, kbTD) beta_ = beta(lbd0, d, D_0, D0, kbT[i]) s2s1 = S21data[i, 4] * (ak_ * beta_) / 2 res = minisc(minfunc, args=(s2s1, hw[i], N0, kbTc, kbTD), bounds=(0, kbTc), method='bounded') kbTeff = res.x D_ = D(kbTeff, N0, kbTc, kbTD) Nqp[i] = S21data[0, 14] * nqp(kbTeff, D_, N0) return kbT / kb, Nqp
def NqpfromQi(S21data, uselowtempapprox=True, SC=SuperCond.Al()): """Calculates the number of quasiparticles from the measured temperature dependence of Qi. Returns temperatures in K, along with the calculated quasiparticle numbers. If uselowtempapprox, the complex impedence is calculated directly with a low temperature approximation, else it\'s calculated with the cinduct function in kidcalc (slow).""" ak_ = ak(S21data) hw = S21data[:, 5] * const.Plack / const.e * 1e6 kbT = S21data[:, 1] * const.Boltzmann / const.e * 1e6 if uselowtempapprox: beta_ = kidcalc.beta(kbT[0], SC.D0, SuperCond.Sheet(SC, d=S21data[0, 25])) def minfunc(kbT, s2s1, hw, D0): xi = hw / (2 * kbT) return np.abs(np.pi / 4 * ((np.exp(D0 / kbT) - 2 * np.exp(-xi) * i0(xi)) / (np.sinh(xi) * k0(xi))) - s2s1) Nqp = np.zeros(len(kbT)) for i in range(len(kbT)): s2s1 = S21data[i, 4] * (ak_ * beta_) / 2 res = minisc( minfunc, args=(s2s1, hw[i], SC.D0), bounds=(0, SC.kbTc), method="bounded", ) kbTeff = res.x Nqp[i] = S21data[0, 14] * kidcalc.nqp(kbTeff, SC.D0, SC) return kbT / (const.Boltzmann / const.e * 1e6), Nqp else: def minfunc(kbT, s2s1, hw, SC): D_ = kidcalc.D(kbT, SC) s1, s2 = kidcalc.cinduct(hw, D_, kbT) return np.abs(s2s1 - s2 / s1) Nqp = np.zeros(len(kbT)) for i in range(len(kbT)): D_0 = kidcalc.D(kbT[i], SC) beta_ = kidcalc.beta(kbT[i], D_0, SuperCond.Sheet(SC, d=S21data[0, 25])) s2s1 = S21data[i, 4] * (ak_ * beta_) / 2 res = minisc(minfunc, args=(s2s1, hw[i], SC), bounds=(0, SC.kbTc), method="bounded") kbTeff = res.x D_ = kidcalc.D(kbTeff, SC) Nqp[i] = S21data[0, 14] * kidcalc.nqp(kbTeff, D_, SC) return kbT / (const.Boltzmann / const.e * 1e6), Nqp
def D(kbT, SC): """Calculates the thermal average energy gap, Delta. Tries to load Ddata, but calculates from scratch otherwise. Then, it cannot handle arrays. """ Ddata = SC.Ddata if Ddata is not None: Dspl = interpolate.splrep(Ddata[0, :], Ddata[1, :], s=0) return np.clip(interpolate.splev(kbT, Dspl), 0, None) else: warnings.warn( "D calculation takes long.. \n Superconductor={}\n N0={}\n kbTD={}\n Tc={}" .format(SC.name, SC.N0, SC.kbTD, SC.kbTc / (const.Boltzmann / const.e * 1e6))) def integrandD(E, D, kbT, SC): return SC.N0 * SC.Vsc * (1 - 2 * f(E, kbT)) / np.sqrt(E**2 - D**2) def dint(D, kbT, SC): return np.abs( integrate.quad( integrandD, D, SC.kbTD, args=(D, kbT, SC), points=(D, ))[0] - 1) res = minisc(dint, args=(kbT, SC), method="bounded", bounds=(0, SC.D0)) if res.success: return np.clip(res.x, 0, None)
def kbTeff(N_qp, N0, V, kbTc, kbTD): '''Calculates the effective temperature (in µeV) at a certain number of quasiparticles.''' Ddata = load_Ddata(N0, kbTc, kbTD) if Ddata is not None: kbTspl = interpolate.splrep(Ddata[2, :], Ddata[0, :]) return interpolate.splev(N_qp / V, kbTspl) else: def minfunc(kbT, N_qp, N0, V, kbTc, kbTD): Dt = D(kbT, N0, kbTc, kbTD) return np.abs(nqp(kbT, Dt, N0) - N_qp / V) res = minisc(minfunc, bounds=(0, 1 * 86.17), args=(N_qp, N0, V, kbTc, kbTD), method="bounded", options={'xatol': 1e-15}) if res.success: return res.x
def hwread(hw0, kbT0, ak, lbd0, d, D_, D0, kbT, N0, kbTc, kbTD): '''Calculates at which frequency, on probes at resonance. This must be done iteratively, as the resonance frequency is dependent on the complex conductivity, which in turn depends on the read frequency.''' D_0 = D(kbT0, N0, kbTc, kbTD) s20 = cinduct(hw0, D_0, kbT0)[1] def minfuc(hw, hw0, s20, ak, lbd0, d, D_, D0, kbT): s1, s2 = cinduct(hw, D_, kbT) return np.abs(hwres(s2, hw0, s20, ak, lbd0, d, D_, D0, kbT) - hw) res = minisc( minfuc, bracket=(.5 * hw0, hw0, 2 * hw0), args=(hw0, s20, ak, lbd0, d, D_, D0, kbT), method="brent", options={"xtol": 1e-21}, ) if res.success: return res.x
def kbTeff(nqp, SC): """Calculates the effective temperature (in µeV) at a certain quasiparticle density.""" Ddata = SC.Ddata if Ddata is not None: kbTspl = interpolate.splrep(Ddata[2, :], Ddata[0, :]) return interpolate.splev(nqp, kbTspl) else: def minfunc(kbT, Nqp, SC): Dt = D(kbT, SC) return np.abs(nqp(kbT, Dt, SC) - nqp) res = minisc( minfunc, bounds=(0, 0.9 * SC.kbTc), args=(nqp, SC), method="bounded", options={"xatol": 1e-15}, ) if res.success: return res.x
def D(kbT, N0, kbTc, kbTD, kb=86.17): '''Calculates the thermal average energy gap, Delta. Tries to load Ddata, but calculates from scratch otherwise. Then, it cannot handle arrays. ''' Ddata = load_Ddata(N0, kbTc, kbTD) if Ddata is not None: Dspl = interpolate.splrep(Ddata[0, :], Ddata[1, :], s=0) return np.clip(interpolate.splev(kbT, Dspl), 0, None) else: warnings.warn('D takes long.. \n N0={}\n kbTD={}\n Tc={}'.format( N0, kbTD, kbTc / kb)) _Vsc = Vsc(kbTc, N0, kbTD) def integrandD(E, D, kbT, N0, _Vsc): return N0 * _Vsc * (1 - 2 * f(E, kbT)) / np.sqrt(E**2 - D**2) def dint(D, kbT, N0, _Vsc, kbTD): return np.abs( integrate.quad(integrandD, D, kbTD, args=(D, kbT, N0, _Vsc))[0] - 1) res = minisc(dint, args=(kbT, N0, _Vsc, kbTD)) if res.success: return np.clip(res.x, 0, None)
def fit_epb(self, peakdata, wvl, *args, var="phase"): """Sets the pair-breaking efficiency to match the maximum of the predicted pulse the highest point of peakdata.""" peakheight = peakdata.max() hwrad = const.Planck / const.e * 1e12 * const.c / (wvl * 1e-3) tres = self.tres def minfunc(epb, hwrad, tres, var, peakheight): self.epb = epb _, _, dAtheta = self.calc_respt(hwrad, *args, tStop=3 * tres, points=10) if var == "phase": return np.abs(dAtheta[1, :].max() - peakheight) elif var == "amp": return np.abs(dAtheta[0, :].max() - peakheight) res = minisc( minfunc, args=(hwrad, tres, var, peakheight), bounds=(0, 1), method="bounded", options={"maxiter": 5, "xatol": 1e-3}, ) self.epb = res.x