Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added airbridges to QGDSRenderer #962

Open
wants to merge 59 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
2a4e33c
added QComponent representing Airbridge for GDS
Jun 26, 2023
06b43bc
Merge branch 'airbridges' of https://github.com/clarkmiyamoto/qiskit-…
Jun 26, 2023
7d44837
more airbridge stuff
Jun 27, 2023
b1d75e5
correct pathing for Airbridge_forGDS
Jun 27, 2023
ba1a21d
should be working??? time to test
Jun 27, 2023
2e1b955
added pathing for Airbridging
Jun 27, 2023
6ec3837
fixed typo in make_uniform_airbridging
Jun 27, 2023
03a30f3
added bridge_minimum_spacing to default_options
Jun 27, 2023
7b9632a
fixed typo in extract_qgeom_from_unrendered_qcomp
Jun 27, 2023
afbd457
fixed variable assignment error in Airbridge_forGDS
Jun 27, 2023
61761c8
typo in Airbridge_forGDS
Jun 27, 2023
bb7514c
fixed typo in make_uniform_airbridging_df
Jun 27, 2023
e2d5dc9
fixed typo in make_uniform_airbridging_df
Jun 27, 2023
3cc56b2
fixed cpw_with_ab property
Jun 27, 2023
63c1d6f
fixed self reassignment of ab_placement_to_df
Jun 27, 2023
5824996
fixed bug where ab_placement_to_df didn't save data
Jun 27, 2023
8d64e7f
fixed typo in make_uniform_airbridging_df
Jun 27, 2023
7317803
test
Jun 27, 2023
c134e0d
forgot to import draw in make_airbridge.py
Jun 27, 2023
0cdc8c5
fixed typo in cpws_with_ab
Jun 27, 2023
5f70178
fixed typo in cpws_with_ab
Jun 27, 2023
b5d5396
fixed find_uniform_ab_placement
Jun 27, 2023
af264c1
add float casting to find_uniform_ab_placement
Jun 27, 2023
52eec98
fixed precision error
Jun 27, 2023
6e0875c
reworked self.precision
Jun 27, 2023
9dd9679
forgot to reference self in ab_placement_to_df
Jun 27, 2023
3a8dda3
fixed output of find_uniform_ab_placement
Jun 27, 2023
ec9dcf4
fixed keyerror
Jun 27, 2023
bbba191
fixed typo in calling _multipolygon_to_gds
Jun 27, 2023
2ca5f96
added MultiPoly
Jun 27, 2023
f599ed0
maybed fixed ab_placement_to_df
Jun 27, 2023
a184cc8
typo
Jun 27, 2023
4874446
updates self.chip_info
Jun 27, 2023
276269d
should push to gds
Jun 27, 2023
0722e4a
should push to gds
Jun 27, 2023
4cc60f6
fixed rotation of ab
Jun 27, 2023
2bbac99
fixed rotation of ab
Jun 27, 2023
63a09fb
fixed rotation of ab
Jun 27, 2023
7167ff7
fixed depreciation warning
Jun 27, 2023
b04f902
couldn't fix depreciation error, will leave for someone else
Jun 27, 2023
2ea6c29
added documentation
Jun 27, 2023
bc1ec37
added basic tests
Jun 27, 2023
79977e2
yapf styling
Jun 27, 2023
728e72d
yapf in test
Jun 27, 2023
d37bf2f
fixed error in data_type parsing in _make_uniform_airbridging_df
Jun 27, 2023
eb5dbf8
default_options.airbrdige.datatype isn't loading
Jun 27, 2023
8befcc8
logger works now
Jun 27, 2023
bfb3e15
removed unnessary arg in _make_uniform_airbridging_df
Jun 27, 2023
af5c54e
fixed spelling of outer
Jun 27, 2023
ddfb065
fixed airbridge.py drawing
Jun 27, 2023
1bbea15
update QGDS tutorial to include how to use airbridges
Jun 27, 2023
5af5df4
update QGDS tutorial to include how to use airbridges
Jun 27, 2023
9bb2f43
fixed typo in MPL test
Jun 27, 2023
ef0e92b
add robust test to airbridging
Jun 27, 2023
a0ac02c
fixed tests
Jun 27, 2023
9f8edd5
fixed yapf in tests
Jun 27, 2023
4e95215
typo in test_renderer_gdsrenderer_high_level
Jun 27, 2023
9b5e9bf
typo in test
Jun 27, 2023
bf8de84
Merge branch 'main' into airbridges
zlatko-minev Sep 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions qiskit_metal/renderers/renderer_gds/airbridge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from qiskit_metal import draw, Dict
from qiskit_metal.qlibrary.core.base import QComponent


