Exemplo n.º 1
0
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)))
Exemplo n.º 2
0
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
Exemplo n.º 3
0
class Rho(Agent):
    base_name = "rho"

    material = Enum('LiNbYZ', 'GaAs', 'LiNb128', 'LiNbYZX',
                    'STquartz').tag(label="material", expression="Substrate")

    def _default_material(self):
        return 'LiNbYZ'

    def _observe_material(self, change):
        if change["type"] == "update":
            self.Dvv = None
            self.vf = None
            self.epsinf = None

    @t_property(desc="coupling strength (relative speed difference)",
                unit="%",
                tex_str=r"$\Delta v/v$",
                expression=r"$\Delta v/v=(v_f-v_m)/v_f$",
                label="piezoelectric coupling")
    def Dvv(self, material):
        return {
            "STquartz": 0.06e-2,
            'GaAs': 0.035e-2,
            'LiNbYZ': 2.4e-2,
            'LiNb128': 2.7e-2,
            'LiNbYZX': 0.8e-2
        }[material]

    K2 = SProperty().tag(desc="coupling strength",
                         unit="%",
                         tex_str=r"K$^2$",
                         expression=r"K$^2=2\Delta v/v$",
                         label="piezoelectric coupling")

    @K2.getter
    def _get_K2(self, Dvv):
        r"""Coupling strength. K$^2=2\Delta v/v$"""
        return Dvv * 2.0

    @K2.setter
    def _get_Dvv(self, K2):
        """other coupling strength. free speed minus metal speed all over free speed"""
        return K2 / 2.0

    @t_property(desc="speed of SAW on free surface",
                unit="m/s",
                expression=r"$v_f$",
                format_str=r"{0:.4g} m/s",
                label="free SAW speed")
    def vf(self, material):
        return {
            "STquartz": 3159.0,
            'GaAs': 2900.0,
            'LiNbYZ': 3488.0,
            'LiNb128': 3979.0,
            'LiNbYZX': 3770.0
        }[material]

    @t_property(desc="Capacitance of one finger pair per unit length",
                expression=r"$\epsilon_\infty=C_S$",
                label="SAW permittivity")
    def epsinf(self, material):
        return {
            "STquartz": 5.6 * eps0,
            'GaAs': 1.2e-10,
            'LiNbYZ': 46.0 * eps0,
            'LiNb128': 56.0 * eps0,
            'LiNbYZX': 46.0 * eps0
        }[material]

    ft = Enum("double", "single").tag(desc="finger type of IDT",
                                      label="Finger type")

    def _observe_ft(self, change):
        if change["type"] == "update":
            self.ft_mult = None
            self.Ct_mult = None

    def _default_ft(self):
        return "double"

    @t_property(desc=r"single : 1, double : 2",
                label="finger type multiplier",
                expression=r"$c_{ft}$")
    def ft_mult(self, ft):
        return {"double": 2.0, "single": 1.0}[ft]

    @t_property(dictify={
        "single": 1.0,
        "double": sqrt(2)
    },
                label="Capacitance multiplier",
                expression=r"$c_c$",
                desc=r"single : $1$, double : $\sqrt{2}$")
    def Ct_mult(self, ft):
        return get_tag(self, "Ct_mult", "dictify")[ft]

    f = Float().tag(desc="what frequency is being stimulated/measured",
                    unit="GHz",
                    label="Operating frequency",
                    expression=r"$f$")

    def _default_f(self):
        """default f is 1Hz off from f0"""
        return self.f0  #-1.0

    f0 = Float(5.0000001e9).tag(unit="GHz",
                                desc="Center frequency of IDT",
                                reference="",
                                expression=r"$f_0$",
                                label="Center frequency")

    lbda = SProperty().tag(unit="um",
                           desc="wavelength",
                           reference="",
                           label="wavelength",
                           expression=r"$\lambda=v_f/f$")

    @lbda.getter
    def _get_lbda(self, f, vf):
        """wavelength relationship to speed and frequency"""
        return vf / f

    @lbda.setter
    def _get_f(self, lbda, vf):
        """frequency relationship to speed and wavelength"""
        return vf / lbda

    lbda0 = SProperty().tag(unit="um",
                            desc="Center wavelength",
                            reference="",
                            label="center wavelength",
                            expression=r"$\lambda_0=v_f/f_0$")

    @lbda0.getter
    def _get_lbda0(self, f0, vf):
        return vf / f0

    @lbda0.setter
    def _get_f0(self, lbda0, vf):
        return vf / lbda0

    k = SProperty().tag(label="Wavenumber", expression=r"$k=2\pi/\lambda$")

    @k.getter
    def _get_k(self, lbda):
        return 2 * pi / lbda

    @k.setter
    def _get_lbda_get_k(self, k):
        return 2 * pi / k

    k0 = SProperty().tag(label="Center wavenumber",
                         expression=r"$k_0=2\pi/\lambda_0$")

    @k0.getter
    def _get_k0(self, lbda0):
        return 2 * pi / lbda0

    @k0.setter
    def _get_lbda0_get_k0(self, k0):
        return 2 * pi / k0

    eta = Float(0.5).tag(desc="metalization ratio",
                         label="metallization ratio",
                         expression=r"$\eta$")

    @log_func
    def _get_eta(self, a, g):
        """metalization ratio"""
        return a / (a + g)

    g = SProperty().tag(desc="gap between fingers",
                        unit="um",
                        label="finger gap",
                        expression=r"$g$")

    @g.getter
    def _get_g(self, a, eta):
        """gap given metalization and finger width
        eta=a/(a+g)
        => a=(a+g)*eta
        => (1-eta)*a=g*eta
        => g=a*(1/eta-1)"""
        return a * (1.0 / eta - 1.0)

    @g.setter
    def _get_a_get_g(self, g, eta):
        """finger width given gap and metalization ratio
        eta=a/(a+g)
        => a=(a+g)*eta
        => (1-eta)*a=g*eta
        => a=g*eta/(1-eta)"""
        return g * eta / (1.0 - eta)

    a = SProperty().tag(desc="width of fingers",
                        unit="um",
                        label="finger width",
                        expression=r"$a$")

    @a.getter
    def _get_a(self, eta, lbda0, ft_mult):
        """finger width from lbda0"""
        return eta * lbda0 / (2.0 * ft_mult)

    @a.setter
    def _get_lbda0_get_a(self, a, eta, ft_mult):
        return a / eta * 2.0 * ft_mult

    p = SProperty().tag(desc="periodicity",
                        unit="um",
                        label="finger periodicity",
                        expression=r"$p=a+g$")

    @p.getter
    def _get_p(self, a, g):
        """periodicity from a and g"""
        return a + g

    @p.setter
    def _get_lbda0_get_p(self, p, ft_mult):
        return 2 * ft_mult * p

    @private_property
    def fixed_freq(self):
        return linspace(self.fixed_freq_min, self.fixed_freq_max,
                        self.N_fixed).astype(float64)

    N_fixed = Int(10000)
    fixed_freq_max = Float()
    fixed_freq_min = Float(0.01)

    def _default_fixed_freq_max(self):
        return 200.0 * self.f0

    def _default_fixed_freq_min(self):
        return 0.0001  #*self.f0

    lgf1 = Typed(Legendre)  #.tag(sub=True)
    lgf2 = Typed(Legendre)  #.tag(sub=True)

    def _default_lgf1(self):
        return Legendre(x=-cos(pi * self.eta), Nmult=0)

    def _default_lgf2(self):
        return Legendre(x=cos(pi * self.eta),
                        v=self._get_m(f=self.fixed_freq_max))

    def _observe_eta(self, change):
        if change["type"] == "update":
            if self.fixed_update:
                self.fixed_reset()

    fixed_update = Bool(False).tag(
        desc=
        "if True, changing eta will trigger an update of fixed values (slow computation)"
    )

    #@log_callable()
    def fixed_reset(self):
        self.lgf1.Pv(0.0, -cos(pi * self.eta), 0)
        self.lgf2.Pv(self.fixed_freq_max / (2 * self.ft_mult * self.f0),
                     cos(pi * self.eta))
        self.get_member("fixed_freq").reset(self)
        self.get_member("fixed_alpha").reset(self)
        self.get_member("surface_x").reset(self)
        self.get_member("surface_charge").reset(self)
        self.get_member("surface_voltage").reset(self)

    @private_property
    def fixed_alpha(self):
        return self._get_alpha(f=self.fixed_freq)

    @private_property
    def fixed_m(self):
        return self._get_m(f=self.fixed_freq)

    @private_property
    def fixed_s(self):
        return self._get_s(f=self.fixed_freq)

    m = SProperty().tag(desc="integer number of wavelengths")

    @m.getter
    def _get_m(self, f, f0, ft_mult):
        fs = self._get_fs(f=f, f0=f0, ft_mult=ft_mult)
        if isinstance(f, float):
            return int(fs)
        return fs.astype(int64)

    s = SProperty()

    @s.getter
    def _get_s(self, f, f0, ft_mult):
        fs = self._get_fs(f=f, f0=f0, ft_mult=ft_mult)
        m = self._get_m(f=f, f0=f0, ft_mult=ft_mult)
        return fs - m

    fs = SProperty()

    @fs.getter
    def _get_fs(self, f, f0, ft_mult):
        return f / (2.0 * ft_mult * f0)

    alpha = SProperty().tag(desc="single : 1.694, double : 1.247",
                            label="mu multiplier",
                            expression=r"$\alpha$")

    @alpha.getter
    def _get_alpha(self, f, f0, ft_mult, eta, epsinf):
        m = self._get_m(f=f, f0=f0, ft_mult=ft_mult)
        s = self._get_s(f=f, f0=f0, ft_mult=ft_mult)
        return 2 * sin(pi * s) / self.lgf1.Pv(-s) * self.lgf2.Pv(m)

    alpha0 = SProperty()

    @alpha0.getter
    def _get_alpha0(self, f0, ft_mult, eta, epsinf):
        return self._get_alpha(f=f0,
                               f0=f0,
                               ft_mult=ft_mult,
                               eta=eta,
                               epsinf=epsinf)

    @private_property
    def surface_x(self):
        fs = self._get_fs(f=self.fixed_freq)
        df = 1.0 / (fs[1] - fs[0]) / 2.0  #*self.lbda0/2
        return linspace(-df / 2.0, df / 2.0, self.N_fixed)

    @private_property
    def surface_charge(self):
        return fft.fftshift(real(ifft(self.fixed_alpha * self.epsinf)))

    @private_property
    def surface_voltage(self):
        lbda = self._get_lbda(f=self.fixed_freq)
        kCs = self._get_k(lbda)  #*self.epsinf
        return fft.fftshift(real(fft.ifft(self.fixed_alpha /
                                          kCs))).astype(float64)

    @private_property
    def view_window(self):
        return SurfaceChargeView(agent=self)

    @private_property
    def plot_func_dict(self):
        return OrderedDict([
            ("legendre test", dict(code=self.lgf1.lgf_test_plot)),
            ("plot_alpha", dict(code=self.plot_alpha)),
            ("plot surface charge", dict(code=self.plot_surface_charge)),
            ("plot surface voltage", dict(code=self.plot_surface_voltage)),
        ])

    def plot_alpha(self, pl=None, **kwargs):
        if pl is None:
            pl = "alpha_" + self.name
        f, alpha = self.fixed_freq, self.fixed_alpha
        pl = line(f / self.f0,
                  alpha,
                  plotter=pl,
                  plot_name=self.name,
                  color="blue",
                  label=self.name,
                  **kwargs)
        pl.xlabel = "frequency/center frequency"
        pl.ylabel = "element factor"
        pl.set_ylim(-1.0, 2.0)
        return pl

    def plot_surface_charge(self, pl=None, **kwargs):
        if pl is None:
            pl = "surface_charge_" + self.name
        x, charge = self.surface_x, self.surface_charge
        pl = line(x,
                  charge,
                  plotter=pl,
                  plot_name=self.name,
                  color="blue",
                  label=self.name,
                  **kwargs)
        pl.xlabel = "x/center wavelength"
        pl.ylabel = "surface charge"
        #pl.set_ylim(-1.0, 2.0)
        return pl

    def plot_surface_voltage(self, pl=None, **kwargs):
        if pl is None:
            pl = "surface_voltage_" + self.name
        x, voltage = self.surface_x, self.surface_voltage
        pl = line(x,
                  voltage,
                  plotter=pl,
                  plot_name=self.name,
                  color="blue",
                  label=self.name,
                  **kwargs)
        pl.xlabel = "x/center wavelength"
        pl.ylabel = "surface voltage"
        #pl.set_ylim(-1.0, 2.0)
        return pl
