Coverage for jaxquantum/devices/superconducting/ats.py: 83%
58 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-27 22:28 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-27 22:28 +0000
1"""ATS."""
3from flax import struct
4from jax import config
6import jax.numpy as jnp
8from jaxquantum.devices.superconducting.flux_base import FluxDevice
9from jaxquantum.core.operators import identity, destroy, create
10from jaxquantum.core.qarray import cosm, sinm
12config.update("jax_enable_x64", True)
15@struct.dataclass
16class ATS(FluxDevice):
17 """
18 ATS Device.
19 """
21 def common_ops(self):
22 """Written in the linear basis."""
23 ops = {}
25 N = self.N_pre_diag
26 ops["id"] = identity(N)
27 ops["a"] = destroy(N)
28 ops["a_dag"] = create(N)
29 ops["phi"] = self.phi_zpf() * (ops["a"] + ops["a_dag"])
30 ops["n"] = 1j * self.n_zpf() * (ops["a_dag"] - ops["a"])
31 return ops
33 def phi_zpf(self):
34 """Return Phase ZPF."""
35 return (2 * self.params["Ec"] / self.params["El"]) ** (0.25)
37 def n_zpf(self):
38 """Return Charge ZPF."""
39 return (self.params["El"] / (32 * self.params["Ec"])) ** (0.25)
41 def get_linear_frequency(self):
42 """Get frequency of linear terms."""
43 return jnp.sqrt(8 * self.params["El"] * self.params["Ec"])
45 def get_H_linear(self):
46 """Return linear terms in H."""
47 w = self.get_linear_frequency()
48 ops = self.linear_ops
49 return w * (
50 ops["a_dag"] @ ops["a"]
51 + 0.5 * ops["id"]
52 )
54 @staticmethod
55 def get_H_nonlinear_static(phi_op, Ej, dEj, Ej2, phi_sum, phi_delta):
56 cos_phi_op = cosm(phi_op)
57 sin_phi_op = sinm(phi_op)
59 cos_2phi_op = cos_phi_op @ cos_phi_op - sin_phi_op @ sin_phi_op
60 sin_2phi_op = 2 * cos_phi_op @ sin_phi_op
62 H_nl_Ej = (
63 -2
64 * Ej
65 * (
66 cos_phi_op * jnp.cos(2 * jnp.pi * phi_delta)
67 - sin_phi_op * jnp.sin(2 * jnp.pi * phi_delta)
68 )
69 * jnp.cos(2 * jnp.pi * phi_sum)
70 )
71 H_nl_dEj = (
72 2
73 * dEj
74 * (
75 sin_phi_op * jnp.cos(2 * jnp.pi * phi_delta)
76 + cos_phi_op * jnp.sin(2 * jnp.pi * phi_delta)
77 )
78 * jnp.sin(2 * jnp.pi * phi_sum)
79 )
80 H_nl_Ej2 = (
81 2
82 * Ej2
83 * (
84 cos_2phi_op * jnp.cos(2 * 2 * jnp.pi * phi_delta)
85 - sin_2phi_op * jnp.sin(2 * 2 * jnp.pi * phi_delta)
86 )
87 * jnp.cos(2 * 2 * jnp.pi * phi_sum)
88 )
90 H_nl = H_nl_Ej + H_nl_dEj + H_nl_Ej2
92 # id_op = jqt.identity_like(phi_op)
93 # phi_delta_ext_op = self.params["phi_delta_ext"] * id_op
94 # H_nl_old = - 2 * Ej * jqt.cosm(phi_op + 2 * jnp.pi * phi_delta_ext_op) * jnp.cos(2 * jnp.pi * self.params["phi_sum_ext"])
95 # H_nl_old += 2 * dEj * jqt.sinm(phi_op + 2 * jnp.pi * phi_delta_ext_op) * jnp.sin(2 * jnp.pi * self.params["phi_sum_ext"])
96 # H_nl_old += 2 * Ej2 * jqt.cosm(2*phi_op + 2 * 2 * jnp.pi * phi_delta_ext_op) * jnp.cos(2 * 2 * jnp.pi * self.params["phi_sum_ext"])
98 return H_nl
100 def get_H_nonlinear(self, phi_op):
101 """Return nonlinear terms in H."""
103 Ej = self.params["Ej"]
104 dEj = self.params["dEj"]
105 Ej2 = self.params["Ej2"]
107 phi_sum = self.params["phi_sum_ext"]
108 phi_delta = self.params["phi_delta_ext"]
110 return ATS.get_H_nonlinear_static(phi_op, Ej, dEj, Ej2, phi_sum, phi_delta)
112 def get_H_full(self):
113 """Return full H in linear basis."""
114 ops = self.linear_ops
115 linear = self.get_linear_frequency() * (
116 ops["a_dag"] @ ops["a"] + 0.5 * ops["id"]
117 )
118 return linear + self.get_H_nonlinear(ops["phi"])
120 def potential(self, phi):
121 """Return potential energy for a given phi."""
123 phi_delta_ext = self.params["phi_delta_ext"]
124 phi_sum_ext = self.params["phi_sum_ext"]
126 V = 0.5 * self.params["El"] * (2 * jnp.pi * phi) ** 2
127 V += (
128 -2
129 * self.params["Ej"]
130 * jnp.cos(2 * jnp.pi * (phi + phi_delta_ext))
131 * jnp.cos(2 * jnp.pi * phi_sum_ext)
132 )
133 V += (
134 2
135 * self.params["dEj"]
136 * jnp.sin(2 * jnp.pi * (phi + phi_delta_ext))
137 * jnp.sin(2 * jnp.pi * phi_sum_ext)
138 )
139 V += (
140 2
141 * self.params["Ej2"]
142 * jnp.cos(2 * 2 * jnp.pi * (phi + phi_delta_ext))
143 * jnp.cos(2 * 2 * jnp.pi * phi_sum_ext)
144 )
146 return V