class Airbridge_forGDS(QComponent):
"""
The base "Airbridge" inherits the "QComponent" class.

NOTE TO USER: This component is designed for GDS export only.
This QComponent should NOT be rendered for EM simulation.

Default Options:
* crossover_length: '22um' -- Distance between the two outer squares (aka bridge length).
Usually, this should be the same length as (cpw_width + 2 * cpw_gap)
* bridge_width: '7.5um' -- Width of bridge element
* inner_length: '8um' -- Length of inner square.
* outer_length: '11um' -- Length of outer square.
* square_layer: 30 -- GDS layer of inner squares.
* bridge_layer: 31 -- GDS layer of bridge + outer squares.
"""

# Default drawing options
default_options = Dict(crossover_length='22um',
bridge_width='7.5um',
inner_length='8um',
outer_length='11um',
square_layer=30,
bridge_layer=31)
"""Default drawing options"""

# Name prefix of component, if user doesn't provide name
component_metadata = Dict(short_name='airbridge')
"""Component metadata"""

def make(self):
"""Convert self.options into QGeometry."""
# Parse options
p = self.parse_options()
crossover_length = p.crossover_length
bridge_width = p.bridge_width
inner_length = p.inner_length
outer_length = p.outer_length

# Make the inner square structure
left_inside = draw.rectangle(inner_length, inner_length, 0, 0)
right_inside = draw.translate(left_inside,
crossover_length / 2 + outer_length / 2,
0)
left_inside = draw.translate(left_inside,
-(crossover_length / 2 + outer_length / 2),
0)

inside_struct = draw.union(left_inside, right_inside)

# Make the outer square structure
left_outside = draw.rectangle(outer_length, outer_length, 0, 0)
right_outside = draw.translate(left_outside,
crossover_length / 2 + outer_length / 2,
0)
left_outside = draw.translate(
left_outside, -(crossover_length / 2 + outer_length / 2), 0)

# Make the bridge structure
bridge = draw.rectangle(crossover_length, bridge_width, 0, 0)
bridge_struct = draw.union(bridge, left_outside, right_outside)

### Final adjustments to allow repositioning
final_design = [bridge_struct, inside_struct]
final_design = draw.rotate(final_design, p.orientation, origin=(0, 0))
final_design = draw.translate(final_design, p.pos_x, p.pos_y)
bridge_struct, inside_struct = final_design

### Add everything as a QGeometry
self.add_qgeometry('poly', {'bridge_struct': bridge_struct},
layer=p.bridge_layer,
subtract=False)
self.add_qgeometry('poly', {'inside_struct': inside_struct},
layer=p.square_layer,
subtract=False)
121 changes: 120 additions & 1 deletion qiskit_metal/renderers/renderer_gds/gds_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import numpy as np

from qiskit_metal.renderers.renderer_base import QRenderer
from qiskit_metal.renderers.renderer_gds.airbridge import Airbridge_forGDS
from qiskit_metal.renderers.renderer_gds.make_airbridge import Airbridging
from qiskit_metal.renderers.renderer_gds.make_cheese import Cheesing
from qiskit_metal.toolbox_metal.parsing import is_true
from qiskit_metal import draw
Expand Down Expand Up @@ -94,6 +96,13 @@ class QGDSRenderer(QRenderer):
* junction_pad_overlap: '5um'
* max_points: '199'
* fabricate: 'False'
* airbridge: Dict
* geometry: Dict
qcomponent_base: Airbridge_forGDS
options: Dict(crossover_length='22um')
* bridge_pitch: '100um'
* bridge_minimum_spacing: '5um'
* datatype: '0'
* cheese: Dict
* datatype: '100'
* shape: '0'
Expand Down Expand Up @@ -212,6 +221,26 @@ class QGDSRenderer(QRenderer):
# handle is 8191.
max_points='199',

# Airbriding
airbridge=Dict(
# GDS datatype of airbridges.
datatype='0',

# Setup geometrical style of airbridge
geometry=Dict(
# Skeleton of airbridge in QComponent form,
# meaning this is a child of QComponents.
qcomponent_base=Airbridge_forGDS,
# These options are plugged into the qcomponent_base.
# Think of it as calling qcomponent_base(design, name, options=options).
options=Dict(crossover_length='22um')),
# Spacing between centers of each airbridge.
bridge_pitch='100um',

# Minimum spacing between each airbridge,
# this number usually comes from fabrication guidelines.
bridge_minimum_spacing='5um'),