Exemplo n.º 4
0
class IDT(Rho):
    """Theoretical description of IDT"""
    base_name = "IDT"

    Y0_type = Enum("formula", "center")
    df_type = Enum("formula", "center")
    mus_type = Enum("formula", "center")
    Ga_type = Enum("sinc", "giant atom", "full sum")
    Ba_type = Enum("hilbert", "formula")
    rs_type = Enum("formula", "constant")
    gate_type = Enum("constant", "capacitive", "transmission")
    #YL_type=Enum("constant", "inductor")
    magabs_type = Enum("S11", "S12", "S13", "S21", "S22", "S23", "S31", "S32",
                       "S33")
    S_type = Enum("simple", "simpleP", "RAM")

    Cc = Float(1e-15).tag(desc="coupling capacitance", unit="fF")

    def _default_Ga_type(self):
        return "giant atom"

    def _default_fixed_freq_max(self):
        return 20.0 * self.f0

    def _default_f(self):
        """default f is 0.01Hz off from f0"""
        return self.f0 - 0.01

    Np = Float(9).tag(desc="\# of finger pairs",
                      low=0.5,
                      expression=r"$N_p$",
                      label="\# of finger pairs")

    ef = Int(0).tag(desc="for edge effect compensation",
                    label="\# of extra fingers",
                    low=0)

    W = Float(25.0e-6).tag(desc="IDT width", unit="um", label="IDT width")

    Ct = SProperty().tag(unit="fF",
                         label="IDT capacitance",
                         expression=r"$C_t$",
                         desc="Total capacitance of IDT",
                         reference="Morgan page 16/145")

    @Ct.getter
    def _get_Ct(self, epsinf, Ct_mult, W, Np):
        """Morgan page 16, 145"""
        return Ct_mult * W * epsinf * Np

    @Ct.setter
    def _get_epsinf(self, Ct, Ct_mult, W, Np):
        """reversing capacitance to extract eps infinity"""
        return Ct / (Ct_mult * W * Np)

    Ga0_approx = SProperty().tag(
        desc="Conductance at center frequency",
        expression=
        r"$G_{a0} = c_{Ga0} \omega_0 \epsilon_\infty W N_p^2 \Delta v/v$",
        label="Center conductance")

    @Ga0_approx.getter
    def _get_Ga0_approx(self, f0, epsinf, ft, W, Dvv, Np):
        """Ga0 from morgan"""
        Ga0_mult = {"single": 2.872, "double": 3.111}[ft]
        return Ga0_mult * 2.0 * pi * f0 * epsinf * W * Dvv * (Np**2)

    X = SProperty().tag(label="relative frequency",
                        expression=r"$X=N_p \pi (f-f_0)/f_0$")

    @X.getter
    def _get_X(self, Np, f, f0):
        """standard normalized frequency dependence"""
        return Np * pi * (f - f0) / f0

    @log_func
    def sinc(self, f, f0, Np):
        X = Np * pi * (f - f0) / f0
        return sin(X) / X

    @log_func
    def sinc_sq_ls(self, f, f0, Np):
        X = Np * pi * (f - f0) / f0
        return -(sin(2.0 * X) - 2.0 * X) / (2.0 * X**2.0)

    @log_func
    def giant_atom(self, f, f0, Np):
        X = Np * pi * (f - f0) / f0
        return 1.0 / Np * sin(X) / sin(X / Np)

    @log_func
    def giant_atom_ls(self, f, f0, Np):
        X = Np * pi * (f - f0) / f0
        return (1.0 / Np)**2 * 2 * (Np * sin(2 * X / Np) -
                                    sin(2 * X)) / (2 * (1 - cos(2 * X / Np)))

    def hilbert_ls(self, cpl):
        return imag(hilbert(cpl))

    @log_func
    def df_corr(self, f, f0):
        return sqrt(2.0) * cos(pi * f / (4 * f0))

    mus = SProperty().tag(desc="Datta voltage coefficient",
                          expression=r"$\mu=j \alpha \Delta v/v$",
                          label="Voltage coeffecient (one finger)")

    @mus.getter
    def _get_mus(self, f, f0, ft_mult, eta, epsinf, Dvv):
        alpha = self._get_alpha(f=f,
                                f0=f0,
                                ft_mult=ft_mult,
                                eta=eta,
                                epsinf=epsinf)
        return 1.0j * alpha * Dvv

    mus0 = SProperty().tag(
        desc="Datta voltage coefficient",
        expression=r"$\mu_0=j \alpha_0 \Delta v/v$",
        label="Voltage coeffecient (center frequency, one finger)")

    @mus0.getter
    def _get_mus0(self, f0, ft_mult, eta, epsinf, Dvv):
        return self._get_mus(f=f0,
                             f0=f0,
                             ft_mult=ft_mult,
                             eta=eta,
                             epsinf=epsinf,
                             Dvv=Dvv)

    Y0 = SProperty().tag(
        desc="Datta's characteristic SAW impedance",
        expression=r"$Y_0=\pi f W \epsilon_\infty / (\Delta v/v)$",
        label="Characteristic impedance")

    @Y0.getter
    def _get_Y0(self, f, Dvv, epsinf, W):
        return pi * f * W * epsinf / Dvv

    Y00 = SProperty().tag(
        desc="Datta's characteristic SAW impedance",
        expression=r"$Y_0=\pi f_0 W \epsilon_\infty / (\Delta v/v)$",
        label="Characteristic impedance (center frequency)")

    @Y00.getter
    def _get_Y00(self, f0, Dvv, epsinf, W):
        return self._get_Y0(f=f0, Dvv=Dvv, epsinf=epsinf,
                            W=W)  #pi*f0*W*epsinf/Dvv

    Ga = SProperty().tag(desc="Ga adjusted for frequency f")

    @Ga.getter
    def _get_Ga(self, f, f0, ft_mult, eta, epsinf, Dvv, Np, W):
        if self.S_type == "RAM":
            return self.get_fix("Ga", f)

        if self.Y0_type == "center":
            Y0 = self._get_Y00(f0=f0, Dvv=Dvv, epsinf=epsinf, W=W)
        else:
            Y0 = self._get_Y0(f=f, Dvv=Dvv, epsinf=epsinf, W=W)

        if self.mus_type == "center":
            mus = self._get_mus0(f0=f0,
                                 ft_mult=ft_mult,
                                 eta=eta,
                                 epsinf=epsinf,
                                 Dvv=Dvv)
        else:
            mus = self._get_mus(f=f,
                                f0=f0,
                                ft_mult=ft_mult,
                                eta=eta,
                                epsinf=epsinf,
                                Dvv=Dvv)

        if self.df_type == "center" or self.ft == "single":
            df_corr = 1.0
        else:
            df_corr = self.df_corr(f=f, f0=f0)
        if self.ft == "double":
            df_corr *= sqrt(2.0)

        if self.Ga_type == "sinc":
            cpl_form = Np * self.sinc(f=f, f0=f0, Np=Np)
        elif self.Ga_type == "giant atom":
            cpl_form = Np * self.giant_atom(f=f, f0=f0, Np=Np)

        if self.Ga_type == "full sum":
            mu = mus * self._get_Asum(f=f, f0=f0, Np=Np)
        else:
            mu = mus * df_corr * cpl_form

        return 2.0 * Y0 * absolute(
            mu
        )**2  #+(2*self.Ct)*(2*pi)*(self.dephasing+self.dephasing_slope*f)/1.0

    Ga0 = SProperty().tag(desc="Ga (center frequency)")

    @Ga0.getter
    def _get_Ga0(self, f0, Np, W, Dvv, epsinf, eta, ft_mult):
        return self._get_Ga(f=f0 + 0.001,
                            f0=f0,
                            Np=Np,
                            W=W,
                            Dvv=Dvv,
                            epsinf=epsinf,
                            eta=eta,
                            ft_mult=ft_mult)

    @private_property
    def fixed_Ga(self):
        return self.fixed_P[1]
        #return self._get_Ga(f=self.fixed_freq)

    Ba = SProperty()

    @Ba.getter
    def _get_Ba(self, f, f0, ft_mult, eta, epsinf, W, Dvv, Np):
        if self.Ga_type == "full sum" or self.S_type == "RAM":
            return self.get_fix("Ba", f)
        if self.Ba_type == "formula":
            Ga0 = self._get_Ga0(f0=f0,
                                Np=Np,
                                W=W,
                                Dvv=Dvv,
                                epsinf=epsinf,
                                eta=eta,
                                ft_mult=ft_mult)
            if self.Ga_type == "sinc":
                return -Ga0 * self.sinc_sq_ls(
                    f=f, f0=f0, Np=Np)  #(sin(2.0*X)-2.0*X)/(2.0*X**2.0)
            if self.Ga_type == "giant atom":
                return -Ga0 * self.giant_atom_ls(
                    f=f, f0=f0, Np=Np
                )  #(1.0/Np)**2*2*(Np*sin(2*gX/Np)-sin(2*gX))/(2*(1-cos(2*gX/Np)))
        Ga = self._get_Ga(f=self.fixed_freq,
                          f0=f0,
                          Np=Np,
                          W=W,
                          Dvv=Dvv,
                          epsinf=epsinf,
                          eta=eta,
                          ft_mult=ft_mult)
        yp = -imag(hilbert(Ga))
        return interp(f, self.fixed_freq, yp)

    @private_property
    def fixed_Ba(self):
        return self.fixed_P[2]
        #return self._get_Ba(f=self.fixed_freq)

    @private_property
    def fixed_P(self):
        if self.S_type == "RAM":
            return self.fixed_RAM_P  #_get_RAM_P()
        return self._get_simple_P(f=self.fixed_freq)

    simple_P = SProperty().tag(sub=True)

    @simple_P.getter
    def _get_simple_P(self, f, f0, ft_mult, eta, epsinf, W, Dvv, Np, Ct, dL,
                      vf, L_IDT):
        Ga = self._get_Ga(f=f,
                          f0=f0,
                          Np=Np,
                          W=W,
                          Dvv=Dvv,
                          epsinf=epsinf,
                          eta=eta,
                          ft_mult=ft_mult)
        Ba = self._get_Ba(f=f,
                          f0=f0,
                          Np=Np,
                          W=W,
                          Dvv=Dvv,
                          epsinf=epsinf,
                          eta=eta,
                          ft_mult=ft_mult)
        w = 2 * pi * f
        k = 2 * pi * f / vf
        jkL = 1.0j * k * L_IDT
        P11 = P22 = 0.0
        P12 = P21 = exp(-jkL)
        P13 = P23 = 1.0j * sqrt(Ga / 2.0) * exp(-jkL / 2.0)
        P31 = P32 = -2.0 * P13
        P33 = Ga + 1.0j * Ba + 1.0j * w * Ct - 1.0j / w * dL
        return (P11, P12, P13, P21, P22, P23, P31, P32, P33), Ga, Ba

    coupling = SProperty().tag(desc="""Coupling adjusted by sinc sq""",
                               unit="GHz",
                               expression=r"$\Gamma(f)/2 \pi$",
                               label="full qubit coupling")

    @coupling.getter
    def _get_coupling(self, f, f0, ft_mult, eta, epsinf, Dvv, Ct_mult, Np, W):
        if self.gate_type == "constant":
            Ga = self._get_Ga(f=f,
                              f0=f0,
                              ft_mult=ft_mult,
                              eta=eta,
                              epsinf=epsinf,
                              Dvv=Dvv,
                              Np=Np,
                              W=W)
            Ct = self._get_Ct(epsinf=epsinf, Ct_mult=Ct_mult, W=W, Np=Np)
            return Ga / (2 * Ct) / (
                2 * pi)  #+(self.dephasing+self.dephasing_slope*f)/1.0
        return self.get_fix("coupling", f=f)

    Lamb_shift = SProperty().tag(desc="""Lamb shift""",
                                 unit="GHz",
                                 expression=r"$B_a/\omega C$",
                                 label="Lamb shift")

    @Lamb_shift.getter
    def _get_Lamb_shift(self, f, f0, ft_mult, eta, epsinf, W, Dvv, Np,
                        Ct_mult):
        """returns Lamb shift"""
        if self.gate_type == "constant":
            Ba = self._get_Ba(f=f,
                              f0=f0,
                              Np=Np,
                              W=W,
                              Dvv=Dvv,
                              epsinf=epsinf,
                              eta=eta,
                              ft_mult=ft_mult)
            Ct = self._get_Ct(epsinf=epsinf, Ct_mult=Ct_mult, W=W, Np=Np)
            return -Ba / (2 * Ct) / (2 * pi)
        return self.get_fix("Lamb_shift", f=f)

    Ga0_mult = SProperty().tag(
        desc="single: $2.87=1.694^2$, double: $3.11=(1.247 \sqrt{2})^2$",
        expression=r"$c_{Ga}(f)$",
        label=r"$G_a$ multiplier")

    @Ga0_mult.getter
    def _get_Ga0_mult(self, f0, Np, W, ft_mult, eta, epsinf, Dvv):
        Ga0 = self._get_Ga0(f0=f0,
                            Np=Np,
                            W=W,
                            epsinf=epsinf,
                            eta=eta,
                            ft_mult=ft_mult)
        return Ga0 / (2.0 * pi * f0 * W * epsinf * Dvv * Np**2)

    max_coupling = SProperty().tag(desc="""Coupling at IDT center frequency""",
                                   unit="GHz",
                                   label="Coupling at center frequency",
                                   tex_str=r"$\gamma_{f0}$")

    @max_coupling.getter
    def _get_max_coupling(self, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W):
        return self._get_coupling(f=f0 + 0.001,
                                  f0=f0,
                                  ft_mult=ft_mult,
                                  eta=eta,
                                  epsinf=epsinf,
                                  Ct_mult=Ct_mult,
                                  Dvv=Dvv,
                                  Np=Np,
                                  W=W)

    max_coupling_approx = SProperty().tag(
        unit="GHz",
        label="Qubit coupling ($f$) (no sinc)",
        expression=r"$\Gamma/2\pi \approx c_g(f) f_0 K^2 N_p$",
        desc="frequency dependent")

    @max_coupling_approx.getter
    def _get_max_coupling_approx(self, f0, K2, Np, ft):
        cpl_mult = {"single": 0.71775, "double": 0.54995}[ft]
        return cpl_mult * f0 * K2 * Np

    def fixed_reset(self):
        """resets fixed properties in proper order"""
        super(IDT, self).fixed_reset()
        self.get_member("fixed_P").reset(self)
        self.get_member("fixed_RAM_P").reset(self)
        self.get_member("fixed_X").reset(self)
        self.get_member("fixed_Asum").reset(self)
        self.get_member("fixed_Ga").reset(self)
        self.get_member("fixed_Ba").reset(self)
        self.get_member("fixed_coupling").reset(self)
        self.get_member("fixed_Lamb_shift").reset(self)
        self.get_member("fixed_S").reset(self)

    @private_property
    def fixed_X(self):
        return self._get_X(f=self.fixed_freq)

    @private_property
    def fixed_w(self):
        return 2.0 * pi * self.fixed_freq

    def get_fix(self, name, f):
        return interp(f, self.fixed_freq, getattr(self, "fixed_" + name))

    @private_property
    def fixed_coupling(self):
        if self.gate_type == "constant":
            return self.fixed_Ga / (2 * self.Ct) / (2 * pi)
        return absolute([fp[0] for fp in self.fit_params]) * 1e9

    @private_property
    def fixed_Lamb_shift(self):
        if self.gate_type == "constant":
            return -self.fixed_Ba / (2.0 * self.Ct) / (2.0 * pi)
        return self.fixed_freq - array([fp[1] for fp in self.fit_params]) * 1e9

    dloss1 = Float(0.0)
    dloss2 = Float(0.0)

    #propagation_loss=SProperty()
    #@propagation_loss.getter
    #def _get_propagation_loss(self, f, f0, dloss1, dloss2):
    #    return exp(-f/f0*dloss1-dloss2*(f/f0)**2)

    @t_property(sub=True)
    def polarity(self, Np, ft):
        if ft == "single":
            return arange(int(Np)) + 0.5
        return array(sqze(zip(arange(Np) + 0.5, arange(Np) + 0.75)))

    @t_property(sub=True)
    def g_arr(self, polarity):
        return ones(len(polarity))

    @log_func
    def _get_Asum(self, f, f0, Np, dloss1, dloss2, g_arr, polarity):
        return 1.0 / Np * array([
            sum([
                g_arr[i] * exp(2.0j * pi * frq / f0 * n -
                               frq / f0 * dloss1 * n - n * dloss2 *
                               (frq / f0)**2) for i, n in enumerate(polarity)
            ]) for frq in f
        ])

    @private_property
    def fixed_Asum(self):
        return self._get_Asum(f=self.fixed_freq)

    dL = Float(0.0)
    YL = Complex(1.0 / 50.0)
    YS = Complex(1.0 / 50.0)
    Cground = Float().tag(unit="fF")

    @private_property
    def fixed_S(self):
        if self.S_type == "simple":
            return self._get_simple_S(f=self.fixed_freq)
        P = self.fixed_P[0]
        return self.PtoS(*P, YL=self.YL)

    simple_S = SProperty().tag(sub=True)

    @simple_S.getter
    def _get_simple_S(self, f, f0, ft_mult, eta, epsinf, W, Dvv, Np, Ct, YL,
                      dL, vf, L_IDT, Cc, YS, Cground):
        Ga = self._get_Ga(f=f,
                          f0=f0,
                          Np=Np,
                          W=W,
                          Dvv=Dvv,
                          epsinf=epsinf,
                          eta=eta,
                          ft_mult=ft_mult)
        Ba = self._get_Ba(f=f,
                          f0=f0,
                          Np=Np,
                          W=W,
                          Dvv=Dvv,
                          epsinf=epsinf,
                          eta=eta,
                          ft_mult=ft_mult)
        w = 2 * pi * f
        GL = real(YL)
        k = 2 * pi * f / vf
        jkL = 1.0j * k * L_IDT
        P33plusYL = Ga + 1.0j * Ba + 1.0j * w * Ct - 1.0j / w * dL + YL
        S11 = S22 = -Ga / P33plusYL * exp(-jkL)
        S12 = S21 = exp(-jkL) + S11
        if self.gate_type == "capacitive":
            Zatom = -1.0j / (w * Cc) + 1 / P33plusYL
            Zeff = 1.0 / (1.0j * w * Cground + 1.0 / Zatom)
            ZS = 1 / YS
            S33 = (Zatom - ZS) / (Zatom + ZS)
            S13 = S23 = S32 = S31 = (1.0 + S33) / 2.0
        elif self.gate_type == "transmission":
            Zatom = -1.0j / (w * Cc) + 1 / P33plusYL
            ZS = 1 / YS
            Zeff = ZS * Zatom / (Zatom + ZS)
            S33 = (Zeff - ZS) / (Zeff + ZS)
            S13 = S23 = S32 = S31 = (1.0 + S33) / 2.0
        else:
            S13 = S23 = S32 = S31 = 1.0j * sqrt(
                2.0 * Ga * GL) / P33plusYL * exp(-jkL / 2.0)
            S33 = (YL - Ga + 1.0j * Ba + 1.0j * w * Ct -
                   1.0j / w * dL) / P33plusYL
        return (S11, S12, S13, S21, S22, S23, S31, S32, S33)

    def PtoS(self, P11, P12, P13, P21, P22, P23, P31, P32, P33, YL=1 / 50.0):
        YLplusP33 = YL + P33
        sqrtYL = sqrt(YL)
        S11 = P11 - P13 * P31 / YLplusP33
        S12 = P12 - P13 * P32 / YLplusP33
        S13 = 2.0 * sqrtYL * P13 / YLplusP33
        S21 = P21 - P23 * P31 / YLplusP33
        S22 = P22 - P23 * P32 / YLplusP33
        S23 = -P31 * sqrtYL * P23 / YLplusP33
        S31 = -P31 * sqrtYL / YLplusP33
        S32 = -P32 * sqrtYL / YL + P33
        S33 = (YL - P33) / YLplusP33
        return (S11, S12, S13, S21, S22, S23, S31, S32, S33)

    rs = Complex()

    def _get_rs(self, f):
        h = 30e-9
        lbda = self._get_lbda(f=f)
        rs = (-1.7 / 100 - 0.24 * h / lbda) * 1.0j
        return array([r if absolute(r) < 0.9 else 0.9j for r in rs])

        #if absolute(rs)>=1.0:
        #    return 0.9999j
        #return rs

    ts = SProperty()

    @ts.getter
    def _get_ts(self, rs):
        return sqrt(1.0 - absolute(rs)**2)

    Gs = SProperty().tag(
        desc="Inglebrinsten's approximation of $\Gamma_S$ (Morgan)",
        expression=r"$\Gamma_S \approx (\Delta v/v)/\epsilon_\infty$")

    @Gs.getter
    def _get_Gs(self, Dvv, epsinf):
        return Dvv / epsinf

    L_IDT = SProperty().tag(desc="length of IDT",
                            unit="um",
                            expression=r"$L_{IDT}=N_{IDT}p$",
                            label="IDT length")

    @L_IDT.getter
    def _get_L_IDT(self, N_IDT, p):
        return N_IDT * p

    N_IDT = SProperty().tag(desc="total number of IDT fingers",
                            label="Total IDT fingers",
                            expression=r"$N_{IDT}=2 c_{ft} N_p$")

    @N_IDT.getter
    def _get_N_IDT(self, ft_mult, Np):
        return 2 * ft_mult * Np  #+ft_mult*(Np+1)

    def _get_RAM_P_one_f(self, f, p, N_IDT, L_IDT, f0, alpha, rs, Y0, dloss1,
                         dloss2, W, Np, ft, vf, Dvv, epsinf):
        #k=2*pi*f/vf#-1.0j*(f/f0*dloss1+dloss2*(f/f0)**2) 0.19 f/1e9 + 0.88 (f/1e9)**2 dB/us*1e6/3488 *log(10.0)/20.0
        k = 2 * pi * f / vf - 1.0j * (
            dloss1 * f / 1e9 + dloss2 *
            (f / 1e9)**2) * 1e6 / 3488 * log(10.0) / 20.0
        ts = sqrt(1.0 - absolute(rs)**2)
        A = 1.0 / ts * matrix([[exp(-1.0j * k * p), rs],
                               [-rs, exp(1.0j * k * p)]])  #.astype(complex128)
        AN = A**int(N_IDT)
        AN11, AN12, AN21, AN22 = AN[0, 0], AN[0, 1], AN[1, 0], AN[1, 1]
        P11 = -AN21 / AN22
        P21 = AN11 - AN12 * AN21 / AN22
        P12 = 1.0 / AN22
        P22 = AN12 / AN22
        D = -1.0j * alpha * Dvv * sqrt(Y0)
        B = matrix([(1.0 - rs / ts + 1.0 / ts) * exp(-1.0j * k * p / 2.0),
                    (1.0 + rs / ts + 1.0 / ts) * exp(1.0j * k * p / 2.0)])
        I = eye(2)
        if ft == "single":
            P32_base = (inv(I - A**2) * (I - A**(2 * int(Np)))) * matrix([
                [0], [1.0 / AN[1, 1] * exp(1.0j * k * (L_IDT - p) / 2.0)]
            ])  #geometric series
        else:
            P32_base = (
                (I + A) * inv(I - A**4) * (I - A**(4 * int(Np)))) * matrix([[
                    0
                ], [1.0 / AN[1, 1] * exp(1.0j * k * (L_IDT - 2.0 * p) / 2.0)]])
        P31 = P32 = D * (B * P32_base)
        P13 = P23 = -P31 / 2.0
        return (P11, P12, P13, P21, P22, P23, P31, P32)

    @private_property
    def fixed_RAM_P(self):
        if self.Y0_type == "center":
            Y0 = self.Y00
        else:
            Y0 = self._get_Y0(f=self.fixed_freq)
        if self.mus_type == "center":
            alpha = self.alpha0
        else:
            alpha = self._get_alpha(f=self.fixed_freq)
        if self.rs_type == "constant":
            rs = self.rs
        else:
            rs = self._get_rs(f=self.fixed_freq)
        return self._get_RAM_P(frq=self.fixed_freq, alpha=alpha, Y0=Y0, rs=rs)


