Coverage for qpdk / cells / junction.py: 100%
57 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 17:50 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 17:50 +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(tags=("junctions",))
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.
47 Returns:
48 The junction wire component.
49 """
50 c = Component()
52 # Widest straight section with patch
53 wide_straight_ref = c << straight(
54 length=wide_straight_length, cross_section=cross_section_wide
55 )
57 # Add the tapered transition section
58 taper_ref = c << gf.c.taper_cross_section(
59 length=taper_length,
60 cross_section1=cross_section_wide,
61 cross_section2=cross_section_narrow,
62 linear=True,
63 )
65 # Narrow straight section with overlap
66 narrow_straight_ref = c << straight(
67 length=narrow_straight_length, cross_section=cross_section_narrow
68 )
70 # Connect all
71 taper_ref.connect("o1", wide_straight_ref.ports["o2"])
72 narrow_straight_ref.connect("o1", taper_ref.ports["o2"])
74 # Add patch to wide section
75 if layer_patch:
76 patch = c << gf.components.rectangle(
77 size=size_patch,
78 layer=layer_patch,
79 centered=True,
80 )
81 # Overlap with one fourth offset to one side
82 patch.move((
83 wide_straight_ref.dbbox().p1.x - size_patch[0] / 4,
84 wide_straight_ref.y,
85 ))
87 # Add port at wide end
88 c.add_port(
89 port=wide_straight_ref.ports["o1"], name="o1", cross_section=cross_section_wide
90 )
91 # Add port at narrow end
92 c.add_port(
93 port=narrow_straight_ref.ports["o2"],
94 name="o2",
95 cross_section=cross_section_narrow,
96 )
98 return c
101@gf.cell(tags=("junctions",))
102def josephson_junction(
103 junction_overlap_displacement: float = 1.8,
104 wide_straight_length: float = 8.3,
105 narrow_straight_length: float = 0.5,
106 taper_length: float = 4.7,
107 cross_section_wide: CrossSectionSpec = josephson_junction_cross_section_wide,
108 cross_section_narrow: CrossSectionSpec = josephson_junction_cross_section_narrow,
109 layer_patch: LayerSpec = LAYER.JJ_PATCH,
110 size_patch: tuple[float, float] = (1.5, 1.0),
111) -> Component:
112 r"""Creates a single Josephson junction component.
114 A Josephson junction consists of two superconducting electrodes separated
115 by a thin insulating barrier allowing tunnelling.
117 .. svgbob::
119 right_wide
120 ┌───┐ ╷ overlap
121 │ │━━━━────╶╶╷╶╶
122 └───┘ ╷
123 │
124 │
125 ┃
126 ┃
127 ┌───┐
128 │ │
129 └───┘
130 left_wide
132 Args:
133 junction_overlap_displacement: Displacement of the overlap region in µm.
134 Measured from the centers of the junction ports.
135 wide_straight_length: Length of the wide straight section in µm.
136 narrow_straight_length: Length of the narrow straight section in µm.
137 taper_length: Length of the taper section in µm.
138 cross_section_wide: Cross-section specification for the wide section.
139 cross_section_narrow: Cross-section specification for the narrow section.
140 layer_patch: Layer for the patch that creates the overlap region.
141 size_patch: Size of the patch that creates the overlap region.
143 Returns:
144 The Josephson junction component.
145 """
146 c = Component()
148 # Left wire
149 left_wire = c << single_josephson_junction_wire(
150 wide_straight_length=wide_straight_length,
151 narrow_straight_length=narrow_straight_length,
152 taper_length=taper_length,
153 cross_section_wide=cross_section_wide,
154 cross_section_narrow=cross_section_narrow,
155 layer_patch=layer_patch,
156 size_patch=size_patch,
157 )
159 # Right wire
160 right_wire = c << single_josephson_junction_wire(
161 wide_straight_length=wide_straight_length,
162 narrow_straight_length=narrow_straight_length,
163 taper_length=taper_length,
164 cross_section_wide=cross_section_wide,
165 cross_section_narrow=cross_section_narrow,
166 layer_patch=layer_patch,
167 size_patch=size_patch,
168 )
170 total_length = wide_straight_length + narrow_straight_length + taper_length
171 # Position left wire on top of right wire with rotation
172 left_wire.dcplx_trans = (
173 right_wire.ports["o2"].dcplx_trans
174 * DCplxTrans.R90
175 * DCplxTrans(
176 -total_length + junction_overlap_displacement,
177 0,
178 )
179 )
180 right_wire.dcplx_trans *= DCplxTrans(junction_overlap_displacement, 0)
182 # Add ports at wide ends
183 c.add_port(
184 name="left_wide",
185 port=left_wire.ports["o1"],
186 )
187 c.add_port(
188 name="right_wide",
189 port=right_wire.ports["o1"],
190 )
191 # One port at overlap
192 c.add_port(
193 name="overlap",
194 center=(
195 left_wire.ports["o2"].dcplx_trans
196 * DCplxTrans(-junction_overlap_displacement, 0)
197 ).disp.to_p(),
198 width=left_wire.ports["o2"].width,
199 orientation=left_wire.ports["o2"].orientation,
200 layer=left_wire.ports["o2"].layer,
201 port_type="placement",
202 )
204 return c
207@gf.cell(tags=("junctions",))
208def josephson_junction_long(**kwargs) -> Component:
209 """Josephson junction with wide_straight_length=12.
211 Returns:
212 The Josephson junction component with long wires.
213 """
214 return josephson_junction(wide_straight_length=12, **kwargs)
217@gf.cell(tags=("junctions",))
218def squid_junction_long(**kwargs) -> Component:
219 """SQUID junction with josephson_junction_long.
221 Returns:
222 The SQUID junction component with long wires.
223 """
224 return squid_junction(junction_spec=josephson_junction_long, **kwargs)
227@gf.cell(tags=("junctions",))
228def squid_junction(
229 junction_spec: ComponentSpec = josephson_junction,
230 loop_area: float = 4,
231) -> Component:
232 """Creates a SQUID (Superconducting Quantum Interference Device) junction component.
234 A SQUID consists of two Josephson junctions connected in parallel, forming a loop.
236 See :cite:`clarkeSQUIDHandbook2004` for details.
238 Args:
239 junction_spec: Component specification for the Josephson junction component.
240 loop_area: Area of the SQUID loop in µm².
241 This does not take into account the junction wire widths.
243 Returns:
244 The SQUID junction component.
245 """
246 c = Component()
248 junction_comp = gf.get_component(junction_spec)
250 left_junction = c << junction_comp
251 right_junction = c << junction_comp
253 # Form a cross by positioning overlaps on top of each other
254 right_junction.dcplx_trans = (
255 left_junction.ports["overlap"].dcplx_trans
256 * DCplxTrans.R90
257 * DCplxTrans(
258 -left_junction.xmax
259 + (left_junction.xmax - left_junction.ports["overlap"].x),
260 0,
261 )
262 )
264 # Start adding area by displacing junctions
265 displacement_xy = loop_area**0.5
266 right_junction.dcplx_trans *= DCplxTrans((displacement_xy,) * 2)
268 # Add ports from junctions with descriptive names
269 for junction_name, junction in [("left", left_junction), ("right", right_junction)]:
270 for port_side in ["left", "right"]:
271 port_name = f"{junction_name}_{port_side}_wide"
272 c.add_port(name=port_name, port=junction.ports[f"{port_side}_wide"])
274 # Overlaps and their center
275 c.add_port(
276 name="left_overlap",
277 port=left_junction.ports["overlap"],
278 port_type="placement",
279 )
280 c.add_port(
281 name="right_overlap",
282 port=right_junction.ports["overlap"],
283 port_type="placement",
284 )
285 c.add_port(
286 name="loop_center",
287 center=(
288 (
289 left_junction.ports["overlap"].dcplx_trans.disp
290 + right_junction.ports["overlap"].dcplx_trans.disp
291 )
292 / 2
293 ).to_p(),
294 layer=left_junction.ports["overlap"].layer,
295 width=left_junction.ports["overlap"].width,
296 port_type="placement",
297 )
298 return c
301if __name__ == "__main__":
302 show_components(josephson_junction, squid_junction)