# Cheesing is denoted by each chip and layer.
cheese=Dict(
#Cheesing is NOT completed
Expand Down Expand Up @@ -288,7 +317,8 @@ class QGDSRenderer(QRenderer):

element_table_data = dict(
# Cell_name must exist in gds file with: path_filename
junction=dict(cell_name='my_other_junction'))
junction=dict(cell_name='my_other_junction'),
path=dict(make_airbridge=False))
"""Element table data"""

def __init__(self,
Expand Down Expand Up @@ -1096,6 +1126,89 @@ def new_gds_library(self) -> gdspy.GdsLibrary:

return self.lib

### Start of Airbridging

def _populate_airbridge(self):
"""
Main function to make airbridges. This is called in `self.export_to_gds()`.
"""
for chip_name in self.chip_info:
layers_in_chip = self.design.qgeometry.get_all_unique_layers(
chip_name)

chip_box, status = self.design.get_x_y_for_chip(chip_name)
if status == 0:
minx, miny, maxx, maxy = chip_box

# Right now this code assumes airbridges will look
# the same across all CPWs. If you want to change that,
# add an if/else statement here to check for custom behavior.
# You will also have to update the self.default_options.
self._make_uniform_airbridging_df(minx, miny, maxx, maxy,
chip_name)

def _make_uniform_airbridging_df(self, minx: float, miny: float,
maxx: float, maxy: float, chip_name: str):
"""
Apply airbridges to all `path` elements which have
options.gds_make_airbridge = True. This is a
wrapper for Airbridging.make_uniform_airbridging_df(...).

Args:
minx (float): Chip minimum x location.
miny (float): Chip minimum y location.
maxx (float): Chip maximum x location.
maxy (float): chip maximum y location.
chip_name (str): User defined chip name.
"""
# Warning / limitations
if (self.options.corners != 'circular bend'):
self.logger.warning(
'Uniform airbridging is designed for `self.options.corners = "circular bend"`. You might experience unexpected behavior.'
)

# gdspy objects
top_cell = self.lib.cells[f'TOP_{chip_name}']
lib_cell = self.lib.new_cell(f'TOP_{chip_name}_ab')
datatype = int(self.parse_value(self.options.airbridge.datatype))
no_cheese_buffer = float(self.parse_value(
self.options.no_cheese.buffer))

# Airbridge Options
self.options.airbridge.qcomponent_base
self.options.airbridge.options
airbridging = Airbridging(design=self.design,
lib=self.lib,
minx=minx,
miny=miny,
maxx=maxx,
maxy=maxy,
chip_name=chip_name,
precision=self.options.precision)
airbridges_df = airbridging.make_uniform_airbridging_df(
custom_qcomponent=self.options.airbridge.geometry.qcomponent_base,
qcomponent_options=self.options.airbridge.geometry.options,
bridge_pitch=self.options.airbridge.bridge_pitch,
bridge_minimum_spacing=self.options.airbridge.bridge_minimum_spacing
)

# Get all MultiPolygons and render to gds file
for _, row in airbridges_df.iterrows():
ab_component_multi_poly = row['MultiPoly']
ab_component_layer = row['layer']
airbridge_gds = self._multipolygon_to_gds(
multi_poly=ab_component_multi_poly,
layer=ab_component_layer,
data_type=datatype,
no_cheese_buffer=no_cheese_buffer)

lib_cell.add(airbridge_gds)
top_cell.add(gdspy.CellReference(lib_cell))

### End of Airbridging

### Start of Cheesing

def _check_cheese(self, chip: str, layer: int) -> int:
"""Examine the option for cheese_view_in_file.

Expand Down Expand Up @@ -1481,6 +1594,8 @@ def _cheese_buffer_maker(
return combo_shapely
return None # Need explicitly to avoid lint warnings.

### End of Cheesing

def _get_rectangle_points(self, chip_name: str) -> Tuple[list, list]:
"""There can be more than one chip in QGeometry. All chips export to
one gds file. Each chip uses its own subtract rectangle.
Expand Down Expand Up @@ -2162,6 +2277,10 @@ def export_to_gds(self,
# Create self.lib and populate path and poly.
self._populate_poly_path_for_export()

# Adds airbridges to CPWs w/ options.gds_make_airbridge = True
# Options for these airbridges are in self.options.airbridge
self._populate_airbridge()

# Add no-cheese MultiPolygon to
# self.chip_info[chip_name][chip_layer]['no_cheese'],
# if self.options requests the layer.
Expand Down
Loading
Loading