#    @private_property
#    def fixed_Y0(self):
#        return self._get_Y0(f=self.fixed_freq)
#
#    @private_property
#    def fixed_rs(self):
#        return self._get_rs(f=self.fixed_freq)

    @log_func
    def _get_RAM_P(self, frq, f0, alpha, rs, Y0, dloss1, dloss2, W, Np, ft, vf,
                   Dvv, epsinf):
        if Y0 is None:
            Y0 = pi * f0 * W * epsinf / Dvv

        Ct_mult = {"single": 1.0, "double": sqrt(2)}[ft]
        Ct = Ct_mult * W * epsinf * Np

        ft_mult = {"double": 2.0, "single": 1.0}[ft]
        lbda0 = vf / f0
        p = lbda0 / (2 * ft_mult)
        N_IDT = 2 * ft_mult * Np
        L_IDT = Np * lbda0

        #print alpha, rs, Y0, f0, dloss1, dloss2, W, Np, ft, vf, Dvv, epsinf, L_IDT, N_IDT
        if isinstance(alpha, float):
            alpha = ones(len(frq)) * alpha
        if isinstance(rs, complex):
            rs = ones(len(frq)) * rs
        if isinstance(Y0, float):
            Y0 = ones(len(frq)) * Y0

        print "start P"
        P = [
            self._get_RAM_P_one_f(f=f,
                                  Dvv=Dvv,
                                  epsinf=epsinf,
                                  W=W,
                                  vf=vf,
                                  rs=rs[i],
                                  Y0=Y0[i],
                                  p=p,
                                  N_IDT=N_IDT,
                                  alpha=alpha[i],
                                  ft=ft,
                                  Np=Np,
                                  f0=f0,
                                  dloss1=dloss1,
                                  dloss2=dloss2,
                                  L_IDT=L_IDT) for i, f in enumerate(frq)
        ]
        print "P_done"

        (P11, P12, P13, P21, P22, P23, P31,
         P32) = [squeeze(P_ele) for P_ele in zip(*P)]
        print "P_done 2"
        Ga = 2.0 * absolute(P13)**2
        Ba = -imag(hilbert(Ga))
        P33 = Ga + 1.0j * Ba + 2.0j * pi * frq * Ct
        return (P11, P12, P13, P21, P22, P23, P31, P32, P33), Ga, Ba, Ct

    @private_property
    def view_window(self):
        return IDTView(agent=self)
