Demonstrate LVS with KLayout#426
Conversation
Agent-Logs-Url: https://github.com/gdsfactory/quantum-rf-pdk/sessions/169d2f22-adee-4d31-b623-835e10d86125 Co-authored-by: nikosavola <7860886+nikosavola@users.noreply.github.com>
Agent-Logs-Url: https://github.com/gdsfactory/quantum-rf-pdk/sessions/169d2f22-adee-4d31-b623-835e10d86125 Co-authored-by: nikosavola <7860886+nikosavola@users.noreply.github.com>
…tting Agent-Logs-Url: https://github.com/gdsfactory/quantum-rf-pdk/sessions/169d2f22-adee-4d31-b623-835e10d86125 Co-authored-by: nikosavola <7860886+nikosavola@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds an LVS (layout-vs-schematic) flow to QPDK using KLayout, including a generated LVS deck (via Jinja2 templating), new LVS-specific layers (ports + device markers), documentation for running/inspecting LVS, and a small test suite to keep the generated deck in sync.
Changes:
- Introduces a Jinja2-templated KLayout LVS deck plus a Python renderer and committed generated output.
- Adds LVS port layers and device marker layers to the PDK layer map and layer-view configuration (YAML + KLayout layer properties).
- Adds documentation and tests for the rendering/deck consistency.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_lvs.py |
New tests asserting renderer output coverage and that the committed deck matches rendering. |
qpdk/tech.py |
Adds PORT_* and MK_* layer constants to the PDK layer map. |
qpdk/layers.yaml |
Adds LVS_Ports and LVS_Markers layer-view groups for visibility/coloring. |
qpdk/klayout/tech.lyt |
Reorders connectivity <symbols> entries (no functional changes apparent). |
qpdk/klayout/lvs/render_lvs.py |
New deck renderer with declarative layer/connectivity/device tables. |
qpdk/klayout/lvs/qpdk.lvs.j2 |
New Jinja2 template for the KLayout LVS deck. |
qpdk/klayout/lvs/qpdk.lvs |
Generated LVS deck committed to the repo. |
qpdk/klayout/layers.lyp |
Adds LVS port/marker groups to the KLayout layer properties file. |
docs/lvs.md |
New end-to-end documentation for the LVS flow, including component authoring guidance. |
docs/index.md |
Adds LVS docs page to the docs toctree under “Verification”. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from qpdk.klayout.lvs import render_lvs as _render_lvs_mod | ||
| from qpdk.klayout.lvs.render_lvs import ( | ||
| CONNECTIONS, | ||
| DEVICES, | ||
| MARKER_LAYERS, | ||
| PHYSICAL_LAYERS, | ||
| PORT_LAYERS, | ||
| render, | ||
| ) | ||
|
|
||
|
|
There was a problem hiding this comment.
from qpdk.klayout.lvs ... will fail because qpdk/klayout/ and qpdk/klayout/lvs/ are not Python packages in this repo (no __init__.py files). Add __init__.py files (or move the renderer into an existing package) so these imports and tests can run.
| from qpdk.klayout.lvs import render_lvs as _render_lvs_mod | |
| from qpdk.klayout.lvs.render_lvs import ( | |
| CONNECTIONS, | |
| DEVICES, | |
| MARKER_LAYERS, | |
| PHYSICAL_LAYERS, | |
| PORT_LAYERS, | |
| render, | |
| ) | |
| from importlib.machinery import SourceFileLoader | |
| from pathlib import Path | |
| _render_lvs_path = ( | |
| Path(__file__).resolve().parents[1] | |
| / "qpdk" | |
| / "klayout" | |
| / "lvs" | |
| / "render_lvs.py" | |
| ) | |
| _render_lvs_mod = SourceFileLoader( | |
| "qpdk_klayout_lvs_render_lvs", str(_render_lvs_path) | |
| ).load_module() | |
| CONNECTIONS = _render_lvs_mod.CONNECTIONS | |
| DEVICES = _render_lvs_mod.DEVICES | |
| MARKER_LAYERS = _render_lvs_mod.MARKER_LAYERS | |
| PHYSICAL_LAYERS = _render_lvs_mod.PHYSICAL_LAYERS | |
| PORT_LAYERS = _render_lvs_mod.PORT_LAYERS | |
| render = _render_lvs_mod.render |
| from jinja2 import Environment, FileSystemLoader | ||
|
|
There was a problem hiding this comment.
render_lvs.py imports jinja2, but jinja2 is not listed in the project’s core or test dependencies (it appears only under the docs dependency group). Since this module is imported by tests and is part of the shipped package, add jinja2 to the appropriate runtime deps (or make this import optional / guarded) to avoid ImportError in CI and user installs.
| from jinja2 import Environment, FileSystemLoader | |
| try: | |
| from jinja2 import Environment, FileSystemLoader | |
| except ImportError: # pragma: no cover - exercised only when jinja2 is missing | |
| def _missing_jinja2(*args: object, **kwargs: object) -> "NoReturn": # type: ignore[name-defined] | |
| raise RuntimeError( | |
| "The 'jinja2' package is required to use qpdk.klayout.lvs.render_lvs. " | |
| "Install it as a runtime dependency (e.g. 'pip install jinja2') or via " | |
| "the appropriate extras group for this project." | |
| ) | |
| Environment = _missing_jinja2 # type: ignore[assignment] | |
| FileSystemLoader = _missing_jinja2 # type: ignore[assignment] |
|
|
||
| from jinja2 import Environment, FileSystemLoader | ||
|
|
||
| from qpdk import logger |
There was a problem hiding this comment.
Importing logger via from qpdk import logger executes qpdk/__init__.py (which constructs the PDK and imports gdsfactory), adding unnecessary side effects and startup cost for a simple deck renderer. Prefer importing the logger directly (e.g., from qpdk.logger import logger) to keep this script lightweight.
| from qpdk import logger | |
| from qpdk.logger import logger |
| """Render the QPDK KLayout LVS deck from a Jinja2 template. | ||
|
|
||
| The template ``qpdk.lvs.j2`` lives next to this script and is rendered into | ||
| ``qpdk.lvs`` using the layer and device definitions from :mod:`qpdk.tech`. |
There was a problem hiding this comment.
The module docstring says the deck is rendered “using the layer and device definitions from qpdk.tech”, but the layer/connectivity/device tables are currently hard-coded in this file. Either source these values from qpdk.tech (to prevent drift) or adjust the docstring to match the implementation.
| ``qpdk.lvs`` using the layer and device definitions from :mod:`qpdk.tech`. | |
| ``qpdk.lvs`` using the layer and device definitions defined in this module. |
| (bbox[0][0], bbox[0][1]), | ||
| (bbox[1][0], bbox[0][1]), | ||
| (bbox[1][0], bbox[1][1]), | ||
| (bbox[0][0], bbox[1][1]), |
There was a problem hiding this comment.
In this example, bbox = c.bbox() is treated like a 2×2 array (bbox[0][0], etc.), but elsewhere in this repo bbox() returns a KLayout box-like object with attributes (left/right/top/bottom or p1/p2). As written, this snippet is likely to raise at runtime; update it to use the box attributes used throughout the codebase.
| (bbox[0][0], bbox[0][1]), | |
| (bbox[1][0], bbox[0][1]), | |
| (bbox[1][0], bbox[1][1]), | |
| (bbox[0][0], bbox[1][1]), | |
| (bbox.left, bbox.bottom), | |
| (bbox.right, bbox.bottom), | |
| (bbox.right, bbox.top), | |
| (bbox.left, bbox.top), |
Adds a KLayout LVS deck for layout-vs-schematic verification of superconducting quantum circuits, with Jinja2 templating for maintainability and documentation explaining the full flow.
New layers
PORT_M11/10,PORT_M22/10) for net terminal detection per metalMK_TRANSMON200/0,MK_RESONATOR201/0,MK_INDUCTOR202/0,MK_CAPACITOR203/0,MK_JJ204/0) for component identification via boolean AND with physical layersLVS deck (
qpdk/klayout/lvs/)qpdk.lvs.j2— Jinja2 template covering layer definitions, connectivity (TSV, indium bumps, airbridges), marker-based device extraction, and port/pin detectionrender_lvs.py— Declarative data tables for layers, connectivity rules, and device definitions; renders the templateqpdk.lvs— Generated deck, invoked as:klayout -b -r qpdk/klayout/lvs/qpdk.lvs \ -rd input=layout.gds \ -rd schematic=netlist.cir \ -rd report=lvs_report.lvsdbAdding a new device type requires only appending to the
DEVICESlist inrender_lvs.pyand re-rendering.Documentation (
docs/lvs.md)Covers what LVS is in the quantum context, how the deck works (connectivity, ports, markers), how to add port/marker shapes to components, how to run LVS, and how to inspect results in KLayout's Netlist Database Browser.
Tests (
tests/test_lvs.py)9 tests covering template rendering, layer/connectivity/device coverage, and committed file consistency.
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.