Skip to content

Commit

Permalink
Improve probepoint export according to current standards
Browse files Browse the repository at this point in the history
* single-reference support
* assign "west" and "east" probers
* unit tests
* macro to visualise exported probepoints for visual inspection
  • Loading branch information
qpavsmi committed Feb 2, 2024
1 parent e2380b2 commit 9ef81a8
Show file tree
Hide file tree
Showing 7 changed files with 1,020 additions and 70 deletions.
23 changes: 18 additions & 5 deletions klayout_package/python/kqcircuits/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,24 @@
default_bar_format = '{l_bar}{bar}| {n_fmt}/{total_fmt} [Elapsed: {elapsed}, Left (eta): {remaining}, {rate_inv_fmt}' \
'{postfix}]'

# dictionary of probepoint types for probepoint export
# key is the refpoint name prefix for a type of probepoints, value is a text representation of the probepoint type
default_probe_types = {"testarray": "testarrays", "qb": "qubits"}
# tuple of refpoint name suffixes that are used (together with probe_types) to identify refpoints as probepoints
default_probe_suffixes = ("_c", "_l")
# refpoint is extracted as probepoint if it contains some string from default_probe_types and
# ends with some substring from default_probe_suffixes

default_probe_types = ["testarray", "qb"]
default_probe_suffixes = [
"_l", "_r", "_top", # Test array probepoints
# Single island qubit probepoints
"_probe_ground", "_probe_island",
# Double island qubit probepoints
"_probe_island_1", "_probe_island_2"
]
# for probepoint pair, one is assigned to west and other to east prober based on their x coordinate
# but we also want to set a standard where ground is consistently probed from one side and island
# from the other. This dict defines such rules
recommended_probe_suffix_mapping = {
"_probe_ground": "east",
"_probe_island": "west"
}