Exemplo n.º 5
0
class IDT_S_Matrix(IDT):
    S11 = SProperty()

    @S11.getter
    def _get_S11(self, f):
        return self.get_fix("S11", f)

    @private_property
    def fixed_S11(self):
        return self.fixed_S[0]

    S12 = SProperty()

    @S12.getter
    def _get_S12(self, f):
        return self.get_fix("S12", f)

    @private_property
    def fixed_S12(self):
        return self.fixed_S[1]

    S13 = SProperty()

    @S13.getter
    def _get_S13(self, f):
        return self.get_fix("S13", f)

    @private_property
    def fixed_S13(self):
        return self.fixed_S[2]

    S21 = SProperty()

    @S21.getter
    def _get_S21(self, f):
        return self.get_fix("S21", f)

    @private_property
    def fixed_S21(self):
        return self.fixed_S[3]

    S22 = SProperty()

    @S22.getter
    def _get_S22(self, f):
        return self.get_fix("S22", f)

    @private_property
    def fixed_S22(self):
        return self.fixed_S[4]

    S23 = SProperty()

    @S23.getter
    def _get_S23(self, f):
        return self.get_fix("S23", f)

    @private_property
    def fixed_S23(self):
        return self.fixed_S[5]

    S31 = SProperty()

    @S31.getter
    def _get_S31(self, f):
        return self.get_fix("S31", f)

    @private_property
    def fixed_S31(self):
        return self.fixed_S[6]

    S32 = SProperty()

    @S32.getter
    def _get_S32(self, f):
        return self.get_fix("S32", f)

    @private_property
    def fixed_S32(self):
        return self.fixed_S[7]

    S33 = SProperty()

    @S33.getter
    def _get_S33(self, f):
        return self.get_fix("S33", f)

    @private_property
    def fixed_S33(self):
        return self.fixed_S[8]
