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

1"""ATS.""" 

2 

3from flax import struct 

4from jax import config 

5 

6import jax.numpy as jnp 

7 

8from jaxquantum.devices.superconducting.flux_base import FluxDevice 

9from jaxquantum.core.operators import identity, destroy, create 

10from jaxquantum.core.qarray import cosm, sinm 

11 

12config.update("jax_enable_x64", True) 

13 

14 

15@struct.dataclass 

16class ATS(FluxDevice): 

17 """ 

18 ATS Device. 

19 """ 

20 

21 def common_ops(self): 

22 """Written in the linear basis.""" 

23 ops = {} 

24 

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 

32 

33 def phi_zpf(self): 

34 """Return Phase ZPF.""" 

35 return (2 * self.params["Ec"] / self.params["El"]) ** (0.25) 

36 

37 def n_zpf(self): 

38 """Return Charge ZPF.""" 

39 return (self.params["El"] / (32 * self.params["Ec"])) ** (0.25) 

40 

41 def get_linear_frequency(self): 

42 """Get frequency of linear terms.""" 

43 return jnp.sqrt(8 * self.params["El"] * self.params["Ec"]) 

44 

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 ) 

53 

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) 

58 

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 

61 

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 ) 

89 

90 H_nl = H_nl_Ej + H_nl_dEj + H_nl_Ej2 

91 

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"]) 

97 

98 return H_nl 

99 

100 def get_H_nonlinear(self, phi_op): 

101 """Return nonlinear terms in H.""" 

102 

103 Ej = self.params["Ej"] 

104 dEj = self.params["dEj"] 

105 Ej2 = self.params["Ej2"] 

106 

107 phi_sum = self.params["phi_sum_ext"] 

108 phi_delta = self.params["phi_delta_ext"] 

109 

110 return ATS.get_H_nonlinear_static(phi_op, Ej, dEj, Ej2, phi_sum, phi_delta) 

111 

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"]) 

119 

120 def potential(self, phi): 

121 """Return potential energy for a given phi.""" 

122 

123 phi_delta_ext = self.params["phi_delta_ext"] 

124 phi_sum_ext = self.params["phi_sum_ext"] 

125 

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 ) 

145 

146 return V