# Library names in dependency order. Every library should have its dependencies before its own entry.
kqc_library_names = (
Expand Down
7 changes: 7 additions & 0 deletions klayout_package/python/kqcircuits/qubits/double_pads.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ def build(self):
self.add_port("drive", pya.DPoint(float(self.drive_position[0]), float(self.drive_position[1])),
direction=pya.DVector(float(self.drive_position[0]), float(self.drive_position[1])))

# Probepoints
self.refpoints["probe_island_1"] = pya.DPoint(0,
self.squid_offset + squid_height / 2 + taper_height + float(self.island1_extent[1]) / 2)
self.refpoints["probe_island_2"] = pya.DPoint(0,
self.squid_offset - squid_height / 2 - taper_height - float(self.island2_extent[1]) / 2)


def _build_coupler(self, first_island_top_edge):
coupler_top_edge = first_island_top_edge + self.coupler_offset + float(self.coupler_extent[1])
coupler_polygon = pya.DPolygon([
Expand Down
13 changes: 13 additions & 0 deletions klayout_package/python/kqcircuits/qubits/qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ class Qubit(Element):
* possible fluxlines
* e-beam layers for SQUIDs
* SQUID name parameter
It is customary to also define probepoints for a qubit. Simply define two refpoints as appropriate probepoints.
For single island qubits::
self.refpoints["probe_ground"] = pya.DPoint(...)
self.refpoints["probe_island"] = pya.DPoint(...)
self.cell.shapes(self.get_layer("ground_grid_avoidance")).insert(
pya.DBox(-20.0, -20.0, 20.0, 20.0).moved(self.refpoints["probe_ground"]))
For double island qubits::
self.refpoints["probe_island_1"] = pya.DPoint(...)
self.refpoints["probe_island_2"] = pya.DPoint(...)
"""

LIBRARY_NAME = "Qubit Library"
Expand Down
321 changes: 258 additions & 63 deletions klayout_package/python/kqcircuits/util/export_helper.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<doc/>
<autorun>false</autorun>
<autorun-early>false</autorun-early>
<priority>0</priority>
<shortcut/>
<show-in-menu>false</show-in-menu>
<group-name/>
Expand All @@ -34,13 +35,26 @@

"""Prints the probepoints of a chip as JSON. Assumes that a single chip exists in the top cell."""

import json
from kqcircuits.klayout_view import KLayoutView
from kqcircuits.util.export_helper import generate_probepoints_json

top_cell = KLayoutView(current=True).active_cell

### Set file location, or leave empty to get probepoint JSON empty
FILE_LOCATION = ""
### Action
# Note that this works on the bottom face by default. For the top, specify a second 't' argument.
print(generate_probepoints_json(top_cell))
# See API docs on how to best call generate_probepoints_json for your purposes
probepoint_json = generate_probepoints_json(top_cell,
face='1t1',
references=['nw'],
contact=None)
json_str = json.dumps(probepoint_json, indent=2)

if FILE_LOCATION:
with open(FILE_LOCATION, 'w') as file:
file.write(json_str)
else:
print(json_str)
</text>
</klayout-macro>
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description>Visualise probepoints from json file to layout</description>
<version/>
<category>pymacros</category>
<prolog/>
<epilog/>
<doc/>
<autorun>false</autorun>
<autorun-early>false</autorun-early>
<priority>0</priority>
<shortcut/>
<show-in-menu>false</show-in-menu>
<group-name/>
<menu-path/>
<interpreter>python</interpreter>
<dsl-interpreter-name/>
<text># This code is part of KQCircuits
# Copyright (C) 2023 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/developers/osstmpolicy). IQM welcomes contributions to the code. Please see our contribution agreements
# for individuals (meetiqm.com/developers/clas/individual) and organizations (meetiqm.com/developers/clas/organization).


"""Visualises the probepoints in external JSON file.
Open or generate chip geometry then run this macro with specified filename
to compare that the probepoints align with chip components.
After running this macro, right click the Layers panel (on the right by default)
and choose "Add Other Layer Entries".
"""

import json
from kqcircuits.klayout_view import KLayoutView
from kqcircuits.pya_resolver import pya
from kqcircuits.util.export_helper import generate_probepoints_json

# SPECIFY ARGUMENTS
FILENAME = "" # Probepoint JSON file to visualise
FLIP_FACE = False # Mirrors points wrt Y-axis. Recommended for flipchips
FACE = '1t1' # Specify substrate face to probe

cell = KLayoutView(current=True).active_cell

with open(FILENAME) as f:
probepoint_json = json.load(f)

bbox_for_face = cell.dbbox_per_layer(
cell.layout().layer(
[l for l in cell.layout().layer_infos() if l.name == f"{FACE}_base_metal_gap_wo_grid"][0]
)
)

def to_dtext(text_string, json_object):
x = json_object["x"] * 1e3
y = json_object["y"] * 1e3
if FLIP_FACE:
x = bbox_for_face.p2.x - x
else:
x += bbox_for_face.p1.x
y += bbox_for_face.p1.y
return pya.DText(text_string, x, y)

def visualise_point(group, layer_string, text_string, json_object):
layer_name = layer_string if not group else f"{group}_{layer_string}"
cell.shapes(cell.layout().layer(layer_name)).insert(to_dtext(text_string, json_object))

def visualise_group(group):
visualise_point(group.get("id"), "alignment", "alignment", probepoint_json["alignment"])
for site in probepoint_json["sites"]:
visualise_point(group.get("id"), "east", site["id"], site["east"])
visualise_point(group.get("id"), "west", site["id"], site["west"])

for layer in cell.layout().layer_infos():
if "alignment" in layer.name or "west" in layer.name or "east" in layer.name:
cell.shapes(cell.layout().layer(layer)).clear()

if "groups" in probepoint_json:
for group in groups:
visualise_group(group)
else:
visualise_group(probepoint_json)</text>
</klayout-macro>
Loading

0 comments on commit 9ef81a8

Please sign in to comment.