Exemplo n.º 6
0
class QDT(IDT, Sat_Qubit):
    base_name = "QDT"

    @private_property
    def view_window(self):
        return QDTView(agent=self)

    fq0 = SProperty().tag(desc="center frequency of oscillator")

    @fq0.getter
    def _get_fq0(self, f, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W):
        ls = self._get_Lamb_shift(f=f,
                                  f0=f0,
                                  ft_mult=ft_mult,
                                  eta=eta,
                                  epsinf=epsinf,
                                  W=W,
                                  Dvv=Dvv,
                                  Np=Np,
                                  Ct_mult=Ct_mult)
        return sqrt(f * (f - 2.0 * ls))

    @fq0.setter
    def _get_Ej_get_fq0(self, fq0, Ec):
        return (h * fq0) ^ 2 / (8.0 * Ec)

    fFWHM = SProperty().tag(
        desc="center frequency of oscillator plus half width")

    @fFWHM.getter
    def _get_fFWHM(self, f, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W,
                   dephasing, dephasing_slope):
        ls = self._get_Lamb_shift(f=f,
                                  f0=f0,
                                  ft_mult=ft_mult,
                                  eta=eta,
                                  epsinf=epsinf,
                                  W=W,
                                  Dvv=Dvv,
                                  Np=Np,
                                  Ct_mult=Ct_mult)
        gamma = self._get_coupling(f=f,
                                   f0=f0,
                                   ft_mult=ft_mult,
                                   eta=eta,
                                   epsinf=epsinf,
                                   W=W,
                                   Dvv=Dvv,
                                   Np=Np,
                                   Ct_mult=Ct_mult)
        fplus = sqrt(f * (f - 2.0 * ls + 2.0 * gamma))
        fminus = sqrt(f * (f - 2.0 * ls - 2.0 * gamma))
        return fplus, fminus, fplus - fminus + dephasing + dephasing_slope * f

    fluxfq0 = SProperty().tag(desc="center frequency of oscillator as voltage")

    @fluxfq0.getter
    def _get_fluxfq0(self, f, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W,
                     Ct, Ejmax):
        fq0 = self._get_fq0(f=f,
                            f0=f0,
                            ft_mult=ft_mult,
                            eta=eta,
                            epsinf=epsinf,
                            Ct_mult=Ct_mult,
                            Dvv=Dvv,
                            Np=Np,
                            W=W)
        return self._get_flux_from_fq(fq=fq0, Ct=Ct, Ejmax=Ejmax)

    fluxfFWHM = SProperty().tag(desc="FWHM of oscillator")

    @fluxfFWHM.getter
    def _get_fluxfFWHM(self, f, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W,
                       Ct, Ejmax):
        fplus, fminus, fwhm = self._get_fFWHM(f=f,
                                              f0=f0,
                                              ft_mult=ft_mult,
                                              eta=eta,
                                              epsinf=epsinf,
                                              Ct_mult=Ct_mult,
                                              Dvv=Dvv,
                                              Np=Np,
                                              W=W)
        Vminus = self._get_flux_from_fq(fq=fplus, Ct=Ct, Ejmax=Ejmax)
        Vplus = self._get_flux_from_fq(fq=fminus, Ct=Ct, Ejmax=Ejmax)
        return Vplus, Vminus, Vplus - Vminus

    Vfq0 = SProperty().tag(desc="center frequency of oscillator as voltage")

    @Vfq0.getter
    def _get_Vfq0(self, f, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W, Ct,
                  Ejmax, offset, flux_factor):
        fq0 = self._get_fq0(f=f,
                            f0=f0,
                            ft_mult=ft_mult,
                            eta=eta,
                            epsinf=epsinf,
                            Ct_mult=Ct_mult,
                            Dvv=Dvv,
                            Np=Np,
                            W=W)
        return self._get_voltage_from_flux_par(fq=fq0,
                                               Ct=Ct,
                                               Ejmax=Ejmax,
                                               offset=offset,
                                               flux_factor=flux_factor)

    VfFWHM = SProperty().tag(desc="FWHM of oscillator")

    @VfFWHM.getter
    def _get_VfFWHM(self, f, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W, Ct,
                    Ejmax, offset, flux_factor):
        fplus, fminus, fwhm = self._get_fFWHM(f=f,
                                              f0=f0,
                                              ft_mult=ft_mult,
                                              eta=eta,
                                              epsinf=epsinf,
                                              Ct_mult=Ct_mult,
                                              Dvv=Dvv,
                                              Np=Np,
                                              W=W)
        Vminus = self._get_voltage_from_flux_par(fq=fplus,
                                                 Ct=Ct,
                                                 Ejmax=Ejmax,
                                                 offset=offset,
                                                 flux_factor=flux_factor)
        Vplus = self._get_voltage_from_flux_par(fq=fminus,
                                                Ct=Ct,
                                                Ejmax=Ejmax,
                                                offset=offset,
                                                flux_factor=flux_factor)
        return Vplus, Vminus, Vplus - Vminus

    Vfq0_many = SProperty().tag(sub=True)

    @Vfq0_many.getter
    def _get_Vfq0_many(self, f, f0, ft_mult, eta, epsinf, Ct_mult, Dvv, Np, W,
                       Ct, Ejmax, offset, flux_factor):
        fq0 = self._get_fq0(f=f,
                            f0=f0,
                            ft_mult=ft_mult,
                            eta=eta,
                            epsinf=epsinf,
                            Ct_mult=Ct_mult,
                            Dvv=Dvv,
                            Np=Np,
                            W=W)
        return self._get_voltage_from_flux_par_many(fq=fq0,
                                                    Ct=Ct,
                                                    Ejmax=Ejmax,
                                                    offset=offset,
                                                    flux_factor=flux_factor)

