{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Design rule checking\n", "\n", "A design that renders is not a design that works. Nothing in Quantum Metal\n", "stops you from routing a resonator straight through a feedline, from putting\n", "a launchpad past the chip edge, or from asking for a 90 um fillet on a 60 um\n", "segment. The picture looks plausible; the chip does not.\n", "\n", "`qiskit_metal.validation` is a design rule check (DRC) for that class of\n", "mistake. It reads the built qgeometry tables and reports **findings**:\n", "\n", "```python\n", "from qiskit_metal.validation import validate\n", "\n", "result = validate(design)\n", "print(result.report())\n", "```\n", "\n", "**What the default rules check**\n", "\n", "| Rule | Catches | Default | Source |\n", "|---|---|---|---|\n", "| `metal-overlap` | two components' metal overlapping on one layer -- a short | any overlap > 1 um^2 | -- |\n", "| `metal-spacing` | metal close enough that etch residue can bridge it | 2 um | GDSII-to-wafer R8 |\n", "| `cpw-gap` | CPW gap so narrow the interface participation ratio spikes | 3 um | GDSII-to-wafer R1 |\n", "| `chip-bounds` | geometry off the die, silently clipped downstream | -- | -- |\n", "| `short-segment` | a segment too short to host its own fillet arc | fillet radius | -- |\n", "| `qubit-clearance` | a CPW running close enough to a qubit pocket to couple | 3x CPW width | project heuristic |\n", "| `ground-continuity` | the ground plane split into disconnected regions | -- | GDSII-to-wafer R9 |\n", "\n", "Severity matters: **ERROR** is geometry that is wrong regardless of intent,\n", "**WARNING** is legal geometry that is probably unintended or spends a physical\n", "budget (loss, stray coupling). Only errors make a result falsy or raise.\n", "\n", "These are a starting point, not a foundry sign-off. Every threshold is a\n", "constructor argument -- see *Tuning the rules* below.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:11.698392Z", "iopub.status.busy": "2026-08-08T04:41:11.698134Z", "iopub.status.idle": "2026-08-08T04:41:11.703247Z", "shell.execute_reply": "2026-08-08T04:41:11.702582Z" } }, "outputs": [], "source": [ "# In Colab / Binder, uncomment to install Quantum Metal (lite, no Qt):\n", "# !pip install -q quantum-metal" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:11.705838Z", "iopub.status.busy": "2026-08-08T04:41:11.705585Z", "iopub.status.idle": "2026-08-08T04:41:12.870217Z", "shell.execute_reply": "2026-08-08T04:41:12.869658Z" } }, "outputs": [], "source": [ "import qiskit_metal as qm\n", "from qiskit_metal import Dict, designs\n", "from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket\n", "from qiskit_metal.qlibrary.terminations.launchpad_wb import LaunchpadWirebond\n", "from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround\n", "from qiskit_metal.qlibrary.tlines.pathfinder import RoutePathfinder\n", "from qiskit_metal.qlibrary.tlines.straight_path import RouteStraight\n", "from qiskit_metal.validation import validate\n", "\n", "\n", "def new_design():\n", " design = designs.DesignPlanar()\n", " design.overwrite_enabled = True\n", " design.chips.main.size.size_x = \"6mm\"\n", " design.chips.main.size.size_y = \"6mm\"\n", " return design\n", "\n", "\n", "def link(design, name, start, end, ori_start, ori_end, cls=RouteStraight, **options):\n", " \"\"\"A CPW between two fresh open terminations -- shorthand for this notebook.\"\"\"\n", " OpenToGround(\n", " design,\n", " f\"{name}_a\",\n", " options=dict(pos_x=start[0], pos_y=start[1], orientation=ori_start),\n", " )\n", " OpenToGround(\n", " design,\n", " f\"{name}_b\",\n", " options=dict(pos_x=end[0], pos_y=end[1], orientation=ori_end),\n", " )\n", " return cls(\n", " design,\n", " name,\n", " options=Dict(\n", " pin_inputs=Dict(\n", " start_pin=Dict(component=f\"{name}_a\", pin=\"open\"),\n", " end_pin=Dict(component=f\"{name}_b\", pin=\"open\"),\n", " ),\n", " **options,\n", " ),\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A design with one defect per rule\n", "\n", "Each block below is a mistake that is easy to make and hard to see. Read them\n", "now, then look at the plot and try to spot them before running the check." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:12.872157Z", "iopub.status.busy": "2026-08-08T04:41:12.872031Z", "iopub.status.idle": "2026-08-08T04:41:13.985311Z", "shell.execute_reply": "2026-08-08T04:41:13.984879Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "10:41PM 13s WARNING [check_lengths]: For path table, component=kink, key=trace has short segments that could cause issues with fillet. Values in (1-1) are index(es) in shapely geometry.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "10:41PM 13s WARNING [check_lengths]: For path table, component=kink, key=cut has short segments that could cause issues with fillet. Values in (1-1) are index(es) in shapely geometry.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "10:41PM 13s WARNING [check_lengths]: For path table, component=kink, key=trace has short segments that could cause issues with fillet. Values in (1-1) are index(es) in shapely geometry.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "10:41PM 13s WARNING [check_lengths]: For path table, component=kink, key=cut has short segments that could cause issues with fillet. Values in (1-1) are index(es) in shapely geometry.\n" ] }, { "data": { "text/plain": [ "['Q1',\n", " 'cross_h_a',\n", " 'cross_h_b',\n", " 'cross_h',\n", " 'cross_v_a',\n", " 'cross_v_b',\n", " 'cross_v',\n", " 'near_a_a',\n", " 'near_a_b',\n", " 'near_a',\n", " 'near_b_a',\n", " 'near_b_b',\n", " 'near_b',\n", " 'thin_a',\n", " 'thin_b',\n", " 'thin',\n", " 'LP',\n", " 'kink_a',\n", " 'kink_b',\n", " 'kink',\n", " 'hug_a',\n", " 'hug_b',\n", " 'hug',\n", " 'split_a',\n", " 'split_b',\n", " 'split']" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "design = new_design()\n", "\n", "TransmonPocket(design, \"Q1\", options=dict(pos_x=\"0mm\", pos_y=\"0mm\"))\n", "\n", "# 1. metal-overlap: two CPWs cross. On one layer, that is a short.\n", "link(design, \"cross_h\", (\"-2.6mm\", \"2mm\"), (\"-1.2mm\", \"2mm\"), \"180\", \"0\")\n", "link(design, \"cross_v\", (\"-1.9mm\", \"1.4mm\"), (\"-1.9mm\", \"2.6mm\"), \"270\", \"90\")\n", "\n", "# 2. metal-spacing: parallel CPWs 1 um apart. Not a short in the CAD, but\n", "# incomplete etching leaves residue that bridges gaps this narrow.\n", "link(design, \"near_a\", (\"0.6mm\", \"2.0055mm\"), (\"2.4mm\", \"2.0055mm\"), \"180\", \"0\")\n", "link(design, \"near_b\", (\"0.6mm\", \"1.9945mm\"), (\"2.4mm\", \"1.9945mm\"), \"180\", \"0\")\n", "\n", "# 3. cpw-gap: a 1 um gap concentrates field in the lossy substrate interface.\n", "link(\n", " design,\n", " \"thin\",\n", " (\"-2.6mm\", \"-2.4mm\"),\n", " (\"-0.6mm\", \"-2.4mm\"),\n", " \"180\",\n", " \"0\",\n", " trace_gap=\"1um\",\n", ")\n", "\n", "# 4. chip-bounds: the launchpad hangs off the die.\n", "LaunchpadWirebond(\n", " design, \"LP\", options=dict(pos_x=\"3.4mm\", pos_y=\"0mm\", orientation=\"180\")\n", ")\n", "\n", "# 5. short-segment: 100 um legs cannot host a 150 um fillet radius.\n", "link(\n", " design,\n", " \"kink\",\n", " (\"1.2mm\", \"-2.6mm\"),\n", " (\"1.3mm\", \"-2.5mm\"),\n", " \"180\",\n", " \"90\",\n", " cls=RoutePathfinder,\n", " fillet=\"150um\",\n", ")\n", "\n", "# 6. qubit-clearance: a CPW skimming Q1's pocket couples to the qubit.\n", "link(design, \"hug\", (\"-1.5mm\", \"0.35mm\"), (\"1.5mm\", \"0.35mm\"), \"180\", \"0\")\n", "\n", "# 7. ground-continuity: a CPW reaching both die edges cuts the ground in two.\n", "link(design, \"split\", (\"-2.994mm\", \"-1.2mm\"), (\"2.994mm\", \"-1.2mm\"), \"180\", \"0\")\n", "\n", "design.rebuild()\n", "design.components.keys()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:13.986617Z", "iopub.status.busy": "2026-08-08T04:41:13.986527Z", "iopub.status.idle": "2026-08-08T04:41:14.121623Z", "shell.execute_reply": "2026-08-08T04:41:14.120614Z" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = qm.view(design)\n", "qm.show_inline(fig)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The dashed rectangle is the die outline -- `qm.view` draws it so geometry\n", "placed off the chip is visible rather than silently clipped downstream (pass\n", "`chip_outline=False` for the geometry alone). The launchpad on the right is\n", "plainly outside it.\n", "\n", "The rest are invisible at this zoom. That is the point -- the eye checks\n", "topology, not micron-scale spacing.\n", "\n", "## Run the checks" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.124593Z", "iopub.status.busy": "2026-08-08T04:41:14.124374Z", "iopub.status.idle": "2026-08-08T04:41:14.161361Z", "shell.execute_reply": "2026-08-08T04:41:14.160389Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 finding(s) from 11 rule(s): 3 error(s), 7 warning(s)\n", " [error] metal-overlap: cross_h and cross_v overlap by 100 um^2 of metal on layer 1 @ (-1.9000, 2.0000)\n", " [error] metal-spacing: near_a and near_b are 1.00 um apart (minimum 2.00 um) @ (2.4000, 2.0000)\n", " [warning] cpw-gap: thin has a 1.00 um CPW gap (minimum 3.00 um) @ (-2.6000, -2.4000)\n", " [error] chip-bounds: LP extends 660.0 um beyond the 'main' chip outline @ (3.5175, 0.0000)\n", " [warning] short-segment: kink.trace segment 0 is 100.0 um long but needs 150.0 um for a 150.0 um fillet @ (1.2500, -2.6000)\n", " [warning] short-segment: kink.trace segment 1 is 100.0 um long but needs 150.0 um for a 150.0 um fillet @ (1.3000, -2.5500)\n", " [warning] short-segment: kink.cut segment 0 is 100.0 um long but needs 150.0 um for a 150.0 um fillet @ (1.2500, -2.6000)\n", " [warning] short-segment: kink.cut segment 1 is 100.0 um long but needs 150.0 um for a 150.0 um fillet @ (1.3000, -2.5500)\n", " [warning] qubit-clearance: hug passes 14.0 um from Q1's pocket (0.64x CPW width; want 3.0x = 66 um) @ (0.0000, 0.3500)\n", " [warning] ground-continuity: ground plane on layer 1 is split into 2 disconnected regions (mm^2: 24.528, 10.705); confirm airbridges or vias tie them together -- this check sees only same-layer metal @ (0.0000, -1.8000)\n" ] } ], "source": [ "result = validate(design)\n", "print(result.report())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reading the result\n", "\n", "`validate` returns a `ValidationResult`. It is **falsy when there are errors**,\n", "so it drops straight into an `if`. Each `Finding` is a frozen dataclass with\n", "the rule name, severity, message, the components involved, an `(x, y)`\n", "location in millimetres, and the measured `value` against the `limit` it\n", "missed." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.163884Z", "iopub.status.busy": "2026-08-08T04:41:14.163740Z", "iopub.status.idle": "2026-08-08T04:41:14.169770Z", "shell.execute_reply": "2026-08-08T04:41:14.168511Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "passes: False\n", "errors: 3 warnings: 7\n", "\n", "rule: metal-overlap\n", "severity: error\n", "components: ('cross_h', 'cross_v')\n", "location: (-1.9, 2.0)\n", "value/limit: 9.999999999999574e-05 / 1e-06\n" ] } ], "source": [ "print(\"passes:\", bool(result))\n", "print(\"errors:\", len(result.errors), \" warnings:\", len(result.warnings))\n", "\n", "worst = result.errors[0]\n", "print()\n", "print(\"rule: \", worst.rule)\n", "print(\"severity: \", worst.severity)\n", "print(\"components:\", worst.components)\n", "print(\"location: \", worst.location)\n", "print(\"value/limit:\", worst.value, \"/\", worst.limit)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.172201Z", "iopub.status.busy": "2026-08-08T04:41:14.172046Z", "iopub.status.idle": "2026-08-08T04:41:14.178028Z", "shell.execute_reply": "2026-08-08T04:41:14.177245Z" } }, "outputs": [ { "data": { "text/plain": [ "Counter({'short-segment': 4,\n", " 'metal-overlap': 1,\n", " 'metal-spacing': 1,\n", " 'cpw-gap': 1,\n", " 'chip-bounds': 1,\n", " 'qubit-clearance': 1,\n", " 'ground-continuity': 1})" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Group by rule to see the shape of the problem rather than a flat list.\n", "from collections import Counter\n", "\n", "Counter(f.rule for f in result.findings)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fixing them\n", "\n", "Each finding names the physics it protects, so the fix is not arbitrary.\n", "\n", "1. **`metal-overlap`** -- move `cross_v` clear of `cross_h`. If the crossing is\n", " deliberate, carry one line over the other on an airbridge. Drawing a bridge\n", " on top is not enough: the two lines still overlap on the base layer. See\n", " *Deliberate crossings* below.\n", "2. **`metal-spacing`** -- open the gap to 200 um. The 2 um default comes from\n", " published superconducting-chip rule sets; your foundry sets the real number.\n", "3. **`cpw-gap`** -- back to the standard 6 um. Narrow gaps push field into the\n", " substrate-metal interface, where two-level-system loss lives.\n", "4. **`chip-bounds`** -- pull the launchpad onto the die, or grow the die.\n", " Off-chip geometry is silently clipped by the GDS and FEM renderers.\n", "5. **`short-segment`** -- either lengthen the legs or shrink the fillet. A\n", " segment must be at least the fillet radius long (twice, if it is an interior\n", " segment with a corner at each end) or the renderer drops the arc and you get\n", " a sharp corner -- a current crowding point.\n", "6. **`qubit-clearance`** -- move the CPW away from the pocket. This is a\n", " *project heuristic*, not a literature value: 3x the CPW width is a\n", " conservative starting point, not a coupling calculation.\n", "7. **`ground-continuity`** -- stop the CPW short of the die edges so ground can\n", " flow around it. A split ground plane is not automatically wrong -- airbridges\n", " tie the pieces together and this rule cannot see them -- but an unintended\n", " split hosts slotline modes." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.180724Z", "iopub.status.busy": "2026-08-08T04:41:14.180504Z", "iopub.status.idle": "2026-08-08T04:41:14.513581Z", "shell.execute_reply": "2026-08-08T04:41:14.513042Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Design rules passed (11 rules ran, no findings).\n" ] } ], "source": [ "design = new_design()\n", "\n", "TransmonPocket(design, \"Q1\", options=dict(pos_x=\"0mm\", pos_y=\"0mm\"))\n", "\n", "link(design, \"cross_h\", (\"-2.6mm\", \"2mm\"), (\"-1.2mm\", \"2mm\"), \"180\", \"0\")\n", "link(design, \"cross_v\", (\"-1.9mm\", \"1.2mm\"), (\"-1.9mm\", \"1.7mm\"), \"270\", \"90\")\n", "link(design, \"near_a\", (\"0.6mm\", \"2.1mm\"), (\"2.4mm\", \"2.1mm\"), \"180\", \"0\")\n", "link(design, \"near_b\", (\"0.6mm\", \"1.9mm\"), (\"2.4mm\", \"1.9mm\"), \"180\", \"0\")\n", "link(\n", " design,\n", " \"thin\",\n", " (\"-2.6mm\", \"-2.4mm\"),\n", " (\"-0.6mm\", \"-2.4mm\"),\n", " \"180\",\n", " \"0\",\n", " trace_gap=\"6um\",\n", ")\n", "LaunchpadWirebond(\n", " design, \"LP\", options=dict(pos_x=\"2.5mm\", pos_y=\"0mm\", orientation=\"180\")\n", ")\n", "link(\n", " design,\n", " \"kink\",\n", " (\"0.9mm\", \"-2.6mm\"),\n", " (\"1.6mm\", \"-2.0mm\"),\n", " \"180\",\n", " \"90\",\n", " cls=RoutePathfinder,\n", " fillet=\"90um\",\n", ")\n", "link(design, \"hug\", (\"-1.5mm\", \"0.7mm\"), (\"1.5mm\", \"0.7mm\"), \"180\", \"0\")\n", "link(design, \"split\", (\"-2.4mm\", \"-1.2mm\"), (\"2.4mm\", \"-1.2mm\"), \"180\", \"0\")\n", "\n", "design.rebuild()\n", "\n", "result = validate(design)\n", "print(result.report())" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.514798Z", "iopub.status.busy": "2026-08-08T04:41:14.514716Z", "iopub.status.idle": "2026-08-08T04:41:14.556806Z", "shell.execute_reply": "2026-08-08T04:41:14.556397Z" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = qm.view(design)\n", "qm.show_inline(fig)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Deliberate crossings\n", "\n", "The rules check metal on each layer. An `Airbridge` puts its span and landing\n", "pads on their own layers (30 and 31 by default), so placing one over the\n", "crossing changes nothing on layer 1: the two lines still overlap, and the\n", "check still reports a short." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 finding(s) from 11 rule(s): 1 error(s), 0 warning(s)\n", " [error] metal-overlap: cross_h and cross_v overlap by 100 um^2 of metal on layer 1 @ (-1.9000, 2.0000)\n" ] } ], "source": [ "from qiskit_metal.qlibrary.tlines.airbridge import Airbridge\n", "from qiskit_metal.validation import Waiver\n", "\n", "crossing = new_design()\n", "link(crossing, \"cross_h\", (\"-2.6mm\", \"2mm\"), (\"-1.2mm\", \"2mm\"), \"180\", \"0\")\n", "link(crossing, \"cross_v\", (\"-1.9mm\", \"1.4mm\"), (\"-1.9mm\", \"2.6mm\"), \"270\", \"90\")\n", "Airbridge(\n", " crossing, \"AB\", options=dict(pos_x=\"-1.9mm\", pos_y=\"2mm\", crossover_length=\"30um\")\n", ")\n", "crossing.rebuild()\n", "\n", "print(validate(crossing).report())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a real crossover, cut the upper line where it crosses and connect the two\n", "cut ends to the bridge's pins `a` and `b`. The line is then continuous through\n", "the bridge, nothing overlaps on layer 1, and the check passes." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Design rules passed (11 rules ran, no findings).\n" ] } ], "source": [ "crossing = new_design()\n", "link(crossing, \"cross_v\", (\"-1.9mm\", \"1.4mm\"), (\"-1.9mm\", \"2.6mm\"), \"270\", \"90\")\n", "OpenToGround(\n", " crossing, \"h_west\", options=dict(pos_x=\"-2.6mm\", pos_y=\"2mm\", orientation=\"180\")\n", ")\n", "OpenToGround(\n", " crossing, \"h_east\", options=dict(pos_x=\"-1.2mm\", pos_y=\"2mm\", orientation=\"0\")\n", ")\n", "Airbridge(\n", " crossing, \"AB\", options=dict(pos_x=\"-1.9mm\", pos_y=\"2mm\", crossover_length=\"30um\")\n", ")\n", "\n", "# cross_h, cut in two at the bridge: west end -> pin a, pin b -> east end.\n", "for name, start, end in [\n", " (\"cross_h_west\", (\"h_west\", \"open\"), (\"AB\", \"a\")),\n", " (\"cross_h_east\", (\"AB\", \"b\"), (\"h_east\", \"open\")),\n", "]:\n", " RouteStraight(\n", " crossing,\n", " name,\n", " options=Dict(\n", " pin_inputs=Dict(\n", " start_pin=Dict(component=start[0], pin=start[1]),\n", " end_pin=Dict(component=end[0], pin=end[1]),\n", " )\n", " ),\n", " )\n", "crossing.rebuild()\n", "\n", "print(validate(crossing).report())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the layout keeps the lines whole on purpose -- for example, the crossovers\n", "are cut and bridged later in the mask flow -- keep the crossing and record a\n", "`Waiver` instead. A waiver needs a reason, can be limited to one rule, the\n", "components involved and a maximum value, and does not hide anything: the\n", "waived finding is still listed in the report, it just no longer counts as an\n", "error. Do not widen the rule's threshold instead; that would also hide real\n", "shorts." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "passes: True\n", "Design rules passed (11 rules ran, no findings).\n", "1 waived:\n", " [error] metal-overlap: cross_h and cross_v overlap by 100 um^2 of metal on layer 1 @ (-1.9000, 2.0000)\n", " waived: cross_v is carried over cross_h on an airbridge in the mask flow\n" ] } ], "source": [ "crossing = new_design()\n", "link(crossing, \"cross_h\", (\"-2.6mm\", \"2mm\"), (\"-1.2mm\", \"2mm\"), \"180\", \"0\")\n", "link(crossing, \"cross_v\", (\"-1.9mm\", \"1.4mm\"), (\"-1.9mm\", \"2.6mm\"), \"270\", \"90\")\n", "crossing.rebuild()\n", "\n", "waiver = Waiver(\n", " \"cross_v is carried over cross_h on an airbridge in the mask flow\",\n", " rule=\"metal-overlap\",\n", " components=(\"cross_h\", \"cross_v\"),\n", " max_value=200e-6, # mm^2: this crossing overlaps by 100 um^2\n", ")\n", "result = validate(crossing, waivers=[waiver])\n", "print(\"passes:\", bool(result))\n", "print(result.report())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tuning the rules\n", "\n", "Thresholds are constructor arguments, so a process design kit that differs from\n", "the defaults is a call, not a fork. Pass `rules=` to run a different set --\n", "either a subset, or the defaults with one swapped out." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.557871Z", "iopub.status.busy": "2026-08-08T04:41:14.557806Z", "iopub.status.idle": "2026-08-08T04:41:14.565614Z", "shell.execute_reply": "2026-08-08T04:41:14.565227Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8 finding(s) from 1 rule(s): 0 error(s), 8 warning(s)\n", " [warning] cpw-gap: cross_h has a 6.00 um CPW gap (minimum 10.00 um) @ (-1.2000, 2.0000)\n", " [warning] cpw-gap: cross_v has a 6.00 um CPW gap (minimum 10.00 um) @ (-1.9000, 1.2000)\n", " [warning] cpw-gap: near_a has a 6.00 um CPW gap (minimum 10.00 um) @ (2.4000, 2.1000)\n", " [warning] cpw-gap: near_b has a 6.00 um CPW gap (minimum 10.00 um) @ (2.4000, 1.9000)\n", " [warning] cpw-gap: thin has a 6.00 um CPW gap (minimum 10.00 um) @ (-2.6000, -2.4000)\n", " [warning] cpw-gap: kink has a 6.00 um CPW gap (minimum 10.00 um) @ (1.6000, -2.6000)\n", " [warning] cpw-gap: hug has a 6.00 um CPW gap (minimum 10.00 um) @ (-1.5000, 0.7000)\n", " [warning] cpw-gap: split has a 6.00 um CPW gap (minimum 10.00 um) @ (-2.4000, -1.2000)\n" ] } ], "source": [ "from qiskit_metal.validation import DEFAULT_RULES, CPWGapRule, MetalSpacingRule\n", "\n", "# Just one rule, at a tighter limit than the default.\n", "print(validate(design, rules=[CPWGapRule(min_gap=\"10um\")]).report())" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.566632Z", "iopub.status.busy": "2026-08-08T04:41:14.566568Z", "iopub.status.idle": "2026-08-08T04:41:14.581635Z", "shell.execute_reply": "2026-08-08T04:41:14.581238Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 finding(s) from 11 rule(s): 1 error(s), 0 warning(s)\n", " [error] metal-spacing: near_a and near_b are 190.00 um apart (minimum 250.00 um) @ (2.4000, 2.0000)\n" ] } ], "source": [ "# The 2 um default is a fabrication limit. A crosstalk budget is a separate,\n", "# much looser constraint -- unconnected CPWs kept 250 um apart. Replacing the\n", "# rule rather than adding one matters: both copies would run, and the design\n", "# would be reported twice.\n", "house_rules = [r for r in DEFAULT_RULES if r.name != \"metal-spacing\"]\n", "house_rules.append(MetalSpacingRule(min_spacing=\"250um\"))\n", "\n", "print(validate(design, rules=house_rules).report())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Severity is an argument too. Promote a warning to an error when your process\n", "treats it as a hard rule, and the result turns falsy." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.582705Z", "iopub.status.busy": "2026-08-08T04:41:14.582640Z", "iopub.status.idle": "2026-08-08T04:41:14.589819Z", "shell.execute_reply": "2026-08-08T04:41:14.589532Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "from qiskit_metal.validation import Severity\n", "\n", "strict_gap = CPWGapRule(min_gap=\"10um\", severity=Severity.ERROR)\n", "print(bool(validate(design, rules=[strict_gap])))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Failing the build\n", "\n", "In a design script or CI job you want the check to stop the run, not print.\n", "`strict=True` raises `DesignRuleViolation` on any error." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.591108Z", "iopub.status.busy": "2026-08-08T04:41:14.591041Z", "iopub.status.idle": "2026-08-08T04:41:14.598252Z", "shell.execute_reply": "2026-08-08T04:41:14.597875Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "build stopped:\n", "8 finding(s) from 1 rule(s): 8 error(s), 0 warning(s)\n" ] } ], "source": [ "from qiskit_metal.validation import DesignRuleViolation\n", "\n", "try:\n", " validate(design, rules=[strict_gap], strict=True)\n", "except DesignRuleViolation as exc:\n", " print(\"build stopped:\")\n", " print(str(exc).splitlines()[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same thing, without exceptions, at the end of a build script:\n", "\n", "```python\n", "result = validate(design)\n", "if not result:\n", " print(result.report())\n", " raise SystemExit(1)\n", "```\n", "\n", "Quantum Metal gates its own shipped reference designs this way -- see\n", "`tests/test_reference_designs.py`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Writing your own rule\n", "\n", "A rule is any object with a `name`, a `description`, and a `check(design)` that\n", "yields `Finding`s. Subclass `DesignRule` and use the same helpers the built-in\n", "rules use: `chip_bounds`, `component_geometry` (which unions each component's\n", "drawn metal, per layer if you ask), and `representative_point`.\n", "\n", "Here is a fab rule the defaults do not cover: nothing may reach into the dicing\n", "street at the die edge." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2026-08-08T04:41:14.599465Z", "iopub.status.busy": "2026-08-08T04:41:14.599398Z", "iopub.status.idle": "2026-08-08T04:41:14.604668Z", "shell.execute_reply": "2026-08-08T04:41:14.604294Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2 finding(s) from 1 rule(s): 2 error(s), 0 warning(s)\n", " [error] keep-out-border: kink reaches 400 um into the dicing street @ (1.2521, -2.6026)\n", " [error] keep-out-border: LP reaches 400 um into the dicing street @ (2.6510, 0.0000)\n" ] } ], "source": [ "from shapely.geometry import box\n", "\n", "from qiskit_metal.validation import (\n", " DesignRule,\n", " Finding,\n", " chip_bounds,\n", " component_geometry,\n", " representative_point,\n", ")\n", "\n", "\n", "class KeepOutBorderRule(DesignRule):\n", " \"\"\"Metal must stay clear of the dicing street at the chip edge.\"\"\"\n", "\n", " name = \"keep-out-border\"\n", " description = \"Metal reaches into the dicing street.\"\n", "\n", " def __init__(self, margin=\"400um\", severity=Severity.ERROR):\n", " self.margin = margin\n", " self.severity = severity\n", "\n", " def check(self, design):\n", " margin = design.parse_value(self.margin)\n", " minx, miny, maxx, maxy = chip_bounds(design)\n", " keep_in = box(minx + margin, miny + margin, maxx - margin, maxy - margin)\n", "\n", " for name, geometry in component_geometry(design).items():\n", " outside = geometry.difference(keep_in)\n", " if outside.is_empty:\n", " continue\n", " yield Finding(\n", " rule=self.name,\n", " severity=self.severity,\n", " message=(\n", " f\"{name} reaches {margin * 1000:.0f} um into the dicing street\"\n", " ),\n", " components=(name,),\n", " location=representative_point(outside),\n", " value=outside.area,\n", " limit=0.0,\n", " )\n", "\n", "\n", "print(validate(design, rules=[KeepOutBorderRule()]).report())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What this does not check\n", "\n", "DRC is a geometry check. It says nothing about whether your resonator is at the\n", "frequency you wanted, whether the coupling is right, or whether the qubit is\n", "anharmonic enough -- those need the analysis notebooks in section 4. It also\n", "knows nothing about your foundry's actual rule deck; the defaults are a\n", "published starting point.\n", "\n", "Three known limits worth stating plainly:\n", "\n", "- **Layers are trusted.** Overlap and spacing are checked per layer, so metal on\n", " layer 30 crossing metal on layer 1 is fine. If your stack does not match that\n", " assumption, the rules will miss real shorts.\n", "- **`net_info` is trusted.** Components joined through a pin are exempt from the\n", " overlap and spacing rules, because a route abutting its termination is not a\n", " short.\n", "- **`ground-continuity` sees one layer.** It reports that the ground is split,\n", " not that a piece is floating -- an airbridge on another layer may well tie the\n", " pieces together.\n", "\n", "## References\n", "\n", "- *From GDSII to Wafer: EDA Design Flow and Data Conversion for Wafer-Scale\n", " Manufacturing of Superconducting Quantum Chips*,\n", " [arXiv:2604.11379](https://arxiv.org/abs/2604.11379) -- the R1 / R8 / R9\n", " thresholds used above.\n", "- *A Review of Design Concerns in Superconducting Quantum Circuits*,\n", " [arXiv:2411.16967](https://arxiv.org/abs/2411.16967) -- crosstalk mechanisms\n", " and airbridge placement.\n", "- Airbridges in Quantum Metal: tutorial 2.15.\n", "- Full worked designs that pass these rules: Appendix A." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.14" } }, "nbformat": 4, "nbformat_minor": 4 }