Coverage for qpdk / cells / junction.py: 100%
57 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 10:27 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 10:27 +0000
1"""Josephson junction components."""
3from __future__ import annotations
5import gdsfactory as gf
6from gdsfactory.component import Component
7from gdsfactory.typings import ComponentSpec, CrossSectionSpec, LayerSpec
8from klayout.db import DCplxTrans
10from qpdk.cells.waveguides import straight
11from qpdk.helper import show_components
12from qpdk.tech import (
13 LAYER,
14 josephson_junction_cross_section_narrow,
15 josephson_junction_cross_section_wide,
16)
19@gf.cell
20def single_josephson_junction_wire(
21 wide_straight_length: float = 8.3,
22 narrow_straight_length: float = 0.5,
23 taper_length: float = 4.7,
24 cross_section_wide: CrossSectionSpec = josephson_junction_cross_section_wide,
25 cross_section_narrow: CrossSectionSpec = josephson_junction_cross_section_narrow,
26 layer_patch: LayerSpec = LAYER.JJ_PATCH,
27 size_patch: tuple[float, float] = (1.5, 1.0),
28) -> Component:
29 r"""Creates a single wire to use in a Josephson junction.
31 .. svgbob::
33 ┌───┐
34 │o1 │━━━━────╶╶╶╶╶ o2
35 └───┘
36 wide narrow
38 Args:
39 wide_straight_length: Length of the wide straight section in µm.
40 narrow_straight_length: Length of the narrow straight section in µm.
41 taper_length: Length of the taper section in µm.
42 cross_section_wide: Cross-section specification for the wide section.
43 cross_section_narrow: Cross-section specification for the narrow section.
44 layer_patch: Layer for the patch that creates the overlap region.
45 size_patch: Size of the patch that creates the overlap region.
46 """
47 c = Component()
49 # Widest straight section with patch
50 wide_straight_ref = c << straight(
51 length=wide_straight_length, cross_section=cross_section_wide
52 )
54 # Add the tapered transition section
55 taper_ref = c << gf.c.taper_cross_section(
56 length=taper_length,
57 cross_section1=cross_section_wide,
58 cross_section2=cross_section_narrow,
59 linear=True,
60 )
62 # Narrow straight section with overlap
63 narrow_straight_ref = c << straight(
64 length=narrow_straight_length, cross_section=cross_section_narrow
65 )
67 # Connect all
68 taper_ref.connect("o1", wide_straight_ref.ports["o2"])
69 narrow_straight_ref.connect("o1", taper_ref.ports["o2"])
71 # Add patch to wide section
72 if layer_patch:
73 patch = c << gf.components.rectangle(
74 size=size_patch,
75 layer=layer_patch,
76 centered=True,
77 )
78 # Overlap with one fourth offset to one side
79 patch.move(
80 (wide_straight_ref.dbbox().p1.x - size_patch[0] / 4, wide_straight_ref.y)
81 )
83 # Add port at wide end
84 c.add_port(
85 port=wide_straight_ref.ports["o1"], name="o1", cross_section=cross_section_wide
86 )
87 # Add port at narrow end
88 c.add_port(
89 port=narrow_straight_ref.ports["o2"],
90 name="o2",
91 cross_section=cross_section_narrow,
92 )
94 return c
97@gf.cell
98def josephson_junction(
99 junction_overlap_displacement: float = 1.8,
100 wide_straight_length: float = 8.3,
101 narrow_straight_length: float = 0.5,
102 taper_length: float = 4.7,
103 cross_section_wide: CrossSectionSpec = josephson_junction_cross_section_wide,
104 cross_section_narrow: CrossSectionSpec = josephson_junction_cross_section_narrow,
105 layer_patch: LayerSpec = LAYER.JJ_PATCH,
106 size_patch: tuple[float, float] = (1.5, 1.0),
107) -> Component:
108 r"""Creates a single Josephson junction component.
110 A Josephson junction consists of two superconducting electrodes separated
111 by a thin insulating barrier allowing tunnelling.
113 .. svgbob::
115 right_wide
116 ┌───┐ ╷ overlap
117 │ │━━━━────╶╶╷╶╶
118 └───┘ ╷
119 │
120 │
121 ┃
122 ┃
123 ┌───┐
124 │ │
125 └───┘
126 left_wide
128 Args:
129 junction_overlap_displacement: Displacement of the overlap region in µm.
130 Measured from the centers of the junction ports.
131 wide_straight_length: Length of the wide straight section in µm.
132 narrow_straight_length: Length of the narrow straight section in µm.
133 taper_length: Length of the taper section in µm.
134 cross_section_wide: Cross-section specification for the wide section.
135 cross_section_narrow: Cross-section specification for the narrow section.
136 layer_patch: Layer for the patch that creates the overlap region.
137 size_patch: Size of the patch that creates the overlap region.
138 """
139 c = Component()
141 # Left wire
142 left_wire = c << single_josephson_junction_wire(
143 wide_straight_length=wide_straight_length,
144 narrow_straight_length=narrow_straight_length,
145 taper_length=taper_length,
146 cross_section_wide=cross_section_wide,
147 cross_section_narrow=cross_section_narrow,
148 layer_patch=layer_patch,
149 size_patch=size_patch,
150 )
152 # Right wire
153 right_wire = c << single_josephson_junction_wire(
154 wide_straight_length=wide_straight_length,
155 narrow_straight_length=narrow_straight_length,
156 taper_length=taper_length,
157 cross_section_wide=cross_section_wide,
158 cross_section_narrow=cross_section_narrow,
159 layer_patch=layer_patch,
160 size_patch=size_patch,
161 )
163 total_length = wide_straight_length + narrow_straight_length + taper_length
164 # Position left wire on top of right wire with rotation
165 left_wire.dcplx_trans = (
166 right_wire.ports["o2"].dcplx_trans
167 * DCplxTrans.R90
168 * DCplxTrans(
169 -total_length + junction_overlap_displacement,
170 0,
171 )
172 )
173 right_wire.dcplx_trans *= DCplxTrans(junction_overlap_displacement, 0)
175 # Add ports at wide ends
176 c.add_port(
177 name="left_wide",
178 port=left_wire.ports["o1"],
179 )
180 c.add_port(
181 name="right_wide",
182 port=right_wire.ports["o1"],
183 )
184 # One port at overlap
185 c.add_port(
186 name="overlap",
187 center=(
188 left_wire.ports["o2"].dcplx_trans
189 * DCplxTrans(-junction_overlap_displacement, 0)
190 ).disp.to_p(),
191 width=left_wire.ports["o2"].width,
192 orientation=left_wire.ports["o2"].orientation,
193 layer=left_wire.ports["o2"].layer,
194 port_type="placement",
195 )
197 return c
200@gf.cell
201def josephson_junction_long(**kwargs) -> Component:
202 """Josephson junction with wide_straight_length=12."""
203 return josephson_junction(wide_straight_length=12, **kwargs)
206@gf.cell
207def squid_junction_long(**kwargs) -> Component:
208 """SQUID junction with josephson_junction_long."""
209 return squid_junction(junction_spec=josephson_junction_long, **kwargs)
212@gf.cell
213def squid_junction(
214 junction_spec: ComponentSpec = josephson_junction,
215 loop_area: float = 4,
216) -> Component:
217 """Creates a SQUID (Superconducting Quantum Interference Device) junction component.
219 A SQUID consists of two Josephson junctions connected in parallel, forming a loop.
221 See :cite:`clarkeSQUIDHandbook2004` for details.
223 Args:
224 junction_spec: Component specification for the Josephson junction component.
225 loop_area: Area of the SQUID loop in µm².
226 This does not take into account the junction wire widths.
227 """
228 c = Component()
230 junction_comp = gf.get_component(junction_spec)
232 left_junction = c << junction_comp
233 right_junction = c << junction_comp
235 # Form a cross by positioning overlaps on top of each other
236 right_junction.dcplx_trans = (
237 left_junction.ports["overlap"].dcplx_trans
238 * DCplxTrans.R90
239 * DCplxTrans(
240 -left_junction.xmax
241 + (left_junction.xmax - left_junction.ports["overlap"].x),
242 0,
243 )
244 )
246 # Start adding area by displacing junctions
247 displacement_xy = loop_area**0.5
248 right_junction.dcplx_trans *= DCplxTrans((displacement_xy,) * 2)
250 # Add ports from junctions with descriptive names
251 for junction_name, junction in [("left", left_junction), ("right", right_junction)]:
252 for port_side in ["left", "right"]:
253 port_name = f"{junction_name}_{port_side}_wide"
254 c.add_port(name=port_name, port=junction.ports[f"{port_side}_wide"])
256 # Overlaps and their center
257 c.add_port(
258 name="left_overlap",
259 port=left_junction.ports["overlap"],
260 port_type="placement",
261 )
262 c.add_port(
263 name="right_overlap",
264 port=right_junction.ports["overlap"],
265 port_type="placement",
266 )
267 c.add_port(
268 name="loop_center",
269 center=(
270 (
271 left_junction.ports["overlap"].dcplx_trans.disp
272 + right_junction.ports["overlap"].dcplx_trans.disp
273 )
274 / 2
275 ).to_p(),
276 layer=left_junction.ports["overlap"].layer,
277 width=left_junction.ports["overlap"].width,
278 port_type="placement",
279 )
280 return c
283if __name__ == "__main__":
284 show_components(josephson_junction, squid_junction)