#    GL=Float(1.0)
#    simple_S_qdt=SProperty().tag(sub=True)
#    @simple_S_qdt.getter
#    def _get_simple_S_qdt(self, f, f0, ft_mult, eta, epsinf, Ct_mult, K2, Np, Ct, L, dL, vf, L_IDT, GL):
#        Ga=self._get_Ga(f=f, f0=f0, ft_mult=ft_mult, eta=eta, epsinf=epsinf, Ct_mult=Ct_mult, K2=K2, Np=Np)
#        Ba=self._get_Ba(f=f, f0=f0, ft_mult=ft_mult, eta=eta, epsinf=epsinf, Ct_mult=Ct_mult, K2=K2, Np=Np)
#        w=2*pi*f
#        YL=-1.0j/(w*L)
#
#        k=2*pi*f/vf
#        jkL=1.0j*k*L_IDT
#        P33plusYL=Ga+1.0j*Ba+1.0j*w*Ct-1.0j/w*dL+YL
#        S11=S22=-Ga/P33plusYL*exp(-jkL)
#        S12=S21=exp(-jkL)+S11
#        S13=S23=S32=S31=1.0j*sqrt(2.0*Ga*GL)/P33plusYL*exp(-jkL/2.0)
#        S33=(YL-Ga+1.0j*Ba+1.0j*w*Ct-1.0j/w*dL)/P33plusYL
#        return (S11, S12, S13,
#                S21, S22, S23,
#                S31, S32, S33)

    @private_property
    def fixed_fq(self):
        return linspace(self.fixed_fq_min, self.fixed_fq_max,
                        self.N_fixed_fq).astype(float64)

    N_fixed_fq = Int(500)
    fixed_fq_max = Float()
    fixed_fq_min = Float(0.01)

    def _default_fixed_freq_max(self):
        return 2.0 * self.f0

    def _default_fixed_fq_max(self):
        return 2.0 * self.f0

    def _default_fixed_fq_min(self):
        return 0.0001  #*self.f0

    def _default_N_fixed(self):
        return 400

    calc_p_guess = Bool(False)
    fitter = Typed(LorentzianFitter, ())  #fit.gamma=0.05

    flux_indices = List()

    def _default_flux_indices(self):
        return [range(len(self.fixed_fq))]

    @private_property
    def flat_flux_indices(self):
        return [n for ind in self.flux_indices for n in ind]

    fit_indices = List()  #.tag(private=True)

    def _default_fit_indices(self):
        return [range(len(self.fixed_freq))]

    @private_property
    def flat_indices(self):
        return [n for ind in self.fit_indices for n in ind]

    @private_property
    def MagAbs(self):
        #(S11, S12, S13,
        # S21, S22, S23,
        # S31, S32, S33)=self.fixed_S

        magind = {
            "S11": 0,
            "S12": 1,
            "S13": 2,
            "S21": 3,
            "S22": 4,
            "S23": 5,
            "S31": 6,
            "S32": 7,
            "S33": 8
        }[self.magabs_type]
        magcom = self.fixed_S[:, magind, :]
        #magcom={"S11" : S11, "S12" : S12, "S13" : S13,
        #        "S21" : S21, "S22" : S22, "S23" : S23,
        #        "S31" : S31, "S32" : S32, "S33" : S33}[self.magabs_type]
        return absolute(magcom)
        #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

    @private_property
    def fit_params(self):
        MagAbsSq = (self.MagAbs**2).transpose()
        if self.fitter.fit_params is None:
            self.fitter.full_fit(x=self.fixed_fq[self.flat_flux_indices] / 1e9,
                                 y=MagAbsSq,
                                 indices=self.flat_indices,
                                 gamma=self.fitter.gamma)
            if self.calc_p_guess:
                self.fitter.make_p_guess(
                    self.fixed_fq[self.flat_flux_indices] / 1e9,
                    y=MagAbsSq,
                    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.fixed_fq[self.flat_flux_indices] / 1e9,
                self.fit_params)).transpose()

#    YL=SProperty()
#    @YL.getter
#    def _get_YL(self, w, L):
#        if self.YL_type=="constant":
#            return self.YL
#        elif self.YL_type=="inductor":
#            return -1.0j/(w*L)

    @private_property
    def fixed_S(self):
        w = 2 * pi * self.fixed_freq
        L_arr = self._get_L(fq=self.fixed_fq)
        if self.S_type == "simple":
            return array([
                self._get_simple_S(f=self.fixed_freq, YL=-1.0j / (w * L))
                for L in L_arr
            ])
        P = self.fixed_P[0]
        #return self.PtoS(*P, YL=self.YL)
        return array([self.PtoS(*P, YL=-1.0j / (w * L)) for L in L_arr])

    lamb_shifted_transmon_energy = SProperty()

    @lamb_shifted_transmon_energy.getter
    def _get_lamb_shifted_transmon_energy(self, Ej, Ec, m, f0, ft_mult, eta,
                                          epsinf, W, Dvv, Np, Ct_mult):
        Em = -Ej + sqrt(8.0 * Ej * Ec) * (m + 0.5) - (Ec / 12.0) * (
            6.0 * m**2 + 6.0 * m + 3.0)
        if m == 0:
            return Em
        Emm1 = -Ej + sqrt(
            8.0 * Ej * Ec) * (m - 1 + 0.5) - (Ec / 12.0) * (6.0 *
                                                            (m - 1)**2 + 6.0 *
                                                            (m - 1) + 3.0)
        fq = (Em - Emm1) / h
        fls = self._get_Lamb_shift(f=fq,
                                   f0=f0,
                                   ft_mult=ft_mult,
                                   eta=eta,
                                   epsinf=epsinf,
                                   W=W,
                                   Dvv=Dvv,
                                   Np=Np,
                                   Ct_mult=Ct_mult)
        return Em + h * fls

    lamb_shifted_transmon_energy_levels = SProperty()

    @lamb_shifted_transmon_energy_levels.getter
    def _get_lamb_shifted_transmon_energy_levels(self, Ej, f0, ft_mult, eta,
                                                 epsinf, W, Dvv, Np, Ct_mult,
                                                 Ec, n_energy):
        return [
            self._get_lamb_shifted_transmon_energy(Ej=Ej,
                                                   Ec=Ec,
                                                   m=m,
                                                   f0=f0,
                                                   ft_mult=ft_mult,
                                                   eta=eta,
                                                   epsinf=epsinf,
                                                   W=W,
                                                   Dvv=Dvv,
                                                   Np=Np,
                                                   Ct_mult=Ct_mult)
            for m in range(n_energy)
        ]
