Source code for qnngds.devices.htron

"""Heater cryotron devices `[1] <https://doi.org/10.1038/s41928-019-0300-8>`_, `[2] <https://doi.org/10.1103/PhysRevApplied.14.054011>`_."""

# can be removed in python 3.14, see https://peps.python.org/pep-0749/
from __future__ import annotations

import qnngds as qg
import phidl.geometry as pg

import numpy as np

from functools import partial

from qnngds.typing import LayerSpec, DeviceSpec
from qnngds import Device

from . import nanowire as nanowire


[docs]@qg.device def planar( wire_width: int | float = 0.3, gate_width: int | float = 0.1, channel_width: int | float = 0.2, gap: int | float = 0.02, gate_length: int | float = 0.01, channel_length: int | float = 0.01, layer: LayerSpec = (1, 0), ) -> Device: """Create a planar hTron. Args: wire_width (int or float): Width of routing wires in microns gate_width (int or float): Width of superconducting gate in microns channel_width (int or float): Width of superconducting channel in microns gap (int or float): Spacing between gate and channel in microns gate_length (int or float): Length of superconducting gate in microns channel_length (int or float): Length of superconducting channel in microns layer (LayerSpec): GDS layer specification Returns: (Device): a single planar hTron """ HTRON = Device("htron_planar") ports = [] for direction, width, length in ( (1, channel_width, channel_length), (-1, gate_width, gate_length), ): compass_size = (width, np.max((length - 4 * width, 0.1))) constr = HTRON << pg.compass(size=compass_size, layer=qg.get_layer(layer)) constr.center = [0, 0] constr.move([direction * (gap / 2 + width / 2), 0]) taper = qg.geometries.angled_taper(wire_width, width, 45, layer=layer) taper_lower = HTRON << taper taper_upper = HTRON << taper if direction < 0: taper_upper.mirror() else: taper_lower.mirror() taper_lower.connect(port=taper_lower.ports[1], destination=constr.ports["N"]) taper_upper.connect(port=taper_upper.ports[1], destination=constr.ports["S"]) ports.append(taper_lower.ports[2]) ports.append(taper_upper.ports[2]) for p, port in enumerate(ports): HTRON.add_port(name=p + 1, port=port) return HTRON
[docs]@qg.device def heater( heater_spec: DeviceSpec = nanowire.sharp( constr_width=0.5, wire_width=1, length=2, layer=(10, 0) ), pad_size: tuple[float, float] = (2, 2), pad_layer: LayerSpec = (20, 0), ) -> Device: """Create a heater with superconducting leads for use with hTrons. Args: heater_spec (DeviceSpec): spec for heater pad_size (tuple[float, float]): (width, height) of pad pad_layer (LayerSpec): layer specification for top pads Returns: (Device): a heater with pads """ HEATER = Device("heater") heater = qg.get_device(heater_spec) port = next(iter(heater.ports.values())) width = port.width layer = port.layer outline = (pad_size[1] - width) / 2 if outline < 0: raise ValueError( f"{pad_size=} and {heater_spec=} do not give enough space to " f"make a pad that overhangs the heater contacts" "Increase pad_size and/or decrease pad_outline" ) extended = qg.utilities.extend_ports( device=heater, port_names=heater.ports.keys(), extension=pg.straight( size=(width, pad_size[0] - outline), layer=qg.get_layer(layer) ), new_ports=False, ) HEATER << extended t_pad = pg.compass(size=pad_size, layer=qg.get_layer(pad_layer)) t_pads = [] for i in range(2): t_pads.append(HEATER << t_pad) for i in range(2): t_pads[i].connect( t_pads[i].ports["W"], heater.ports[i + 1], ) HEATERu = Device("heater") HEATERu << pg.union(HEATER, by_layer=True) dir_lut = {1: "W", 2: "N", 3: "E", 4: "S"} for n, t_pad in enumerate(t_pads): for i in range(3): HEATERu.add_port( name=3 * n + i + 1, port=t_pad.ports[dir_lut[i + 2]], layer=pad_layer ) return HEATERu
[docs]@qg.device def multilayer( rotation: float = 0, channel_spec: DeviceSpec = partial( nanowire.variable_length, constr_width=1, wire_width=2, length=4, symmetric=True, layer=(1, 0), ), gate_spec: DeviceSpec = heater, ) -> Device: """Create a multilayer hTron. Args: rotation (float): amount to rotate gate relative to channel. channel_spec (DeviceSpec): callable function that generates a Device for the channel nanowire gate_spec (DeviceSpec): callable function that generates a Device for the gate nanowire Returns: (Device): a multilayer hTron """ HTRON = Device("htron_multilayer") c = qg.get_device(channel_spec) g = qg.get_device(gate_spec) channel = HTRON << c gate = HTRON << g gate.rotate(rotation) gate.move(gate.center, channel.center) for p, port_name in enumerate(gate.ports): HTRON.add_port(name=f"g{p + 1}", port=gate.ports[port_name]) for p, port_name in enumerate(channel.ports): HTRON.add_port(name=f"c{p + 1}", port=channel.ports[port_name]) return HTRON