Exemplo n.º 7
0
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
Exemplo n.º 8
0
class IDT(Agent):
    """Theoretical description of IDT"""
    base_name = "IDT"
    #main_params=["ft", "f0", "lbda0", "a", "g", "eta", "Np", "ef", "W", "Ct",
    #            "material", "Dvv", "K2", "vf", "epsinf"]

    material = Enum('LiNbYZ', 'GaAs', 'LiNb128', 'LiNbYZX', 'STquartz')

    def _default_material(self):
        return 'LiNbYZ'

    def _observe_material(self, change):
        if change["type"] == "update":
            self.Dvv = None
            self.vf = None
            self.epsinf = None

    @t_property(desc="coupling strength",
                unit="%",
                tex_str=r"$\Delta v/v$",
                expression=r"$(v_f-v_m))/v_f$")
    def Dvv(self, material):
        return {
            "STquartz": 0.06e-2,
            'GaAs': 0.035e-2,
            'LiNbYZ': 2.4e-2,
            'LiNb128': 2.7e-2,
            'LiNbYZX': 0.8e-2
        }[material]

    @t_property(desc="speed of SAW on free surface",
                unit="m/s",
                tex_str=r"$v_f$",
                format_str=r"{0:.4g} m/s")
    def vf(self, material):
        return {
            "STquartz": 3159.0,
            'GaAs': 2900.0,
            'LiNbYZ': 3488.0,
            'LiNb128': 3979.0,
            'LiNbYZX': 3770.0
        }[material]

    @t_property(desc="Capacitance of single finger pair per unit length",
                tex_str=r"$\epsilon_\infty$")
    def epsinf(self, material):
        return {
            "STquartz": 5.6 * eps0,
            'GaAs': 1.2e-10,
            'LiNbYZ': 46.0 * eps0,
            'LiNb128': 56.0 * eps0,
            'LiNbYZX': 46.0 * eps0
        }[material]

    ft = Enum("double", "single").tag(desc="finger type of IDT",
                                      label="Finger type",
                                      show_value=False)

    def _observe_ft(self, change):
        if change["type"] == "update":
            self.ft_mult = None
            self.Ga0_mult = None
            self.Ct_mult = None
            self.mu_mult = None

    def _default_ft(self):
        return "double"

    @t_property(desc="multiplier based on finger type")
    def ft_mult(self, ft):
        return {"double": 2.0, "single": 1.0}[ft]

    @t_property(dictify={
        "single": 1.694**2,
        "double": (1.247 * sqrt(2))**2
    })  #{"single":2.87, "double":3.11}
    def Ga0_mult(self, ft):
        return get_tag(self, "Ga0_mult", "dictify")[ft]

    @t_property(dictify={"single": 1.0, "double": sqrt(2)})
    def Ct_mult(self, ft):
        return get_tag(self, "Ct_mult", "dictify")[ft]

    @t_property()
    def mu_mult(self, ft):
        return {"single": 1.694, "double": 1.247}[ft]

    #coupling_mult_dict={"single" : 0.71775, "double" : 0.54995}

    couple_mult = SProperty()

    @couple_mult.getter
    def _get_couple_mult(self, Ga0_mult, Ct_mult):
        return Ga0_mult / (4 * Ct_mult)

    f = Float(4.4e9).tag(
        desc=
        "Operating frequency, e.g. what frequency is being stimulated/measured"
    )

    Np = Float(9).tag(desc="\# of finger pairs",
                      low=0.5,
                      tex_str=r"$N_p$",
                      label="\# of finger pairs")

    ef = Int(0).tag(desc="for edge effect compensation",
                    label="\# of extra fingers",
                    low=0)

    W = Float(25.0e-6).tag(desc="height of finger.", unit="um")

    eta = Float(0.5).tag(desc="metalization ratio")

    f0 = Float(5.0e9).tag(unit="GHz",
                          desc="Center frequency of IDT",
                          reference="",
                          tex_str=r"$f_0$",
                          label="Center frequency")

    C = SProperty().tag(unit="fF",
                        desc="Total capacitance of IDT",
                        reference="Morgan page 16/145")

    @C.getter
    def _get_C(self, epsinf, Ct_mult, W, Np):
        """Morgan page 16, 145"""
        return Ct_mult * W * epsinf * Np

    @C.setter
    def _get_epsinf(self, C, Ct_mult, W, Np):
        """reversing capacitance to extract eps infinity"""
        return C / (Ct_mult * W * Np)

    @log_func
    def _get_eta(self, a, g):
        """metalization ratio"""
        return a / (a + g)

    K2 = SProperty().tag(desc="coupling strength",
                         unit="%",
                         tex_str=r"K$^2$",
                         expression=r"K$^2=2\Delta v/v$")

    @K2.getter
    def _get_K2(self, Dvv):
        r"""Coupling strength. K$^2=2\Delta v/v$"""
        return Dvv * 2.0

    @K2.setter
    def _get_Dvv(self, K2):
        """other couplign strength. free speed minus metal speed all over free speed"""
        return K2 / 2.0

    Ga0 = SProperty().tag(desc="Conductance at center frequency")

    @Ga0.getter
    def _get_Ga0(self, Ga0_mult, f0, epsinf, W, Dvv, Np):
        """Ga0 from morgan"""
        return Ga0_mult * 2 * pi * f0 * epsinf * W * Dvv * (Np**2)

    Ga0div2C = SProperty()

    @Ga0div2C.getter
    def _get_Ga0div2C(self, couple_mult, f0, K2, Np):
        """coupling at center frequency, in Hz (2 pi removed)"""
        return couple_mult * f0 * K2 * Np

    X = SProperty()

    @X.getter
    def _get_X(self, Np, f, f0):
        """standard frequency dependence"""
        return Np * pi * (f - f0) / f0

    coupling = SProperty().tag(desc="""Coupling adjusted by sinc sq""",
                               unit="GHz",
                               tex_str=r"$G_f$")

    @coupling.getter
    def _get_coupling(self, f, couple_mult, f0, K2, Np):
        gamma0 = self._get_Ga0div2C(couple_mult=couple_mult,
                                    f0=f0,
                                    K2=K2,
                                    Np=Np)
        gX = self._get_X(Np=Np, f=f, f0=f0)
        #return gamma0*(1.0/Np*sin(gX)/sin(gX/Np))**2
        return gamma0 * (sqrt(2.0) * cos(pi * f / (4 * f0)) * sin(pi * f /
                                                                  (2 * f0)) *
                         (1.0 / Np) * sin(gX) / sin(gX / Np))**2

        #return gamma0*(sqrt(2)*cos(pi*f/(4*f0))*(1.0/Np)*sin(gX)/sin(gX/Np))**2
        #return gamma0*(sin(gX)/gX)**2.0

    max_coupling = SProperty().tag(desc="""Coupling at IDT center frequency""",
                                   unit="GHz",
                                   label="Coupling at center frequency",
                                   tex_str=r"$\gamma_{f0}$")

    @max_coupling.getter
    def _get_max_coupling(self, couple_mult, f0, K2, Np):
        return self._get_Ga0div2C(couple_mult=couple_mult, f0=f0, K2=K2, Np=Np)

    Lamb_shift = SProperty().tag(desc="""Lamb shift""",
                                 unit="GHz",
                                 tex_str=r"$G_f$")

    @Lamb_shift.getter
    def _get_Lamb_shift(self, f, couple_mult, f0, K2, Np):
        """returns Lamb shift"""
        frq = linspace(-5e9, 15e9, 20000)
        yp = imag(
            hilbert(
                self._get_coupling(f=frq,
                                   couple_mult=couple_mult,
                                   f0=f0,
                                   K2=K2,
                                   Np=Np)))
        #self.get_member("Lamb_shift_hilbert").reset(self)
        return interp(f, frq, yp)  #*self.Lamb_shift_hilbert)
        #gamma0=self._get_Ga0div2C(couple_mult=couple_mult, f0=f0, K2=K2, Np=Np)
        #gX=self._get_X(Np=Np, f=f, f0=f0)
        #return gamma0*(1.0/Np)**2*2*(Np*sin(2*gX/Np)-sin(2*gX))/(2*(1-cos(2*gX/Np)))
        #return -gamma0*(sin(2.0*gX)-2.0*gX)/(2.0*gX**2.0)

    #Lamb_shift_hilbert=SProperty()
    @private_property
    def Lamb_shift_hilbert(self):
        frq = linspace(-5e9, 15e9, 20000)
        return frq, imag(hilbert(self._get_coupling(f=frq)))

    ZL = Float(50.0)
    GL = Float(1 / 50.0)

    S11 = SProperty()

    @S11.getter
    def _get_S11(self, f, couple_mult, f0, K2, Np, C, ZL):
        Ga = self._get_Ga(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        Ba = self._get_Ba(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        w = 2 * pi * f
        return Ga / (Ga + 1j * Ba + 1j * w * C + 1.0 / ZL)

    S13 = SProperty()

    @S13.getter
    def _get_S13(self, f, couple_mult, f0, K2, Np, C, ZL, GL):
        Ga = self._get_Ga(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        Ba = self._get_Ba(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        w = 2 * pi * f
        return 1j * sqrt(2 * Ga * GL) / (Ga + 1j * Ba + 1j * w * C + 1.0 / ZL)

    Ga = SProperty().tag(desc="Ga adjusted for frequency f")

    @Ga.getter
    def _get_Ga(self, f, couple_mult, f0, K2, Np, C):
        return self._get_coupling(
            f=f, couple_mult=couple_mult, f0=f0, K2=K2, Np=Np) * 2 * C * 2 * pi

    Ba = SProperty()

    @Ba.getter
    def _get_Ba(self, f, couple_mult, f0, K2, Np, C):
        return -self._get_Lamb_shift(
            f=f, couple_mult=couple_mult, f0=f0, K2=K2, Np=Np) * 2 * C * 2 * pi

    lbda = SProperty()

    @lbda.getter
    def _get_lbda(self, f, vf):
        """wavelength relationship to speed and frequency"""
        return vf / f

    @lbda.setter
    def _get_f(self, lbda, vf):
        """frequency relationship to speed and wavelength"""
        return vf / lbda

    lbda0 = SProperty().tag(unit="um", desc="Center wavelength", reference="")

    @lbda0.getter
    def _get_lbda0(self, f0, vf):
        return self._get_lbda(f=f0, vf=vf)

    @lbda0.setter
    def _get_f0(self, lbda0, vf):
        return self._get_f(lbda=lbda0, vf=vf)

    g = SProperty().tag(
        desc=
        "gap between fingers (um). about 0.096 for double fingers at 4.5 GHz",
        unit="um")

    @g.getter
    def _get_g(self, a, eta):
        """gap given metalization and finger width
        eta=a/(a+g)
        => a=(a+g)*eta
        => (1-eta)*a=g*eta
        => g=a*(1/eta-1)"""
        return a * (1.0 / eta - 1.0)

    @g.setter
    def _get_a_get_(self, g, eta):
        """finger width given gap and metalization ratio
        eta=a/(a+g)
        => a=(a+g)*eta
        => (1-eta)*a=g*eta
        => a=g*eta/(1-eta)"""
        return g * eta / (1.0 - eta)

    a = SProperty().tag(desc="width of fingers", unit="um")

    @a.getter
    def _get_a(self, eta, lbda0, ft_mult):
        """finger width from lbda0"""
        return eta * lbda0 / (2.0 * ft_mult)

    @a.setter
    def _get_lbda0_get_(self, a, eta, ft_mult):
        return a / eta * 2.0 * ft_mult

    @private_property
    def view_window2(self):
        from enaml import imports
        with imports():
            from taref.saw.idt_e import IDT_View
        return IDT_View(idt=self)
Exemplo n.º 9
0
class QDT(IDT, Qubit):
    base_name = "QDT"

    #lamb_shifted_transmon_energy=SProperty()
    #@lamb_shifted_transmon_energy.getter
    def _get_lamb_shifted_transmon_energy(self, Ej, Ec, m, couple_mult, f0, K2,
                                          Np):
        Em = -Ej + sqrt(8.0 * Ej * Ec) * (m + 0.5) - (Ec / 12.0) * (
            6.0 * m**2 + 6.0 * m + 3.0)
        if m == 0:
            return Em
        Emm1 = -Ej + sqrt(
            8.0 * Ej * Ec) * (m - 1 + 0.5) - (Ec / 12.0) * (6.0 *
                                                            (m - 1)**2 + 6.0 *
                                                            (m - 1) + 3.0)
        fq = (Em - Emm1) / h
        fls = self._get_Lamb_shift(f=fq,
                                   couple_mult=couple_mult,
                                   f0=f0,
                                   K2=K2,
                                   Np=Np)
        return Em + h * fls

    lamb_shifted_transmon_energy_levels = SProperty()

    @lamb_shifted_transmon_energy_levels.getter
    def _get_lamb_shifted_transmon_energy_levels(self, Ej, couple_mult, f0, K2,
                                                 Np, Ec, n_energy):
        return [
            self._get_lamb_shifted_transmon_energy(Ej=Ej,
                                                   Ec=Ec,
                                                   m=m,
                                                   couple_mult=couple_mult,
                                                   f0=f0,
                                                   K2=K2,
                                                   Np=Np)
            for m in range(n_energy)
        ]

    lamb_shifted_fq = SProperty().tag(desc="""Operating frequency of qubit""",
                                      unit="GHz")

    @lamb_shifted_fq.getter
    def _get_lamb_shifted_fq(self, Ej, Ec):
        E0, E1 = self._get_lamb_shifted_transmon_energy_levels(Ej=Ej,
                                                               Ec=Ec,
                                                               n_energy=2)
        return (E1 - E0) / h

    lamb_shifted_anharm = SProperty().tag(desc="absolute anharmonicity",
                                          unit="hGHz")

    @lamb_shifted_anharm.getter
    def _get_lamb_shifted_anharm(self, Ej, Ec):
        E0, E1, E2 = self._get_lamb_shifted_transmon_energy_levels(Ej=Ej,
                                                                   Ec=Ec,
                                                                   n_energy=3)
        return (E2 - E1) / h - (E1 - E0) / h

    lamb_shifted_fq2 = SProperty().tag(desc="""20 over 2 freq""", unit="GHz")

    @lamb_shifted_fq2.getter
    def _get_lamb_shifted_fq2(self, Ej, Ec):
        E0, E1, E2 = self._get_lamb_shifted_transmon_energy_levels(Ej=Ej,
                                                                   Ec=Ec,
                                                                   n_energy=3)
        return (E2 - E0) / h / 2.0

    #@s_property(desc="shunt capacitance of QDT", unit="fF")
    #def Cq(self, C):
    #    return C

    #@Cq.setter
    #def _get_C_get_Cq(self, Cq):
    #    return Cq

    ls_flux_parabola = SProperty()

    @ls_flux_parabola.getter
    def _get_ls_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_lamb_shifted_fq(Ej=qEj, Ec=Ec)  #, fq2(qEj, Ec)

    ls_f = SProperty().tag(sub=True)

    @ls_f.getter
    def _get_ls_f(self, f, couple_mult, f0, K2, Np):
        try:
            return array([
                sqrt(qf * (qf - 2 * self._get_Lamb_shift(
                    f=qf, couple_mult=couple_mult, f0=f0, K2=K2, Np=Np)))
                for qf in f
            ])
        except TypeError:
            return sqrt(f * (f - 2 * self._get_Lamb_shift(
                f=f, couple_mult=couple_mult, f0=f0, K2=K2, Np=Np)))

    ls_voltage_from_flux_par = SProperty().tag(sub=True)

    @ls_voltage_from_flux_par.getter
    def _get_ls_voltage_from_flux_par(self, freq_arr, C, Ejmax, offset,
                                      flux_factor, couple_mult, f0, K2, Np):
        ls_f = self._get_ls_f(freq_arr=freq_arr,
                              couple_mult=couple_mult,
                              f0=f0,
                              K2=K2,
                              Np=Np)
        Ec = self._get_Ec(C=C)
        Ej = self._get_Ej_get_fq(fq=ls_f, Ec=Ec)
        flux_d_flux0 = self._get_flux_over_flux0_get_Ej(Ej=Ej, Ejmax=Ejmax)
        return ls_f / 1e9, self._get_voltage(flux_over_flux0=flux_d_flux0,
                                             offset=offset,
                                             flux_factor=flux_factor)

    ls_voltage_from_flux_par_many = SProperty().tag(sub=True)

    @ls_voltage_from_flux_par_many.getter
    def _get_ls_voltage_from_flux_par_many(self, f, C, Ejmax, offset,
                                           flux_factor, couple_mult, f0, K2,
                                           Np):
        ls_f = self._get_ls_f(f=f,
                              couple_mult=couple_mult,
                              f0=f0,
                              K2=K2,
                              Np=Np)
        Ec = self._get_Ec(C=C)
        Ej = self._get_Ej_get_fq(fq=ls_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)

    S11 = SProperty()

    @S11.getter
    def _get_S11(self, f, couple_mult, f0, K2, Np, C, L):
        Ga = self._get_Ga(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        Ba = self._get_Ba(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        w = 2 * pi * f
        try:
            return Ga / (Ga + 1j * Ba + 1j * w * C + 1.0 / (1j * w * L))
        except ValueError:
            return array([
                Ga / (Ga + 1j * Ba + 1j * w * C + 1.0 / (1j * w * qL))
                for qL in L
            ])

    S13 = SProperty()

    @S13.getter
    def _get_S13(self, f, couple_mult, f0, K2, Np, C, L, GL):
        Ga = self._get_Ga(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        Ba = self._get_Ba(f=f,
                          couple_mult=couple_mult,
                          f0=f0,
                          K2=K2,
                          Np=Np,
                          C=C)
        w = 2 * pi * f
        return 1j * sqrt(2.0 * Ga * GL) / (Ga + 1j * Ba + 1j * w * C + 1.0 /
                                           (1j * w * L))
Exemplo n.º 10
0
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