From 2a4e33ce50766f45125ae44f7f722bed39252f7b Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Sun, 25 Jun 2023 19:32:35 -1000 Subject: [PATCH 01/57] added QComponent representing Airbridge for GDS --- .../renderers/renderer_gds/airbridge.py | 68 +++++ .../renderers/renderer_gds/gds_renderer.py | 82 +++++- .../renderers/renderer_gds/make_airbridge.py | 237 ++++++++++++++++++ 3 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 qiskit_metal/renderers/renderer_gds/airbridge.py create mode 100644 qiskit_metal/renderers/renderer_gds/make_airbridge.py diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py new file mode 100644 index 000000000..84b027caf --- /dev/null +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -0,0 +1,68 @@ +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: '20um' -- Distance between the two outter 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. + * outter_length: '11um' -- Length of outter square. + * square_layer: 30 -- GDS layer of inner squares. + * bridge_layer: 31 -- GDS layer of bridge + outter squares. + """ + + # Default drawing options + default_options = Dict(crossover_length = '22um', + bridge_width = '7.5um', + inner_length = '8um', + outter_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='component') + """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 + outter_length = p.outter_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 + inner_length/2, 0) + left_inside = draw.translate(left_inside, -(crossover_length/2 + inner_length/2),0) + + inside_struct = draw.union(left_inside, right_inside) + + # Make the outter square structure + left_outside = draw.rectangle(outter_length, outter_length, 0, 0) + right_outside = draw.translate(left_outside, crossover_length/2 + inner_length/2, 0) + left_outside = draw.translate(left_outside, -(crossover_length/2 + inner_length/2),0) + + bridge_struct = draw.union(bridge, left_outside, right_outside) + + # Make the bridge structure + bridge = draw.rectangle(crossover_length, bridge_width, 0,0) + + ### 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, left_inside, right_inside = 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) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index c6e2e7670..668ad22c0 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -33,6 +33,7 @@ import numpy as np from qiskit_metal.renderers.renderer_base import QRenderer +from airbridge import Airbridge_forGDS from qiskit_metal.renderers.renderer_gds.make_cheese import Cheesing from qiskit_metal.toolbox_metal.parsing import is_true from qiskit_metal import draw @@ -212,6 +213,19 @@ class QGDSRenderer(QRenderer): # handle is 8191. max_points='199', + # Airbriding + airbridge=Dict( + # Setup geometrical style of airbridge + geometry=Dict( + # Skeleton of airbridge in QComponent form, + qcomponent_base=Airbridge_forGDS, + # + options=dict(crossover_length='22um') + ), + # Spacing between centers of each airbridge. + bridge_pitch='100um' + ), + # Cheesing is denoted by each chip and layer. cheese=Dict( #Cheesing is NOT completed @@ -288,7 +302,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, @@ -1096,6 +1111,69 @@ def new_gds_library(self) -> gdspy.GdsLibrary: return self.lib + # Airbriding + + 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) + + for chip_layer in layers_in_chip: + 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 custom behavior. + # You will also have to update the self.default_options. + self._apply_uniform_airbridging(minx, + miny, + maxx, + maxy, + chip_name) + + def _apply_uniform_airbridging(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 also a + wrapper for Airbridging.apply_uniform_airbridging(...). + + 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. + + Returns: + lib (gdspy.GdsLibrary): Holds all of the cells for export. + """ + self.options.airbridge.qcomponent_base + self.options.airbridge.options + airbridging = Airbridging(deisgn=self.design, + lib=self.lib, + minx=minx, + miny=miny, + maxx=maxx, + maxy=maxy, + chip_name=chip_name, + precision=self.options.precision) + lib = airbridging.apply_uniform_airbridging(custom_qcomponent=self.options.airbridge.geometry.qcomponent_base, + qcomponent_options=self.options.airbridge.geometry.options, + bridge_pitch=self.options.airbridge.bridge_pitch) + return lib + + # Cheesing + def _check_cheese(self, chip: str, layer: int) -> int: """Examine the option for cheese_view_in_file. @@ -2162,6 +2240,8 @@ def export_to_gds(self, # Create self.lib and populate path and poly. self._populate_poly_path_for_export() + self._populate_airbridge() + # Add no-cheese MultiPolygon to # self.chip_info[chip_name][chip_layer]['no_cheese'], # if self.options requests the layer. diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py new file mode 100644 index 000000000..2d2b6b9aa --- /dev/null +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -0,0 +1,237 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2017, 2021. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. +""" For GDS export, separate the logic for airbridging.""" + +import gdspy +import shapely +import numpy as np + +from qiskit_metal.qlibrary.core import QComponent +from airbridge import Airbridge + + +class Airbridging: + + def __init__(self, + design: 'QDesign', + lib: gdspy.GdsLibrary, + minx: float, + miny: float, + maxx: float, + maxy: float, + chip_name: str, + precision: float): + # Design variables + self.design = design + self.lib = lib + + # Chip setup variables + self.minx = minx + self.miny = miny + self.maxx = maxx + self.maxy = maxy + self.chip_name = chip_name + self.precision = precision + + + @property + def cpws_with_ab(self) -> 'DataFrame': + ''' + QGeometry of CPWs w/ airbridges + + Returns: + cpws_df (DataFrame): QGeometry of CPWs w/ airbridges + ''' + path_qgeom = self.design.qgeometry.tables['path'] + cpws_df = path_qgeom[path_qgeom['gds_make_airbridge'] == True] + return cpws_df + + #### TODO: still working on this #### + def apply_uniform_airbridging(self, + custom_qcomponent: 'QComponent', + qcomponent_options: dict, + bridge_pitch: float, + ) -> gdspy.GdsLibrary: + # Get shapley cutout of airbridges + shapely_geom = self.extract_shapely_from_unrendered_qcomponent(custom_qcomponent=custom_qcomponent, + qcomponent_options=qcomponent_options) + + # Place the airbridges + for cpw_qgeom in self.cpws_with_ab: + cpw_name = cpw_qgeom['name'] + self.find_ab_placement(cpw_name=cpw_name, + bridge_minimum_spacing=, + bridge_pitch=, + precision=self.precision) + + pass + return self.lib + + + def find_uniform_ab_placement(self, + cpw_name: str, + bridge_minimum_spacing: float, + bridge_pitch: float, + precision: int = 12) -> list[tuple[float, float, float]]: + ''' + Determines where to place the wirebonds given a CPW. + + Inputs: + cpw_name (str): Name of cpw to find airbridge placements. + bridge_minimum_spacing: (float) -- Minimum spacing from corners. Units in mm. + bridge_pitch: (float, in units mm) -- Spacing between the centers of each bridge. Units in mm. + precision: (int, optional) -- How precise did you define your CPWs? + This parameter is meant to take care of floating point errors. + References number of decimal points relative to millimeters. + + Returns: + ab_placements (list[tuple]): Where the airbridges should be placed given `cpw_name`. + + Data structure is in the form of list of tuples + [(x0, y0, theta0), + (x1, y1, theta1), + ..., + (xn, yn, thetan))] + + Units: + - x, y, new_crossover_length are in mm + - theta is in degrees + ''' + target_cpw = self.design.components[cpw_name] + + points = target_cpw.get_points() + ab_placements = [] + points_theta = [] + + fillet = self.design.parse_value(target_cpw.options.fillet) + + ### Handles all the straight sections ### + for i in range(len(points)-1): + # Set up parameters for this calculation + pos_i = points[i] + pos_f = points[i + 1] + + x0 = round(pos_i[0],precision) + y0 = round(pos_i[1],precision) + xf = round(pos_f[0],precision) + yf = round(pos_f[1],precision) + + dl = (xf - x0, yf - y0) + dx = dl[0] + dy = dl[1] + + + theta = np.arctan2(dy,dx) + mag_dl = np.sqrt(dx**2 + dy**2) + lprime = mag_dl - 2 * self.BRS1 + + # Now implement logic to uphold the LL design rules + ## Determine what BRS1 should be. It must be >= 0.005 (5um) + + if fillet > self.BRS1: + lprime = mag_dl - 2 * fillet + else: + lprime = mag_dl - 2 * self.BRS1 + n = 1 #refers to the number of bridges you've already placed + #Asking should I place another? If true place another one. + while (lprime) >= (n * bridge_pitch): + n += 1 + + mu_x = (xf + x0)/2 + mu_y = (yf + y0)/2 + + x = np.array([i * bridge_pitch * np.cos(theta) for i in range(n)]) + y = np.array([i * bridge_pitch * np.sin(theta) for i in range(n)]) + + x = (x - np.average(x)) + mu_x + y = (y - np.average(y)) + mu_y + + for i in range(n): + ab_placements.append((x[i],y[i], np.degrees(theta), None)) + + #This is for the corner points + points_theta.append(theta) + + ### This handles all the corner / turning sections ### + # First check to see if any turns exists + if (len(points) > 2): + corner_points = points_theta[1:-1] + for i in range(len(corner_points)+1): + + # First check to see if we should + # even make an airbridge at this corner + pos_i = points[i] + pos_f = points[i + 1] + + x0 = round(pos_i[0],precision) + y0 = round(pos_i[1],precision) + xf = round(pos_f[0],precision) + yf = round(pos_f[1],precision) + + mag_dl = np.sqrt((xf-x0)**2 + (yf-y0)**2) + + if mag_dl < fillet or mag_dl < self.BRS1: + continue + + # Now that we only have real turns + # let's find the center trace of to align the wirebonds + theta_f = points_theta[i + 1] + theta_i = points_theta[i] + + dx = np.cos(theta_i) - np.cos(theta_f) + dy = np.sin(theta_i) - np.sin(theta_f) + + theta = np.arctan2(dy, dx) + + distance_circle_box_x = fillet * (1-np.abs(np.cos(theta))) + distance_circle_box_y = fillet * (1-np.abs(np.sin(theta))) + + theta_avg = (theta_f + theta_i)/2 + + x = points[i + 1][0] - distance_circle_box_x * np.sign(np.cos(theta)) + y = points[i + 1][1] - distance_circle_box_y * np.sign(np.sin(theta)) + + ab_placements.append((x, y, np.degrees(theta_avg))) + + return ab_placements + + def extract_shapely_from_unrendered_qcomponent(self, + custom_qcomponent: 'QComponent', + qcomponent_options: dict): + ''' + + Args: + custom_qcomponent (QComponent): Class of QComponent, not called / instantiated. + qcomponent_options (dict): Geometrical options for cusotm_qcomponent. In structure of cusotm_qcomponent.default_options. + shapely_geometries (list[shapley]) + ''' + # Chck you put in a QComponent + if not issubclass(custom_qcomponent, QComponent): + raise ValueError('`custom_qcomponent` must be a child of `QComponent`.') + + # Make a name which won't interfer w/ other components + test_name = 'initial_name' + all_component_names = self.design.component.keys() + while test_name in all_component_names: + test_name += '1' + + # Temporarily render in QComponent + qcomponent_obj = custom_qcomponent(self.design, test_name, options=qcomponent_options) + # Extract shapley data + shapely_geometries = qcomponent_obj.qgeometry_table('poly') + # Delete it + qcomponent_obj.delete() + + return shapely_geometries + From 7d448378eff11672645ad155366514e4c07ca51e Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 16:47:06 -1000 Subject: [PATCH 02/57] more airbridge stuff --- .../renderers/renderer_gds/gds_renderer.py | 26 ++++--- .../renderers/renderer_gds/make_airbridge.py | 77 +++++++++++-------- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 668ad22c0..5b4d69d6f 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1111,8 +1111,8 @@ def new_gds_library(self) -> gdspy.GdsLibrary: return self.lib - # Airbriding - + ### Start of Airbridging + def _populate_airbridge(self): """ Main function to make airbridges. This is called in `self.export_to_gds()`. @@ -1128,7 +1128,7 @@ def _populate_airbridge(self): # 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 custom behavior. + # add an if/else statement here to check for custom behavior. # You will also have to update the self.default_options. self._apply_uniform_airbridging(minx, miny, @@ -1144,7 +1144,7 @@ def _apply_uniform_airbridging(self, chip_name: str): """ Apply airbridges to all `path` elements which have - options.gds_make_airbridge = True. This is also a + options.gds_make_airbridge = True. This is a wrapper for Airbridging.apply_uniform_airbridging(...). Args: @@ -1153,9 +1153,6 @@ def _apply_uniform_airbridging(self, maxx (float): Chip maximum x location. maxy (float): chip maximum y location. chip_name (str): User defined chip name. - - Returns: - lib (gdspy.GdsLibrary): Holds all of the cells for export. """ self.options.airbridge.qcomponent_base self.options.airbridge.options @@ -1167,12 +1164,13 @@ def _apply_uniform_airbridging(self, maxy=maxy, chip_name=chip_name, precision=self.options.precision) - lib = airbridging.apply_uniform_airbridging(custom_qcomponent=self.options.airbridge.geometry.qcomponent_base, - qcomponent_options=self.options.airbridge.geometry.options, - bridge_pitch=self.options.airbridge.bridge_pitch) - return lib + airbridging.apply_uniform_airbridging(custom_qcomponent=self.options.airbridge.geometry.qcomponent_base, + qcomponent_options=self.options.airbridge.geometry.options, + bridge_pitch=self.options.airbridge.bridge_pitch) - # Cheesing + ### End of Airbridging + + ### Start of Cheesing def _check_cheese(self, chip: str, layer: int) -> int: """Examine the option for cheese_view_in_file. @@ -1559,6 +1557,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. @@ -2240,6 +2240,8 @@ 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 diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 2d2b6b9aa..7f781e700 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -44,7 +44,6 @@ def __init__(self, self.chip_name = chip_name self.precision = precision - @property def cpws_with_ab(self) -> 'DataFrame': ''' @@ -57,33 +56,36 @@ def cpws_with_ab(self) -> 'DataFrame': cpws_df = path_qgeom[path_qgeom['gds_make_airbridge'] == True] return cpws_df - #### TODO: still working on this #### def apply_uniform_airbridging(self, custom_qcomponent: 'QComponent', qcomponent_options: dict, - bridge_pitch: float, + bridge_pitch: str, + bridge_minimum_spacing: str, ) -> gdspy.GdsLibrary: + + bridge_pitch = self.design.parse_value(bridge_pitch) + bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) + # Get shapley cutout of airbridges - shapely_geom = self.extract_shapely_from_unrendered_qcomponent(custom_qcomponent=custom_qcomponent, + ab_shapely = self.extract_shapely_from_unrendered_qcomponent(custom_qcomponent=custom_qcomponent, qcomponent_options=qcomponent_options) # Place the airbridges for cpw_qgeom in self.cpws_with_ab: cpw_name = cpw_qgeom['name'] - self.find_ab_placement(cpw_name=cpw_name, - bridge_minimum_spacing=, - bridge_pitch=, - precision=self.precision) - - pass + ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, + bridge_pitch=bridge_pitch, + bridge_minimum_spacing=bridge_minimum_spacing, + precision=self.precision) + self.ab_placement_to_gds(ab_placement, ab_shapely) + return self.lib - def find_uniform_ab_placement(self, cpw_name: str, - bridge_minimum_spacing: float, bridge_pitch: float, - precision: int = 12) -> list[tuple[float, float, float]]: + bridge_minimum_spacing: float, + precision: int) -> list[tuple[float, float, float]]: ''' Determines where to place the wirebonds given a CPW. @@ -96,7 +98,7 @@ def find_uniform_ab_placement(self, References number of decimal points relative to millimeters. Returns: - ab_placements (list[tuple]): Where the airbridges should be placed given `cpw_name`. + ab_placements (list[tuple[float, float, float]]): Where the airbridges should be placed for given `cpw_name`. Data structure is in the form of list of tuples [(x0, y0, theta0), @@ -105,8 +107,9 @@ def find_uniform_ab_placement(self, (xn, yn, thetan))] Units: - - x, y, new_crossover_length are in mm - - theta is in degrees + - x (float): Units mm + - y (float): Units mm + - theta (float): Units degrees ''' target_cpw = self.design.components[cpw_name] @@ -122,10 +125,10 @@ def find_uniform_ab_placement(self, pos_i = points[i] pos_f = points[i + 1] - x0 = round(pos_i[0],precision) - y0 = round(pos_i[1],precision) - xf = round(pos_f[0],precision) - yf = round(pos_f[1],precision) + x0 = round(pos_i[0] / precision) * precision + y0 = round(pos_i[1] / precision) * precision + xf = round(pos_f[0] / precision) * precision + yf = round(pos_f[1] / precision) * precision dl = (xf - x0, yf - y0) dx = dl[0] @@ -134,15 +137,12 @@ def find_uniform_ab_placement(self, theta = np.arctan2(dy,dx) mag_dl = np.sqrt(dx**2 + dy**2) - lprime = mag_dl - 2 * self.BRS1 - - # Now implement logic to uphold the LL design rules - ## Determine what BRS1 should be. It must be >= 0.005 (5um) - - if fillet > self.BRS1: + lprime = mag_dl - 2 * bridge_minimum_spacing + + if fillet > bridge_minimum_spacing: lprime = mag_dl - 2 * fillet else: - lprime = mag_dl - 2 * self.BRS1 + lprime = mag_dl - 2 * bridge_minimum_spacing n = 1 #refers to the number of bridges you've already placed #Asking should I place another? If true place another one. while (lprime) >= (n * bridge_pitch): @@ -174,14 +174,14 @@ def find_uniform_ab_placement(self, pos_i = points[i] pos_f = points[i + 1] - x0 = round(pos_i[0],precision) - y0 = round(pos_i[1],precision) - xf = round(pos_f[0],precision) - yf = round(pos_f[1],precision) + x0 = round(pos_i[0] / precision) * precision + y0 = round(pos_i[1] / precision) * precision + xf = round(pos_f[0] / precision) * precision + yf = round(pos_f[1] / precision) * precision mag_dl = np.sqrt((xf-x0)**2 + (yf-y0)**2) - if mag_dl < fillet or mag_dl < self.BRS1: + if mag_dl < fillet or mag_dl < bridge_minimum_spacing: continue # Now that we only have real turns @@ -206,19 +206,30 @@ def find_uniform_ab_placement(self, return ab_placements + def ab_placement_to_gds(ab_placement: list[float], + ab_shapely: 'Shapely'): + for x, y, theta in ab_placement: + pass + def extract_shapely_from_unrendered_qcomponent(self, custom_qcomponent: 'QComponent', qcomponent_options: dict): ''' + Extracts the shapely data from a child of QComponent. + Must have QComponent.make() Args: custom_qcomponent (QComponent): Class of QComponent, not called / instantiated. qcomponent_options (dict): Geometrical options for cusotm_qcomponent. In structure of cusotm_qcomponent.default_options. + + Returns: shapely_geometries (list[shapley]) ''' - # Chck you put in a QComponent + # Chck you put in a QComponent w/ self.make() functionality if not issubclass(custom_qcomponent, QComponent): raise ValueError('`custom_qcomponent` must be a child of `QComponent`.') + if not hasattr(custom_qcomponent, 'make'): + raise AttributeError('`custom_qcomponent` must have `make()` method') # Make a name which won't interfer w/ other components test_name = 'initial_name' From b1d75e5ad25c7fdc184514c00bd407961c6a9352 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 16:49:07 -1000 Subject: [PATCH 03/57] correct pathing for Airbridge_forGDS --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 5b4d69d6f..665e5ba9e 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -33,7 +33,7 @@ import numpy as np from qiskit_metal.renderers.renderer_base import QRenderer -from airbridge import Airbridge_forGDS +from qiskit_metal.renderers.renderer_gds.airbridge import Airbridge_forGDS from qiskit_metal.renderers.renderer_gds.make_cheese import Cheesing from qiskit_metal.toolbox_metal.parsing import is_true from qiskit_metal import draw From ba1a21de71bd3be1ff20d4fcc4eb5844688fd7df Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:40:23 -1000 Subject: [PATCH 04/57] should be working??? time to test --- .../renderers/renderer_gds/gds_renderer.py | 22 +++++--- .../renderers/renderer_gds/make_airbridge.py | 52 +++++++++++++------ 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 665e5ba9e..4543cffa0 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1130,13 +1130,13 @@ def _populate_airbridge(self): # 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._apply_uniform_airbridging(minx, + self._make_uniform_airbridging_df(minx, miny, maxx, maxy, chip_name) - def _apply_uniform_airbridging(self, + def _make_uniform_airbridging_df(self, minx: float, miny: float, maxx: float, @@ -1145,7 +1145,7 @@ def _apply_uniform_airbridging(self, """ Apply airbridges to all `path` elements which have options.gds_make_airbridge = True. This is a - wrapper for Airbridging.apply_uniform_airbridging(...). + wrapper for Airbridging.make_uniform_airbridging_df(...). Args: minx (float): Chip minimum x location. @@ -1164,10 +1164,18 @@ def _apply_uniform_airbridging(self, maxy=maxy, chip_name=chip_name, precision=self.options.precision) - airbridging.apply_uniform_airbridging(custom_qcomponent=self.options.airbridge.geometry.qcomponent_base, - qcomponent_options=self.options.airbridge.geometry.options, - bridge_pitch=self.options.airbridge.bridge_pitch) - + 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) + + for _, row in airbridges_df.iterrows(): + ab_component_multi_poly = row['MultiPoly'] + ab_component_layer = row['layer'] + self._multipolygon_to_gds(multi_poly=ab_component_multi_poly, + layer=ab_component_layer, + datatype=0, + no_cheese_buffer=0) + ### End of Airbridging ### Start of Cheesing diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 7f781e700..de7d7d456 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -16,6 +16,7 @@ import gdspy import shapely import numpy as np +import pandas as pd from qiskit_metal.qlibrary.core import QComponent from airbridge import Airbridge @@ -56,18 +57,18 @@ def cpws_with_ab(self) -> 'DataFrame': cpws_df = path_qgeom[path_qgeom['gds_make_airbridge'] == True] return cpws_df - def apply_uniform_airbridging(self, + def make_uniform_airbridging_df(self, custom_qcomponent: 'QComponent', qcomponent_options: dict, bridge_pitch: str, bridge_minimum_spacing: str, - ) -> gdspy.GdsLibrary: + ) -> 'pd.DataFrame': bridge_pitch = self.design.parse_value(bridge_pitch) bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) # Get shapley cutout of airbridges - ab_shapely = self.extract_shapely_from_unrendered_qcomponent(custom_qcomponent=custom_qcomponent, + ab_qgeom = self.extract_qgeom_from_unrendered_qcomp(custom_qcomponent=custom_qcomponent, qcomponent_options=qcomponent_options) # Place the airbridges @@ -77,9 +78,9 @@ def apply_uniform_airbridging(self, bridge_pitch=bridge_pitch, bridge_minimum_spacing=bridge_minimum_spacing, precision=self.precision) - self.ab_placement_to_gds(ab_placement, ab_shapely) + airbridge_df = self.ab_placement_to_df(ab_placement, ab_qgeom) - return self.lib + return airbridge_df def find_uniform_ab_placement(self, cpw_name: str, @@ -206,16 +207,35 @@ def find_uniform_ab_placement(self, return ab_placements - def ab_placement_to_gds(ab_placement: list[float], - ab_shapely: 'Shapely'): - for x, y, theta in ab_placement: - pass + def ab_placement_to_df(ab_placement: list[float], + qgeom_table: 'geopandas.geodataframe.GeoDataFrame') -> pd.DataFrame: + ''' + With a base airbridge shape, find the shapely data for placing all airbridges. + + ''' + shapley_data_all = [] + layer_data_all = [] + for _, component in qgeom_table.iterrows(): + + for x, y, theta in ab_placement: + # Extract shapely data, and move to proper spot + shapley_data = component['geometry'] + shapley_data = draw.rotate(shapley_data, theta, origin=(0,0)) + shapley_data = draw.translate(shapley_data, x, y) + + # Extract layer info + layer = component['layer'] - def extract_shapely_from_unrendered_qcomponent(self, + airbridge_df = pd.DataFrame({'geometry': shapley_data_all, + 'layer' : layer_data_all}) + + return airbridge_df + + def extract_qgeom_from_unrendered_qcomp(self, custom_qcomponent: 'QComponent', - qcomponent_options: dict): + qcomponent_options: dict) -> shapely.geometry.MultiPolygon: ''' - Extracts the shapely data from a child of QComponent. + Extracts the qgeometry table from a child of QComponent. Must have QComponent.make() Args: @@ -223,7 +243,7 @@ def extract_shapely_from_unrendered_qcomponent(self, qcomponent_options (dict): Geometrical options for cusotm_qcomponent. In structure of cusotm_qcomponent.default_options. Returns: - shapely_geometries (list[shapley]) + custom_qcomponent_multipolygon (shapely.geometry.MultiPolygon) ''' # Chck you put in a QComponent w/ self.make() functionality if not issubclass(custom_qcomponent, QComponent): @@ -240,9 +260,11 @@ def extract_shapely_from_unrendered_qcomponent(self, # Temporarily render in QComponent qcomponent_obj = custom_qcomponent(self.design, test_name, options=qcomponent_options) # Extract shapley data - shapely_geometries = qcomponent_obj.qgeometry_table('poly') + qgeom_table = qcomponent_obj.qgeometry_table('poly') # Delete it qcomponent_obj.delete() - return shapely_geometries + + + return qgeom_table From 2e1b95594ec4d34a2e3581f617a30305bd449eef Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:47:24 -1000 Subject: [PATCH 05/57] added pathing for Airbridging --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 1 + qiskit_metal/renderers/renderer_gds/make_airbridge.py | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 4543cffa0..2cc8637f8 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -34,6 +34,7 @@ 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 diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index de7d7d456..e3f9a502c 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -19,8 +19,6 @@ import pandas as pd from qiskit_metal.qlibrary.core import QComponent -from airbridge import Airbridge - class Airbridging: @@ -62,7 +60,7 @@ def make_uniform_airbridging_df(self, qcomponent_options: dict, bridge_pitch: str, bridge_minimum_spacing: str, - ) -> 'pd.DataFrame': + ) -> pd.DataFrame: bridge_pitch = self.design.parse_value(bridge_pitch) bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) From 6ec383781c99309fc33c3c26666f1ac5894a9b1f Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:48:47 -1000 Subject: [PATCH 06/57] fixed typo in make_uniform_airbridging --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 2cc8637f8..ca2855975 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1157,7 +1157,7 @@ def _make_uniform_airbridging_df(self, """ self.options.airbridge.qcomponent_base self.options.airbridge.options - airbridging = Airbridging(deisgn=self.design, + airbridging = Airbridging(design=self.design, lib=self.lib, minx=minx, miny=miny, From 03a30f380f24ff0ad71e3c0a322df020ecb5de66 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:51:42 -1000 Subject: [PATCH 07/57] added bridge_minimum_spacing to default_options --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index ca2855975..a74d63867 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -224,7 +224,10 @@ class QGDSRenderer(QRenderer): options=dict(crossover_length='22um') ), # Spacing between centers of each airbridge. - bridge_pitch='100um' + bridge_pitch='100um', + # Minimum spacing between each airbridge, + # this number of fabrication guideline based + bridge_minimum_spacing='5um', ), # Cheesing is denoted by each chip and layer. @@ -1167,7 +1170,8 @@ def _make_uniform_airbridging_df(self, 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_pitch=self.options.airbridge.bridge_pitch, + bridge_minimum_spacing=self.options.airbridge.bridge_minimum_spacing) for _, row in airbridges_df.iterrows(): ab_component_multi_poly = row['MultiPoly'] From 7b9632a8ce2982b32b1be743c94d81747a8db344 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:52:48 -1000 Subject: [PATCH 08/57] fixed typo in extract_qgeom_from_unrendered_qcomp --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index e3f9a502c..df7b73893 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -251,7 +251,7 @@ def extract_qgeom_from_unrendered_qcomp(self, # Make a name which won't interfer w/ other components test_name = 'initial_name' - all_component_names = self.design.component.keys() + all_component_names = self.design.components.keys() while test_name in all_component_names: test_name += '1' From afbd4578a05d1029ab29fefd8edc6f996f3b4ee8 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:54:36 -1000 Subject: [PATCH 09/57] fixed variable assignment error in Airbridge_forGDS --- qiskit_metal/renderers/renderer_gds/airbridge.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py index 84b027caf..67589cff4 100644 --- a/qiskit_metal/renderers/renderer_gds/airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -52,10 +52,9 @@ def make(self): right_outside = draw.translate(left_outside, crossover_length/2 + inner_length/2, 0) left_outside = draw.translate(left_outside, -(crossover_length/2 + inner_length/2),0) - bridge_struct = draw.union(bridge, left_outside, right_outside) - # 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] From 61761c8c83568e36d6ecd00af37260a7ca7fbb2d Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:56:00 -1000 Subject: [PATCH 10/57] typo in Airbridge_forGDS --- qiskit_metal/renderers/renderer_gds/airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py index 67589cff4..f03ab6411 100644 --- a/qiskit_metal/renderers/renderer_gds/airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -60,7 +60,7 @@ def make(self): 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, left_inside, right_inside = final_design + 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) From bb7514c29b8751d000c505192060133b60aa9d6a Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:58:36 -1000 Subject: [PATCH 11/57] fixed typo in make_uniform_airbridging_df --- qiskit_metal/renderers/renderer_gds/airbridge.py | 2 +- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py index f03ab6411..d056ebfa8 100644 --- a/qiskit_metal/renderers/renderer_gds/airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -9,7 +9,7 @@ class Airbridge_forGDS(QComponent): This QComponent should NOT be rendered for EM simulation. Default Options: - * crossover_length: '20um' -- Distance between the two outter squares (aka bridge length). + * crossover_length: '22um' -- Distance between the two outter 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. diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index df7b73893..b9249fea5 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -61,7 +61,11 @@ def make_uniform_airbridging_df(self, bridge_pitch: str, bridge_minimum_spacing: str, ) -> pd.DataFrame: - + """ + Makes the uniform airbridging dataframe + + + """ bridge_pitch = self.design.parse_value(bridge_pitch) bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) @@ -70,7 +74,7 @@ def make_uniform_airbridging_df(self, qcomponent_options=qcomponent_options) # Place the airbridges - for cpw_qgeom in self.cpws_with_ab: + for _, cpw_qgeom in self.cpws_with_ab.itter.iterrows(): cpw_name = cpw_qgeom['name'] ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, bridge_pitch=bridge_pitch, From e2d5dc962380c330d0100dfbf9be1a503c3dd15f Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 17:59:58 -1000 Subject: [PATCH 12/57] fixed typo in make_uniform_airbridging_df --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index b9249fea5..8bb467f03 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -74,7 +74,7 @@ def make_uniform_airbridging_df(self, qcomponent_options=qcomponent_options) # Place the airbridges - for _, cpw_qgeom in self.cpws_with_ab.itter.iterrows(): + for _, cpw_qgeom in self.cpws_with_ab.iterrows(): cpw_name = cpw_qgeom['name'] ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, bridge_pitch=bridge_pitch, From 3cc56b2db2f5bf40950589360475f89ed0d2b884 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:14:50 -1000 Subject: [PATCH 13/57] fixed cpw_with_ab property --- .../renderers/renderer_gds/make_airbridge.py | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 8bb467f03..58b3d333e 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -44,16 +44,24 @@ def __init__(self, self.precision = precision @property - def cpws_with_ab(self) -> 'DataFrame': + def cpws_with_ab(self) -> list[str]: ''' QGeometry of CPWs w/ airbridges Returns: - cpws_df (DataFrame): QGeometry of CPWs w/ airbridges + cpw_names (DataFrame): QGeometry of CPWs w/ airbridges ''' + cpw_names = [] + path_qgeom = self.design.qgeometry.tables['path'] cpws_df = path_qgeom[path_qgeom['gds_make_airbridge'] == True] - return cpws_df + unique_id = set(list(cpws_df)) + + for cpw_name, cpw_id in self.design.all_component_names_id(): + if cpw_id in unique_id: + cpw_names.append(cpw_id) + + return cpw_names def make_uniform_airbridging_df(self, custom_qcomponent: 'QComponent', @@ -64,7 +72,14 @@ def make_uniform_airbridging_df(self, """ Makes the uniform airbridging dataframe + Args: + custom_qcomponent (QComponent) + qcomponent_options (dict) + bridge_pitch (str) + bridge_minimum_spacing (str): + Returns: + airbridge_df (pd.DataFrame) """ bridge_pitch = self.design.parse_value(bridge_pitch) bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) @@ -74,8 +89,7 @@ def make_uniform_airbridging_df(self, qcomponent_options=qcomponent_options) # Place the airbridges - for _, cpw_qgeom in self.cpws_with_ab.iterrows(): - cpw_name = cpw_qgeom['name'] + for cpw_name in self.cpws_with_ab: ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, bridge_pitch=bridge_pitch, bridge_minimum_spacing=bridge_minimum_spacing, From 63c1d6ff25603da80143e326abe969a0011d0228 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:18:44 -1000 Subject: [PATCH 14/57] fixed self reassignment of ab_placement_to_df --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 58b3d333e..51cae2d99 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -89,13 +89,17 @@ def make_uniform_airbridging_df(self, qcomponent_options=qcomponent_options) # Place the airbridges + ab_df_list = [] for cpw_name in self.cpws_with_ab: ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, bridge_pitch=bridge_pitch, bridge_minimum_spacing=bridge_minimum_spacing, precision=self.precision) - airbridge_df = self.ab_placement_to_df(ab_placement, ab_qgeom) + airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement, ab_qgeom) + ab_df_list.append(airbridge_df_for_cpw) + airbridge_df = pd.concat(ab_df_list) + return airbridge_df def find_uniform_ab_placement(self, From 58249963de59bfe7bb55dbfdce444526502c979b Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:34:11 -1000 Subject: [PATCH 15/57] fixed bug where ab_placement_to_df didn't save data --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 51cae2d99..2415e1f63 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -95,9 +95,10 @@ def make_uniform_airbridging_df(self, bridge_pitch=bridge_pitch, bridge_minimum_spacing=bridge_minimum_spacing, precision=self.precision) - airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement, ab_qgeom) - ab_df_list.append(airbridge_df_for_cpw) - + airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement=ab_placement, + ab_qgeom=ab_qgeom) + ab_df_list.append(airbridge_df_for_cpw.copy()) + airbridge_df = pd.concat(ab_df_list) return airbridge_df @@ -246,6 +247,10 @@ def ab_placement_to_df(ab_placement: list[float], # Extract layer info layer = component['layer'] + # Add data to DataFrame + shapley_data_all.append(shapley_data) + layer_data_all.append(layer) + airbridge_df = pd.DataFrame({'geometry': shapley_data_all, 'layer' : layer_data_all}) From 8d64e7f6c3758e2ee6dd94d2f006ed02f77b2027 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:37:44 -1000 Subject: [PATCH 16/57] fixed typo in make_uniform_airbridging_df --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 2415e1f63..cc1732761 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -96,7 +96,7 @@ def make_uniform_airbridging_df(self, bridge_minimum_spacing=bridge_minimum_spacing, precision=self.precision) airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement=ab_placement, - ab_qgeom=ab_qgeom) + qgeom_table=ab_qgeom) ab_df_list.append(airbridge_df_for_cpw.copy()) airbridge_df = pd.concat(ab_df_list) From 73178034402bf0cb0656701268bde972e30c0ebd Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:38:53 -1000 Subject: [PATCH 17/57] test --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index cc1732761..56b4c442f 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -67,8 +67,7 @@ def make_uniform_airbridging_df(self, custom_qcomponent: 'QComponent', qcomponent_options: dict, bridge_pitch: str, - bridge_minimum_spacing: str, - ) -> pd.DataFrame: + bridge_minimum_spacing: str) -> pd.DataFrame: """ Makes the uniform airbridging dataframe @@ -228,8 +227,7 @@ def find_uniform_ab_placement(self, return ab_placements - def ab_placement_to_df(ab_placement: list[float], - qgeom_table: 'geopandas.geodataframe.GeoDataFrame') -> pd.DataFrame: + def ab_placement_to_df(ab_placement: list[float], qgeom_table: 'pd.DataFrame') -> pd.DataFrame: ''' With a base airbridge shape, find the shapely data for placing all airbridges. From c134e0dfc918aff37f5b710a951437425e624d65 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:43:48 -1000 Subject: [PATCH 18/57] forgot to import draw in make_airbridge.py --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 56b4c442f..ef82f77e7 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -18,6 +18,8 @@ import numpy as np import pandas as pd +from qiskit_metal import draw + from qiskit_metal.qlibrary.core import QComponent class Airbridging: @@ -96,7 +98,7 @@ def make_uniform_airbridging_df(self, precision=self.precision) airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement=ab_placement, qgeom_table=ab_qgeom) - ab_df_list.append(airbridge_df_for_cpw.copy()) + ab_df_list.append(airbridge_df_for_cpw) airbridge_df = pd.concat(ab_df_list) From 0cdc8c55068db04e18f6a327fcece2b202510c5f Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:56:00 -1000 Subject: [PATCH 19/57] fixed typo in cpws_with_ab --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index ef82f77e7..5c095a70a 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -57,7 +57,7 @@ def cpws_with_ab(self) -> list[str]: path_qgeom = self.design.qgeometry.tables['path'] cpws_df = path_qgeom[path_qgeom['gds_make_airbridge'] == True] - unique_id = set(list(cpws_df)) + unique_id = set(list(cpws_df['component'])) for cpw_name, cpw_id in self.design.all_component_names_id(): if cpw_id in unique_id: From 5f7017884f70d5f071140f657fcf83c2a8f55b24 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 18:58:36 -1000 Subject: [PATCH 20/57] fixed typo in cpws_with_ab --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 5c095a70a..efae357ab 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -61,7 +61,7 @@ def cpws_with_ab(self) -> list[str]: for cpw_name, cpw_id in self.design.all_component_names_id(): if cpw_id in unique_id: - cpw_names.append(cpw_id) + cpw_names.append(cpw_name) return cpw_names From b5d539610e4eab240a9607d3df0668fefc0fb769 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:01:24 -1000 Subject: [PATCH 21/57] fixed find_uniform_ab_placement --- .../renderers/renderer_gds/make_airbridge.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index efae357ab..4f516cbf2 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -108,7 +108,7 @@ def find_uniform_ab_placement(self, cpw_name: str, bridge_pitch: float, bridge_minimum_spacing: float, - precision: int) -> list[tuple[float, float, float]]: + precision: float) -> list[tuple[float, float, float]]: ''' Determines where to place the wirebonds given a CPW. @@ -116,9 +116,9 @@ def find_uniform_ab_placement(self, cpw_name (str): Name of cpw to find airbridge placements. bridge_minimum_spacing: (float) -- Minimum spacing from corners. Units in mm. bridge_pitch: (float, in units mm) -- Spacing between the centers of each bridge. Units in mm. - precision: (int, optional) -- How precise did you define your CPWs? - This parameter is meant to take care of floating point errors. - References number of decimal points relative to millimeters. + precision: (float) -- How precise did you define your CPWs? + This parameter is meant to take care of floating point errors. + References number of decimal points relative to millimeters. Returns: ab_placements (list[tuple[float, float, float]]): Where the airbridges should be placed for given `cpw_name`. @@ -145,8 +145,8 @@ def find_uniform_ab_placement(self, ### Handles all the straight sections ### for i in range(len(points)-1): # Set up parameters for this calculation - pos_i = points[i] - pos_f = points[i + 1] + pos_i = float(points[i]) + pos_f = float(points[i + 1]) x0 = round(pos_i[0] / precision) * precision y0 = round(pos_i[1] / precision) * precision From af264c121e3a6769d5ae8abd11a820060723a779 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:03:58 -1000 Subject: [PATCH 22/57] add float casting to find_uniform_ab_placement --- .../renderers/renderer_gds/make_airbridge.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 4f516cbf2..798d47d7a 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -145,13 +145,13 @@ def find_uniform_ab_placement(self, ### Handles all the straight sections ### for i in range(len(points)-1): # Set up parameters for this calculation - pos_i = float(points[i]) - pos_f = float(points[i + 1]) + pos_i = points[i] + pos_f = points[i + 1] - x0 = round(pos_i[0] / precision) * precision - y0 = round(pos_i[1] / precision) * precision - xf = round(pos_f[0] / precision) * precision - yf = round(pos_f[1] / precision) * precision + x0 = round(float(pos_i[0]) / precision) * precision + y0 = round(float(pos_i[1]) / precision) * precision + xf = round(float(pos_f[0]) / precision) * precision + yf = round(float(pos_f[1]) / precision) * precision dl = (xf - x0, yf - y0) dx = dl[0] @@ -197,10 +197,10 @@ def find_uniform_ab_placement(self, pos_i = points[i] pos_f = points[i + 1] - x0 = round(pos_i[0] / precision) * precision - y0 = round(pos_i[1] / precision) * precision - xf = round(pos_f[0] / precision) * precision - yf = round(pos_f[1] / precision) * precision + x0 = round(float(pos_i[0]) / precision) * precision + y0 = round(float(pos_i[1]) / precision) * precision + xf = round(float(pos_f[0]) / precision) * precision + yf = round(float(pos_f[1]) / precision) * precision mag_dl = np.sqrt((xf-x0)**2 + (yf-y0)**2) From 52eec989dd1045dfa00b10e3e367ecafb000496a Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:07:00 -1000 Subject: [PATCH 23/57] fixed precision error --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 798d47d7a..af1e735f1 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -69,7 +69,8 @@ def make_uniform_airbridging_df(self, custom_qcomponent: 'QComponent', qcomponent_options: dict, bridge_pitch: str, - bridge_minimum_spacing: str) -> pd.DataFrame: + bridge_minimum_spacing: str, + precision: str) -> pd.DataFrame: """ Makes the uniform airbridging dataframe @@ -78,12 +79,14 @@ def make_uniform_airbridging_df(self, qcomponent_options (dict) bridge_pitch (str) bridge_minimum_spacing (str): + precision (str) Returns: airbridge_df (pd.DataFrame) """ bridge_pitch = self.design.parse_value(bridge_pitch) bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) + precision = self.design.parse_value(precision) # Get shapley cutout of airbridges ab_qgeom = self.extract_qgeom_from_unrendered_qcomp(custom_qcomponent=custom_qcomponent, @@ -95,7 +98,7 @@ def make_uniform_airbridging_df(self, ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, bridge_pitch=bridge_pitch, bridge_minimum_spacing=bridge_minimum_spacing, - precision=self.precision) + precision=precision) airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement=ab_placement, qgeom_table=ab_qgeom) ab_df_list.append(airbridge_df_for_cpw) @@ -116,9 +119,9 @@ def find_uniform_ab_placement(self, cpw_name (str): Name of cpw to find airbridge placements. bridge_minimum_spacing: (float) -- Minimum spacing from corners. Units in mm. bridge_pitch: (float, in units mm) -- Spacing between the centers of each bridge. Units in mm. - precision: (float) -- How precise did you define your CPWs? + precision: (float) -- Rounds values to the closest integer multiple of `precision` This parameter is meant to take care of floating point errors. - References number of decimal points relative to millimeters. + Returns: ab_placements (list[tuple[float, float, float]]): Where the airbridges should be placed for given `cpw_name`. From 6e0875c633424d12b947b6594a9a4d1d1bc6915b Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:09:47 -1000 Subject: [PATCH 24/57] reworked self.precision --- .../renderers/renderer_gds/make_airbridge.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index af1e735f1..bc434c91c 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -23,6 +23,13 @@ from qiskit_metal.qlibrary.core import QComponent class Airbridging: + """ + Airbridge for GDS logic + + Args: + precision: (float) -- Rounds values to the closest integer multiple of `precision` + This parameter is meant to take care of floating point errors. + """ def __init__(self, design: 'QDesign', @@ -69,8 +76,7 @@ def make_uniform_airbridging_df(self, custom_qcomponent: 'QComponent', qcomponent_options: dict, bridge_pitch: str, - bridge_minimum_spacing: str, - precision: str) -> pd.DataFrame: + bridge_minimum_spacing: str) -> pd.DataFrame: """ Makes the uniform airbridging dataframe @@ -86,7 +92,6 @@ def make_uniform_airbridging_df(self, """ bridge_pitch = self.design.parse_value(bridge_pitch) bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) - precision = self.design.parse_value(precision) # Get shapley cutout of airbridges ab_qgeom = self.extract_qgeom_from_unrendered_qcomp(custom_qcomponent=custom_qcomponent, @@ -97,8 +102,7 @@ def make_uniform_airbridging_df(self, for cpw_name in self.cpws_with_ab: ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, bridge_pitch=bridge_pitch, - bridge_minimum_spacing=bridge_minimum_spacing, - precision=precision) + bridge_minimum_spacing=bridge_minimum_spacing) airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement=ab_placement, qgeom_table=ab_qgeom) ab_df_list.append(airbridge_df_for_cpw) @@ -110,8 +114,7 @@ def make_uniform_airbridging_df(self, def find_uniform_ab_placement(self, cpw_name: str, bridge_pitch: float, - bridge_minimum_spacing: float, - precision: float) -> list[tuple[float, float, float]]: + bridge_minimum_spacing: float) -> list[tuple[float, float, float]]: ''' Determines where to place the wirebonds given a CPW. @@ -119,10 +122,7 @@ def find_uniform_ab_placement(self, cpw_name (str): Name of cpw to find airbridge placements. bridge_minimum_spacing: (float) -- Minimum spacing from corners. Units in mm. bridge_pitch: (float, in units mm) -- Spacing between the centers of each bridge. Units in mm. - precision: (float) -- Rounds values to the closest integer multiple of `precision` - This parameter is meant to take care of floating point errors. - - + Returns: ab_placements (list[tuple[float, float, float]]): Where the airbridges should be placed for given `cpw_name`. @@ -137,6 +137,8 @@ def find_uniform_ab_placement(self, - y (float): Units mm - theta (float): Units degrees ''' + precision = self.design.parse_value(self.precision) + target_cpw = self.design.components[cpw_name] points = target_cpw.get_points() From 9dd96790601d515af3413900a221b90956b90ad2 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:13:59 -1000 Subject: [PATCH 25/57] forgot to reference self in ab_placement_to_df --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index bc434c91c..7b89991e6 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -234,7 +234,9 @@ def find_uniform_ab_placement(self, return ab_placements - def ab_placement_to_df(ab_placement: list[float], qgeom_table: 'pd.DataFrame') -> pd.DataFrame: + def ab_placement_to_df(self, + ab_placement: list[float], + qgeom_table: 'pd.DataFrame') -> pd.DataFrame: ''' With a base airbridge shape, find the shapely data for placing all airbridges. From 3a8dda3ba0622e186ec6c5d38c58f34c0215eb61 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:18:46 -1000 Subject: [PATCH 26/57] fixed output of find_uniform_ab_placement --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 7b89991e6..e86fea12c 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -186,7 +186,7 @@ def find_uniform_ab_placement(self, y = (y - np.average(y)) + mu_y for i in range(n): - ab_placements.append((x[i],y[i], np.degrees(theta), None)) + ab_placements.append((x[i],y[i], np.degrees(theta))) #This is for the corner points points_theta.append(theta) From ec9dcf4745fd2c4a68b1755197779d5c0c0114cf Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:20:14 -1000 Subject: [PATCH 27/57] fixed keyerror --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index e86fea12c..85128c541 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -258,7 +258,7 @@ def ab_placement_to_df(self, shapley_data_all.append(shapley_data) layer_data_all.append(layer) - airbridge_df = pd.DataFrame({'geometry': shapley_data_all, + airbridge_df = pd.DataFrame({'MultiPoly': shapley_data_all, 'layer' : layer_data_all}) return airbridge_df From bbba1910e1a3238a0984b38c634ab10563be5536 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:22:19 -1000 Subject: [PATCH 28/57] fixed typo in calling _multipolygon_to_gds --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index a74d63867..42aea5e68 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1178,7 +1178,7 @@ def _make_uniform_airbridging_df(self, ab_component_layer = row['layer'] self._multipolygon_to_gds(multi_poly=ab_component_multi_poly, layer=ab_component_layer, - datatype=0, + data_type=0, no_cheese_buffer=0) ### End of Airbridging From 2ca5f96dfa5753663860bf5078f51849ff7d8335 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:23:47 -1000 Subject: [PATCH 29/57] added MultiPoly --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 85128c541..b702c1b7c 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -250,6 +250,7 @@ def ab_placement_to_df(self, shapley_data = component['geometry'] shapley_data = draw.rotate(shapley_data, theta, origin=(0,0)) shapley_data = draw.translate(shapley_data, x, y) + shapley_data = shapely.geometry.MultiPolygon([shapley_data]) # Extract layer info layer = component['layer'] From f599ed074f7563876126ff0ec00048f447839e6b Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:28:06 -1000 Subject: [PATCH 30/57] maybed fixed ab_placement_to_df --- .../renderers/renderer_gds/make_airbridge.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index b702c1b7c..e7a1ed066 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -244,13 +244,12 @@ def ab_placement_to_df(self, shapley_data_all = [] layer_data_all = [] for _, component in qgeom_table.iterrows(): - + shapley_data = component['geometry'] for x, y, theta in ab_placement: # Extract shapely data, and move to proper spot - shapley_data = component['geometry'] - shapley_data = draw.rotate(shapley_data, theta, origin=(0,0)) - shapley_data = draw.translate(shapley_data, x, y) - shapley_data = shapely.geometry.MultiPolygon([shapley_data]) + shapely_copy = draw.rotate(shapley_data, theta, origin=(0,0)) + shapely_copy = draw.translate(shapely_copy, x, y) + shapely_copy = shapely.geometry.MultiPolygon([shapely_copy]) # Extract layer info layer = component['layer'] @@ -266,7 +265,7 @@ def ab_placement_to_df(self, def extract_qgeom_from_unrendered_qcomp(self, custom_qcomponent: 'QComponent', - qcomponent_options: dict) -> shapely.geometry.MultiPolygon: + qcomponent_options: dict) -> 'pd.DataFrame': ''' Extracts the qgeometry table from a child of QComponent. Must have QComponent.make() @@ -276,7 +275,7 @@ def extract_qgeom_from_unrendered_qcomp(self, qcomponent_options (dict): Geometrical options for cusotm_qcomponent. In structure of cusotm_qcomponent.default_options. Returns: - custom_qcomponent_multipolygon (shapely.geometry.MultiPolygon) + qgeom_table (pd.DataFrame) ''' # Chck you put in a QComponent w/ self.make() functionality if not issubclass(custom_qcomponent, QComponent): @@ -297,7 +296,5 @@ def extract_qgeom_from_unrendered_qcomp(self, # Delete it qcomponent_obj.delete() - - return qgeom_table From a184cc81592f0f63be624e88c1bff3b594f8ff37 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:29:10 -1000 Subject: [PATCH 31/57] typo --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index e7a1ed066..5fe7749cf 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -255,7 +255,7 @@ def ab_placement_to_df(self, layer = component['layer'] # Add data to DataFrame - shapley_data_all.append(shapley_data) + shapley_data_all.append(shapely_copy) layer_data_all.append(layer) airbridge_df = pd.DataFrame({'MultiPoly': shapley_data_all, From 48744467bbd985b8a302cb7b3e9257bd723b3ebb Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:46:51 -1000 Subject: [PATCH 32/57] updates self.chip_info --- .../renderers/renderer_gds/gds_renderer.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 42aea5e68..bb8eb665f 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1138,14 +1138,16 @@ def _populate_airbridge(self): miny, maxx, maxy, - chip_name) + chip_name, + chip_layer) def _make_uniform_airbridging_df(self, minx: float, miny: float, maxx: float, maxy: float, - chip_name: str): + chip_name: str, + chip_layer): """ Apply airbridges to all `path` elements which have options.gds_make_airbridge = True. This is a @@ -1176,10 +1178,11 @@ def _make_uniform_airbridging_df(self, for _, row in airbridges_df.iterrows(): ab_component_multi_poly = row['MultiPoly'] ab_component_layer = row['layer'] - self._multipolygon_to_gds(multi_poly=ab_component_multi_poly, - layer=ab_component_layer, - data_type=0, - no_cheese_buffer=0) + airbridge_gds = self._multipolygon_to_gds(multi_poly=ab_component_multi_poly, + layer=ab_component_layer, + data_type=0, + no_cheese_buffer=0) + self.chip_info[chip_name][chip_layer]['no_cheese_gds'] = airbridge_gds ### End of Airbridging From 276269d3b9f7b235519da430a20a8b27bd92ec87 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:55:43 -1000 Subject: [PATCH 33/57] should push to gds --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index bb8eb665f..699e36715 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1175,6 +1175,9 @@ def _make_uniform_airbridging_df(self, bridge_pitch=self.options.airbridge.bridge_pitch, bridge_minimum_spacing=self.options.airbridge.bridge_minimum_spacing) + + top_cell = self.lib.cells[f'TOP_{chip_name}'] + for _, row in airbridges_df.iterrows(): ab_component_multi_poly = row['MultiPoly'] ab_component_layer = row['layer'] @@ -1182,7 +1185,13 @@ def _make_uniform_airbridging_df(self, layer=ab_component_layer, data_type=0, no_cheese_buffer=0) - self.chip_info[chip_name][chip_layer]['no_cheese_gds'] = airbridge_gds + + + lib_cell = self.lib.new_cell(f'TOP_{chip_name}_ab') + + lib_cell.add(airbridge_gds) + + top_cell.add(gdspy.CellReference(lib_cell)) ### End of Airbridging From 0722e4aea78204c197c3b9ba2d56a612d1606b9a Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:56:12 -1000 Subject: [PATCH 34/57] should push to gds --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 699e36715..a1af9b379 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1177,6 +1177,8 @@ def _make_uniform_airbridging_df(self, top_cell = self.lib.cells[f'TOP_{chip_name}'] + lib_cell = self.lib.new_cell(f'TOP_{chip_name}_ab') + for _, row in airbridges_df.iterrows(): ab_component_multi_poly = row['MultiPoly'] @@ -1186,11 +1188,7 @@ def _make_uniform_airbridging_df(self, data_type=0, no_cheese_buffer=0) - - lib_cell = self.lib.new_cell(f'TOP_{chip_name}_ab') - lib_cell.add(airbridge_gds) - top_cell.add(gdspy.CellReference(lib_cell)) ### End of Airbridging From 4cc60f6668f67cfb6537e7116e7d26a05c79f7d9 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:58:50 -1000 Subject: [PATCH 35/57] fixed rotation of ab --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 5fe7749cf..7d5498a99 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -163,7 +163,7 @@ def find_uniform_ab_placement(self, dy = dl[1] - theta = np.arctan2(dy,dx) + theta = np.arctan2(dy,dx) + 45 mag_dl = np.sqrt(dx**2 + dy**2) lprime = mag_dl - 2 * bridge_minimum_spacing @@ -220,7 +220,7 @@ def find_uniform_ab_placement(self, dx = np.cos(theta_i) - np.cos(theta_f) dy = np.sin(theta_i) - np.sin(theta_f) - theta = np.arctan2(dy, dx) + theta = np.arctan2(dy, dx) + 45 distance_circle_box_x = fillet * (1-np.abs(np.cos(theta))) distance_circle_box_y = fillet * (1-np.abs(np.sin(theta))) From 2bbac997ab82f961256acd729d9a4a933c9b0ea4 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 19:59:51 -1000 Subject: [PATCH 36/57] fixed rotation of ab --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 7d5498a99..fb737a193 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -163,7 +163,7 @@ def find_uniform_ab_placement(self, dy = dl[1] - theta = np.arctan2(dy,dx) + 45 + theta = np.arctan2(dy,dx) mag_dl = np.sqrt(dx**2 + dy**2) lprime = mag_dl - 2 * bridge_minimum_spacing @@ -220,7 +220,7 @@ def find_uniform_ab_placement(self, dx = np.cos(theta_i) - np.cos(theta_f) dy = np.sin(theta_i) - np.sin(theta_f) - theta = np.arctan2(dy, dx) + 45 + theta = np.arctan2(dy, dx) distance_circle_box_x = fillet * (1-np.abs(np.cos(theta))) distance_circle_box_y = fillet * (1-np.abs(np.sin(theta))) @@ -247,7 +247,7 @@ def ab_placement_to_df(self, shapley_data = component['geometry'] for x, y, theta in ab_placement: # Extract shapely data, and move to proper spot - shapely_copy = draw.rotate(shapley_data, theta, origin=(0,0)) + shapely_copy = draw.rotate(shapley_data, theta + 45, origin=(0,0)) shapely_copy = draw.translate(shapely_copy, x, y) shapely_copy = shapely.geometry.MultiPolygon([shapely_copy]) From 63a09fb00249e411c9bfaedffc989ca7d2a12f76 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 20:00:18 -1000 Subject: [PATCH 37/57] fixed rotation of ab --- qiskit_metal/renderers/renderer_gds/make_airbridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index fb737a193..533ccd7d9 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -247,7 +247,7 @@ def ab_placement_to_df(self, shapley_data = component['geometry'] for x, y, theta in ab_placement: # Extract shapely data, and move to proper spot - shapely_copy = draw.rotate(shapley_data, theta + 45, origin=(0,0)) + shapely_copy = draw.rotate(shapley_data, theta + 90, origin=(0,0)) shapely_copy = draw.translate(shapely_copy, x, y) shapely_copy = shapely.geometry.MultiPolygon([shapely_copy]) From 7167ff70e267c7f6b578ae181125b4494691c97b Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 20:49:28 -1000 Subject: [PATCH 38/57] fixed depreciation warning --- .../renderers/renderer_gds/airbridge.py | 4 ++-- .../renderers/renderer_gds/gds_renderer.py | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py index d056ebfa8..62acbfbb7 100644 --- a/qiskit_metal/renderers/renderer_gds/airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -49,8 +49,8 @@ def make(self): # Make the outter square structure left_outside = draw.rectangle(outter_length, outter_length, 0, 0) - right_outside = draw.translate(left_outside, crossover_length/2 + inner_length/2, 0) - left_outside = draw.translate(left_outside, -(crossover_length/2 + inner_length/2),0) + right_outside = draw.translate(left_outside, crossover_length/2 + outter_length/2, 0) + left_outside = draw.translate(left_outside, -(crossover_length/2 + outter_length/2),0) # Make the bridge structure bridge = draw.rectangle(crossover_length, bridge_width, 0,0) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index a1af9b379..026221ff4 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -784,6 +784,7 @@ def _fix_short_segments_within_table(self, chip_name: str, chip_layer: int, df_copy = self.chip_info[chip_name][chip_layer][ all_sub_true_or_false].copy(deep=True) + dfs_to_concat = [] for del_key, the_shapes in edit_index.items(): # copy row "index" into a new data-frame "status" times. # Then replace the LONG shapely with all_shapelys. @@ -796,8 +797,8 @@ def _fix_short_segments_within_table(self, chip_name: str, chip_layer: int, orig_row['fillet'] = short_shape['fillet'] # Keep ignore_index=False, otherwise, # the other del_key will not be found. - df_copy = df_copy.append(orig_row, ignore_index=False) - + dfs_to_concat.append(orig_row) + df_copy = pd.concat([df_copy] + dfs_to_concat, ignore_index=True) self.chip_info[chip_name][chip_layer][ all_sub_true_or_false] = df_copy.copy(deep=True) @@ -1160,6 +1161,14 @@ def _make_uniform_airbridging_df(self, maxy (float): chip maximum y location. chip_name (str): User defined chip name. """ + if (self.options.corners != 'circular bend'): + logging.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') + + # Airbridge Options self.options.airbridge.qcomponent_base self.options.airbridge.options airbridging = Airbridging(design=self.design, @@ -1175,11 +1184,7 @@ def _make_uniform_airbridging_df(self, bridge_pitch=self.options.airbridge.bridge_pitch, bridge_minimum_spacing=self.options.airbridge.bridge_minimum_spacing) - - top_cell = self.lib.cells[f'TOP_{chip_name}'] - lib_cell = self.lib.new_cell(f'TOP_{chip_name}_ab') - - + # Run for _, row in airbridges_df.iterrows(): ab_component_multi_poly = row['MultiPoly'] ab_component_layer = row['layer'] From b04f90268f3959013dbb5ac692cb6623ccea2838 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 20:55:26 -1000 Subject: [PATCH 39/57] couldn't fix depreciation error, will leave for someone else --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 026221ff4..736e2ea55 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -784,7 +784,6 @@ def _fix_short_segments_within_table(self, chip_name: str, chip_layer: int, df_copy = self.chip_info[chip_name][chip_layer][ all_sub_true_or_false].copy(deep=True) - dfs_to_concat = [] for del_key, the_shapes in edit_index.items(): # copy row "index" into a new data-frame "status" times. # Then replace the LONG shapely with all_shapelys. @@ -797,8 +796,8 @@ def _fix_short_segments_within_table(self, chip_name: str, chip_layer: int, orig_row['fillet'] = short_shape['fillet'] # Keep ignore_index=False, otherwise, # the other del_key will not be found. - dfs_to_concat.append(orig_row) - df_copy = pd.concat([df_copy] + dfs_to_concat, ignore_index=True) + df_copy = df_copy.append(orig_row, ignore_index=False) + self.chip_info[chip_name][chip_layer][ all_sub_true_or_false] = df_copy.copy(deep=True) From 2ea6c29ff39a95a02e3742b1e65f10132bb93177 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 21:38:42 -1000 Subject: [PATCH 40/57] added documentation --- .../renderers/renderer_gds/gds_renderer.py | 25 +++++-- .../renderers/renderer_gds/make_airbridge.py | 67 ++++++++++++------- 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 736e2ea55..be2000534 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -96,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 + * bridge_pitch: '100um' + * bridge_minimum_spacing: '5um' + * datatype: '0' * cheese: Dict * datatype: '100' * shape: '0' @@ -219,15 +226,21 @@ class QGDSRenderer(QRenderer): # 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 of fabrication guideline based + # this number usually comes from fabrication guidelines. bridge_minimum_spacing='5um', + + # GDS datatype of airbridges. + datatype = '0' ), # Cheesing is denoted by each chip and layer. @@ -1160,12 +1173,14 @@ def _make_uniform_airbridging_df(self, maxy (float): chip maximum y location. chip_name (str): User defined chip name. """ + # Warning / limitations if (self.options.corners != 'circular bend'): logging.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') + no_cheese_buffer = float(self.parse_value(self.options.no_cheese.buffer)) # Airbridge Options self.options.airbridge.qcomponent_base @@ -1183,14 +1198,14 @@ def _make_uniform_airbridging_df(self, bridge_pitch=self.options.airbridge.bridge_pitch, bridge_minimum_spacing=self.options.airbridge.bridge_minimum_spacing) - # Run + # 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=0, - no_cheese_buffer=0) + data_type=int(self.options.airbridge.datatype), + no_cheese_buffer=no_cheese_buffer) lib_cell.add(airbridge_gds) top_cell.add(gdspy.CellReference(lib_cell)) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 533ccd7d9..5899d9340 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -23,13 +23,7 @@ from qiskit_metal.qlibrary.core import QComponent class Airbridging: - """ - Airbridge for GDS logic - - Args: - precision: (float) -- Rounds values to the closest integer multiple of `precision` - This parameter is meant to take care of floating point errors. - """ + """Logic for placing airbridges for QGDSRenderer.""" def __init__(self, design: 'QDesign', @@ -40,6 +34,19 @@ def __init__(self, maxy: float, chip_name: str, precision: float): + """ + Initializes the Airbridging object. + + Args: + design (QDesign): The QDesign object associated with the design. + lib (gdspy.GdsLibrary): The GdsLibrary object to store GDS data. + minx (float): The minimum x-coordinate of the layout bounding box. + miny (float): The minimum y-coordinate of the layout bounding box. + maxx (float): The maximum x-coordinate of the layout bounding box. + maxy (float): The maximum y-coordinate of the layout bounding box. + chip_name (str): The name of the chip. + precision (float): Round position values to the closest integer multiple of this value. + """ # Design variables self.design = design self.lib = lib @@ -58,7 +65,7 @@ def cpws_with_ab(self) -> list[str]: QGeometry of CPWs w/ airbridges Returns: - cpw_names (DataFrame): QGeometry of CPWs w/ airbridges + cpw_names (list[str]): QGeometry of CPWs w/ airbridges ''' cpw_names = [] @@ -81,14 +88,15 @@ def make_uniform_airbridging_df(self, Makes the uniform airbridging dataframe Args: - custom_qcomponent (QComponent) - qcomponent_options (dict) - bridge_pitch (str) - bridge_minimum_spacing (str): - precision (str) + custom_qcomponent (QComponent): Airbridge class, child of QComponent. + qcomponent_options (dict): Options when calling airbridge. + These go in `custom_qcomponent(design, name, options=qcomponent_options)` + bridge_pitch (str): Length between airbridges. Measured from the center of the bridge structure. + bridge_minimum_spacing (str): Spacing between corner and first airbridge. Returns: - airbridge_df (pd.DataFrame) + airbridge_df (pd.DataFrame): Has two columns: 'MultiPoly' and 'layer'. + Used in QGDSRenderer._make_uniform_airbridging_df """ bridge_pitch = self.design.parse_value(bridge_pitch) bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) @@ -104,7 +112,7 @@ def make_uniform_airbridging_df(self, bridge_pitch=bridge_pitch, bridge_minimum_spacing=bridge_minimum_spacing) airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement=ab_placement, - qgeom_table=ab_qgeom) + ab_qgeom=ab_qgeom) ab_df_list.append(airbridge_df_for_cpw) airbridge_df = pd.concat(ab_df_list) @@ -120,8 +128,8 @@ def find_uniform_ab_placement(self, Inputs: cpw_name (str): Name of cpw to find airbridge placements. + bridge_pitch: (float) -- Spacing between the centers of each bridge. Units in mm. bridge_minimum_spacing: (float) -- Minimum spacing from corners. Units in mm. - bridge_pitch: (float, in units mm) -- Spacing between the centers of each bridge. Units in mm. Returns: ab_placements (list[tuple[float, float, float]]): Where the airbridges should be placed for given `cpw_name`. @@ -132,10 +140,9 @@ def find_uniform_ab_placement(self, ..., (xn, yn, thetan))] - Units: - - x (float): Units mm - - y (float): Units mm - - theta (float): Units degrees + - x (float): x position of airbridge. Units mm. + - y (float): y position of airbridge. Units mm. + - theta (float): Rotation of airbridge. Units degrees. ''' precision = self.design.parse_value(self.precision) @@ -232,18 +239,27 @@ def find_uniform_ab_placement(self, ab_placements.append((x, y, np.degrees(theta_avg))) + # Removes airbridge at the start pin + ab_placements = ab_placements[1:] + return ab_placements def ab_placement_to_df(self, - ab_placement: list[float], - qgeom_table: 'pd.DataFrame') -> pd.DataFrame: + ab_placement: list[tuple[float, float, float]], + ab_qgeom: pd.DataFrame) -> pd.DataFrame: ''' With a base airbridge shape, find the shapely data for placing all airbridges. + Args: + ab_placement (list[tuple[float, float, float]]): Output from self.find_uniform_ab_placement + ab_qgeom (pd.DataFrame): QGeometry table of single airbridge. + + Return: + airbridge_df (pd.DataFrame): All airbridges placed. Has two columns: 'MultiPoly' and 'layer'. ''' shapley_data_all = [] layer_data_all = [] - for _, component in qgeom_table.iterrows(): + for _, component in ab_qgeom.iterrows(): shapley_data = component['geometry'] for x, y, theta in ab_placement: # Extract shapely data, and move to proper spot @@ -264,11 +280,10 @@ def ab_placement_to_df(self, return airbridge_df def extract_qgeom_from_unrendered_qcomp(self, - custom_qcomponent: 'QComponent', - qcomponent_options: dict) -> 'pd.DataFrame': + custom_qcomponent: 'QComponent', + qcomponent_options: dict) -> 'pd.DataFrame': ''' Extracts the qgeometry table from a child of QComponent. - Must have QComponent.make() Args: custom_qcomponent (QComponent): Class of QComponent, not called / instantiated. From bc1ec37f54496f7b3ad29d27d6df6a68a08b237c Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 21:52:11 -1000 Subject: [PATCH 41/57] added basic tests --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 4 ++-- qiskit_metal/tests/test_renderers.py | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index be2000534..b66732daa 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -99,7 +99,7 @@ class QGDSRenderer(QRenderer): * airbridge: Dict * geometry: Dict qcomponent_base: Airbridge_forGDS - options: Dict + options: Dict(crossover_length='22um') * bridge_pitch: '100um' * bridge_minimum_spacing: '5um' * datatype: '0' @@ -230,7 +230,7 @@ class QGDSRenderer(QRenderer): 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') + options=Dict(crossover_length='22um') ), # Spacing between centers of each airbridge. bridge_pitch='100um', diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index b5d6a5d17..39c982a90 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -42,6 +42,7 @@ from qiskit_metal.qgeometries.qgeometries_handler import QGeometryTables from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket +from qiskit_metal.renderers.renderer_gds.airbridge import Airbridge_forGDS from qiskit_metal import draw @@ -343,6 +344,15 @@ def test_renderer_gdsrenderer_options(self): self.assertEqual(options['fabricate'], 'False') + self.assertEqual(len(options['airbridge']), 4) + self.assertEqual(len(options['airbridge']['geometry']), 2) + + self.assertEqual(options['airbridge']['geometry']['qcomponent_base'], Airbridge_forGDS) + self.assertEqual(options['airbridge']['geometry']['options']['crossover_length'], '22um') + self.assertEqual(options['airbridge']['bridge_pitch'], '100um') + self.assertEqual(options['airbridge']['bridge_minimum_spacing'], '5um') + self.assertEqual(options['airbridge']['datatype'], '0') + self.assertEqual(len(options['cheese']), 9) self.assertEqual(len(options['no_cheese']), 5) @@ -588,7 +598,7 @@ def test_renderer_gdsrenderer_check_qcomps(self): def test_renderer_mpl_interaction_disconnect(self): """Test disconnect in MplInteraction in mpl_interaction.py.""" mpl = MplInteraction(_plt) - mpl.disconnect() + mpl.didsconnect() self.assertEqual(mpl.figure, None) def test_renderer_gds_check_cheese(self): From 79977e238514c29d4a70037c532ef1889faef92c Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:05:54 -1000 Subject: [PATCH 42/57] yapf styling --- .../renderers/renderer_gds/airbridge.py | 42 +++-- .../renderers/renderer_gds/gds_renderer.py | 60 +++---- .../renderers/renderer_gds/make_airbridge.py | 159 +++++++++--------- 3 files changed, 135 insertions(+), 126 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py index 62acbfbb7..54f5a9dcf 100644 --- a/qiskit_metal/renderers/renderer_gds/airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -1,6 +1,7 @@ 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. @@ -17,14 +18,14 @@ class Airbridge_forGDS(QComponent): * square_layer: 30 -- GDS layer of inner squares. * bridge_layer: 31 -- GDS layer of bridge + outter squares. """ - + # Default drawing options - default_options = Dict(crossover_length = '22um', - bridge_width = '7.5um', - inner_length = '8um', - outter_length = '11um', - square_layer = 30, - bridge_layer = 31) + default_options = Dict(crossover_length='22um', + bridge_width='7.5um', + inner_length='8um', + outter_length='11um', + square_layer=30, + bridge_layer=31) """Default drawing options""" # Name prefix of component, if user doesn't provide name @@ -42,26 +43,37 @@ def make(self): # Make the inner square structure left_inside = draw.rectangle(inner_length, inner_length, 0, 0) - right_inside = draw.translate(left_inside, crossover_length/2 + inner_length/2, 0) - left_inside = draw.translate(left_inside, -(crossover_length/2 + inner_length/2),0) + right_inside = draw.translate(left_inside, + crossover_length / 2 + inner_length / 2, + 0) + left_inside = draw.translate(left_inside, + -(crossover_length / 2 + inner_length / 2), + 0) inside_struct = draw.union(left_inside, right_inside) # Make the outter square structure left_outside = draw.rectangle(outter_length, outter_length, 0, 0) - right_outside = draw.translate(left_outside, crossover_length/2 + outter_length/2, 0) - left_outside = draw.translate(left_outside, -(crossover_length/2 + outter_length/2),0) + right_outside = draw.translate(left_outside, + crossover_length / 2 + outter_length / 2, + 0) + left_outside = draw.translate( + left_outside, -(crossover_length / 2 + outter_length / 2), 0) # Make the bridge structure - bridge = draw.rectangle(crossover_length, bridge_width, 0,0) + 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.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) + 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) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index b66732daa..a0b918eb5 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -230,18 +230,16 @@ class QGDSRenderer(QRenderer): 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') - ), + options=Dict(crossover_length='22um')), # Spacing between centers of each airbridge. bridge_pitch='100um', - - # Minimum spacing between each airbridge, + + # Minimum spacing between each airbridge, # this number usually comes from fabrication guidelines. bridge_minimum_spacing='5um', # GDS datatype of airbridges. - datatype = '0' - ), + datatype='0'), # Cheesing is denoted by each chip and layer. cheese=Dict( @@ -1143,24 +1141,16 @@ def _populate_airbridge(self): 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, + # 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, - chip_layer) - - def _make_uniform_airbridging_df(self, - minx: float, - miny: float, - maxx: float, - maxy: float, - chip_name: str, - chip_layer): + self._make_uniform_airbridging_df(minx, miny, maxx, maxy, + chip_name, chip_layer) + + def _make_uniform_airbridging_df(self, minx: float, miny: float, + maxx: float, maxy: float, chip_name: str, + chip_layer): """ Apply airbridges to all `path` elements which have options.gds_make_airbridge = True. This is a @@ -1175,12 +1165,15 @@ def _make_uniform_airbridging_df(self, """ # Warning / limitations if (self.options.corners != 'circular bend'): - logging.warning('Uniform airbridging is designed for `self.options.corners = "circular bend"`. You might experience unexpected behavior.') + logging.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') - no_cheese_buffer = float(self.parse_value(self.options.no_cheese.buffer)) + no_cheese_buffer = float(self.parse_value( + self.options.no_cheese.buffer)) # Airbridge Options self.options.airbridge.qcomponent_base @@ -1193,19 +1186,22 @@ def _make_uniform_airbridging_df(self, 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) + 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=int(self.options.airbridge.datatype), - no_cheese_buffer=no_cheese_buffer) + airbridge_gds = self._multipolygon_to_gds( + multi_poly=ab_component_multi_poly, + layer=ab_component_layer, + data_type=int(self.options.airbridge.datatype), + no_cheese_buffer=no_cheese_buffer) lib_cell.add(airbridge_gds) top_cell.add(gdspy.CellReference(lib_cell)) diff --git a/qiskit_metal/renderers/renderer_gds/make_airbridge.py b/qiskit_metal/renderers/renderer_gds/make_airbridge.py index 5899d9340..fe40dc086 100644 --- a/qiskit_metal/renderers/renderer_gds/make_airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/make_airbridge.py @@ -22,17 +22,12 @@ from qiskit_metal.qlibrary.core import QComponent + class Airbridging: """Logic for placing airbridges for QGDSRenderer.""" - def __init__(self, - design: 'QDesign', - lib: gdspy.GdsLibrary, - minx: float, - miny: float, - maxx: float, - maxy: float, - chip_name: str, + def __init__(self, design: 'QDesign', lib: gdspy.GdsLibrary, minx: float, + miny: float, maxx: float, maxy: float, chip_name: str, precision: float): """ Initializes the Airbridging object. @@ -79,11 +74,9 @@ def cpws_with_ab(self) -> list[str]: return cpw_names - def make_uniform_airbridging_df(self, - custom_qcomponent: 'QComponent', - qcomponent_options: dict, - bridge_pitch: str, - bridge_minimum_spacing: str) -> pd.DataFrame: + def make_uniform_airbridging_df( + self, custom_qcomponent: 'QComponent', qcomponent_options: dict, + bridge_pitch: str, bridge_minimum_spacing: str) -> pd.DataFrame: """ Makes the uniform airbridging dataframe @@ -102,27 +95,28 @@ def make_uniform_airbridging_df(self, bridge_minimum_spacing = self.design.parse_value(bridge_minimum_spacing) # Get shapley cutout of airbridges - ab_qgeom = self.extract_qgeom_from_unrendered_qcomp(custom_qcomponent=custom_qcomponent, - qcomponent_options=qcomponent_options) + ab_qgeom = self.extract_qgeom_from_unrendered_qcomp( + custom_qcomponent=custom_qcomponent, + qcomponent_options=qcomponent_options) # Place the airbridges ab_df_list = [] for cpw_name in self.cpws_with_ab: - ab_placement = self.find_uniform_ab_placement(cpw_name=cpw_name, - bridge_pitch=bridge_pitch, - bridge_minimum_spacing=bridge_minimum_spacing) - airbridge_df_for_cpw = self.ab_placement_to_df(ab_placement=ab_placement, - ab_qgeom=ab_qgeom) + ab_placement = self.find_uniform_ab_placement( + cpw_name=cpw_name, + bridge_pitch=bridge_pitch, + bridge_minimum_spacing=bridge_minimum_spacing) + airbridge_df_for_cpw = self.ab_placement_to_df( + ab_placement=ab_placement, ab_qgeom=ab_qgeom) ab_df_list.append(airbridge_df_for_cpw) airbridge_df = pd.concat(ab_df_list) return airbridge_df - def find_uniform_ab_placement(self, - cpw_name: str, - bridge_pitch: float, - bridge_minimum_spacing: float) -> list[tuple[float, float, float]]: + def find_uniform_ab_placement( + self, cpw_name: str, bridge_pitch: float, + bridge_minimum_spacing: float) -> list[tuple[float, float, float]]: ''' Determines where to place the wirebonds given a CPW. @@ -151,101 +145,101 @@ def find_uniform_ab_placement(self, points = target_cpw.get_points() ab_placements = [] points_theta = [] - + fillet = self.design.parse_value(target_cpw.options.fillet) - + ### Handles all the straight sections ### - for i in range(len(points)-1): + for i in range(len(points) - 1): # Set up parameters for this calculation pos_i = points[i] pos_f = points[i + 1] - + x0 = round(float(pos_i[0]) / precision) * precision y0 = round(float(pos_i[1]) / precision) * precision xf = round(float(pos_f[0]) / precision) * precision yf = round(float(pos_f[1]) / precision) * precision - + dl = (xf - x0, yf - y0) dx = dl[0] dy = dl[1] - - - theta = np.arctan2(dy,dx) + + theta = np.arctan2(dy, dx) mag_dl = np.sqrt(dx**2 + dy**2) - lprime = mag_dl - 2 * bridge_minimum_spacing - + lprime = mag_dl - 2 * bridge_minimum_spacing + if fillet > bridge_minimum_spacing: lprime = mag_dl - 2 * fillet else: - lprime = mag_dl - 2 * bridge_minimum_spacing - n = 1 #refers to the number of bridges you've already placed + lprime = mag_dl - 2 * bridge_minimum_spacing + n = 1 #refers to the number of bridges you've already placed #Asking should I place another? If true place another one. while (lprime) >= (n * bridge_pitch): n += 1 - - mu_x = (xf + x0)/2 - mu_y = (yf + y0)/2 - + + mu_x = (xf + x0) / 2 + mu_y = (yf + y0) / 2 + x = np.array([i * bridge_pitch * np.cos(theta) for i in range(n)]) y = np.array([i * bridge_pitch * np.sin(theta) for i in range(n)]) x = (x - np.average(x)) + mu_x y = (y - np.average(y)) + mu_y - + for i in range(n): - ab_placements.append((x[i],y[i], np.degrees(theta))) - + ab_placements.append((x[i], y[i], np.degrees(theta))) + #This is for the corner points points_theta.append(theta) - + ### This handles all the corner / turning sections ### # First check to see if any turns exists if (len(points) > 2): corner_points = points_theta[1:-1] - for i in range(len(corner_points)+1): - - # First check to see if we should + for i in range(len(corner_points) + 1): + + # First check to see if we should # even make an airbridge at this corner pos_i = points[i] pos_f = points[i + 1] - + x0 = round(float(pos_i[0]) / precision) * precision y0 = round(float(pos_i[1]) / precision) * precision xf = round(float(pos_f[0]) / precision) * precision yf = round(float(pos_f[1]) / precision) * precision - - mag_dl = np.sqrt((xf-x0)**2 + (yf-y0)**2) - + + mag_dl = np.sqrt((xf - x0)**2 + (yf - y0)**2) + if mag_dl < fillet or mag_dl < bridge_minimum_spacing: continue - + # Now that we only have real turns # let's find the center trace of to align the wirebonds theta_f = points_theta[i + 1] theta_i = points_theta[i] - + dx = np.cos(theta_i) - np.cos(theta_f) dy = np.sin(theta_i) - np.sin(theta_f) - + theta = np.arctan2(dy, dx) - - distance_circle_box_x = fillet * (1-np.abs(np.cos(theta))) - distance_circle_box_y = fillet * (1-np.abs(np.sin(theta))) - - theta_avg = (theta_f + theta_i)/2 - - x = points[i + 1][0] - distance_circle_box_x * np.sign(np.cos(theta)) - y = points[i + 1][1] - distance_circle_box_y * np.sign(np.sin(theta)) - + + distance_circle_box_x = fillet * (1 - np.abs(np.cos(theta))) + distance_circle_box_y = fillet * (1 - np.abs(np.sin(theta))) + + theta_avg = (theta_f + theta_i) / 2 + + x = points[i + 1][0] - distance_circle_box_x * np.sign( + np.cos(theta)) + y = points[i + 1][1] - distance_circle_box_y * np.sign( + np.sin(theta)) + ab_placements.append((x, y, np.degrees(theta_avg))) - + # Removes airbridge at the start pin ab_placements = ab_placements[1:] return ab_placements - - def ab_placement_to_df(self, - ab_placement: list[tuple[float, float, float]], + + def ab_placement_to_df(self, ab_placement: list[tuple[float, float, float]], ab_qgeom: pd.DataFrame) -> pd.DataFrame: ''' With a base airbridge shape, find the shapely data for placing all airbridges. @@ -263,7 +257,9 @@ def ab_placement_to_df(self, shapley_data = component['geometry'] for x, y, theta in ab_placement: # Extract shapely data, and move to proper spot - shapely_copy = draw.rotate(shapley_data, theta + 90, origin=(0,0)) + shapely_copy = draw.rotate(shapley_data, + theta + 90, + origin=(0, 0)) shapely_copy = draw.translate(shapely_copy, x, y) shapely_copy = shapely.geometry.MultiPolygon([shapely_copy]) @@ -274,14 +270,16 @@ def ab_placement_to_df(self, shapley_data_all.append(shapely_copy) layer_data_all.append(layer) - airbridge_df = pd.DataFrame({'MultiPoly': shapley_data_all, - 'layer' : layer_data_all}) + airbridge_df = pd.DataFrame({ + 'MultiPoly': shapley_data_all, + 'layer': layer_data_all + }) return airbridge_df - - def extract_qgeom_from_unrendered_qcomp(self, - custom_qcomponent: 'QComponent', - qcomponent_options: dict) -> 'pd.DataFrame': + + def extract_qgeom_from_unrendered_qcomp( + self, custom_qcomponent: 'QComponent', + qcomponent_options: dict) -> 'pd.DataFrame': ''' Extracts the qgeometry table from a child of QComponent. @@ -294,22 +292,25 @@ def extract_qgeom_from_unrendered_qcomp(self, ''' # Chck you put in a QComponent w/ self.make() functionality if not issubclass(custom_qcomponent, QComponent): - raise ValueError('`custom_qcomponent` must be a child of `QComponent`.') + raise ValueError( + '`custom_qcomponent` must be a child of `QComponent`.') if not hasattr(custom_qcomponent, 'make'): - raise AttributeError('`custom_qcomponent` must have `make()` method') + raise AttributeError( + '`custom_qcomponent` must have `make()` method') # Make a name which won't interfer w/ other components test_name = 'initial_name' all_component_names = self.design.components.keys() while test_name in all_component_names: test_name += '1' - + # Temporarily render in QComponent - qcomponent_obj = custom_qcomponent(self.design, test_name, options=qcomponent_options) + qcomponent_obj = custom_qcomponent(self.design, + test_name, + options=qcomponent_options) # Extract shapley data qgeom_table = qcomponent_obj.qgeometry_table('poly') # Delete it qcomponent_obj.delete() return qgeom_table - From 728e72de82392ad3d69bd943c8be7aaae18849c4 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:08:14 -1000 Subject: [PATCH 43/57] yapf in test --- qiskit_metal/tests/test_renderers.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index 39c982a90..22203b39d 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -346,9 +346,12 @@ def test_renderer_gdsrenderer_options(self): self.assertEqual(len(options['airbridge']), 4) self.assertEqual(len(options['airbridge']['geometry']), 2) - - self.assertEqual(options['airbridge']['geometry']['qcomponent_base'], Airbridge_forGDS) - self.assertEqual(options['airbridge']['geometry']['options']['crossover_length'], '22um') + + self.assertEqual(options['airbridge']['geometry']['qcomponent_base'], + Airbridge_forGDS) + self.assertEqual( + options['airbridge']['geometry']['options']['crossover_length'], + '22um') self.assertEqual(options['airbridge']['bridge_pitch'], '100um') self.assertEqual(options['airbridge']['bridge_minimum_spacing'], '5um') self.assertEqual(options['airbridge']['datatype'], '0') From d37bf2f3457ac929024f792f6774e2187a1799cb Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:12:27 -1000 Subject: [PATCH 44/57] fixed error in data_type parsing in _make_uniform_airbridging_df --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index a0b918eb5..a792dd204 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1172,6 +1172,7 @@ def _make_uniform_airbridging_df(self, minx: float, miny: float, # 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)) @@ -1200,7 +1201,7 @@ def _make_uniform_airbridging_df(self, minx: float, miny: float, airbridge_gds = self._multipolygon_to_gds( multi_poly=ab_component_multi_poly, layer=ab_component_layer, - data_type=int(self.options.airbridge.datatype), + data_type=datatype, no_cheese_buffer=no_cheese_buffer) lib_cell.add(airbridge_gds) From eb5dbf86b36e98256d460247a522b16f8093a490 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:17:13 -1000 Subject: [PATCH 45/57] default_options.airbrdige.datatype isn't loading --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index a792dd204..53a16ed40 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -223,6 +223,9 @@ class QGDSRenderer(QRenderer): # Airbriding airbridge=Dict( + # GDS datatype of airbridges. + datatype='0', + # Setup geometrical style of airbridge geometry=Dict( # Skeleton of airbridge in QComponent form, @@ -236,10 +239,7 @@ class QGDSRenderer(QRenderer): # Minimum spacing between each airbridge, # this number usually comes from fabrication guidelines. - bridge_minimum_spacing='5um', - - # GDS datatype of airbridges. - datatype='0'), + bridge_minimum_spacing='5um'), # Cheesing is denoted by each chip and layer. cheese=Dict( From 8befcc8b0b4191ad3a6e4e50302087641f661a15 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:38:17 -1000 Subject: [PATCH 46/57] logger works now --- qiskit_metal/renderers/renderer_gds/gds_renderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index 53a16ed40..abf395066 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1165,7 +1165,7 @@ def _make_uniform_airbridging_df(self, minx: float, miny: float, """ # Warning / limitations if (self.options.corners != 'circular bend'): - logging.warning( + self.logger.warning( 'Uniform airbridging is designed for `self.options.corners = "circular bend"`. You might experience unexpected behavior.' ) From bfb3e15ace038373e48412b8c51f5736a38d8efd Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:42:17 -1000 Subject: [PATCH 47/57] removed unnessary arg in _make_uniform_airbridging_df --- .../renderers/renderer_gds/gds_renderer.py | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/gds_renderer.py b/qiskit_metal/renderers/renderer_gds/gds_renderer.py index abf395066..5279526cb 100644 --- a/qiskit_metal/renderers/renderer_gds/gds_renderer.py +++ b/qiskit_metal/renderers/renderer_gds/gds_renderer.py @@ -1136,21 +1136,19 @@ def _populate_airbridge(self): layers_in_chip = self.design.qgeometry.get_all_unique_layers( chip_name) - for chip_layer in layers_in_chip: - chip_box, status = self.design.get_x_y_for_chip(chip_name) - if status == 0: - minx, miny, maxx, maxy = chip_box + 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, chip_layer) + # 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, - chip_layer): + maxx: float, maxy: float, chip_name: str): """ Apply airbridges to all `path` elements which have options.gds_make_airbridge = True. This is a From af5c54e6654497e98a8b2e2ccbfa7321eab5bb92 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:45:52 -1000 Subject: [PATCH 48/57] fixed spelling of outer --- .../renderers/renderer_gds/airbridge.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py index 54f5a9dcf..b60cccfe1 100644 --- a/qiskit_metal/renderers/renderer_gds/airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -10,20 +10,20 @@ class Airbridge_forGDS(QComponent): This QComponent should NOT be rendered for EM simulation. Default Options: - * crossover_length: '22um' -- Distance between the two outter squares (aka bridge length). + * 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. - * outter_length: '11um' -- Length of outter square. + * outer_length: '11um' -- Length of outer square. * square_layer: 30 -- GDS layer of inner squares. - * bridge_layer: 31 -- GDS layer of bridge + outter 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', - outter_length='11um', + outer_length='11um', square_layer=30, bridge_layer=31) """Default drawing options""" @@ -39,7 +39,7 @@ def make(self): crossover_length = p.crossover_length bridge_width = p.bridge_width inner_length = p.inner_length - outter_length = p.outter_length + outer_length = p.outer_length # Make the inner square structure left_inside = draw.rectangle(inner_length, inner_length, 0, 0) @@ -52,13 +52,13 @@ def make(self): inside_struct = draw.union(left_inside, right_inside) - # Make the outter square structure - left_outside = draw.rectangle(outter_length, outter_length, 0, 0) + # Make the outer square structure + left_outside = draw.rectangle(outer_length, outer_length, 0, 0) right_outside = draw.translate(left_outside, - crossover_length / 2 + outter_length / 2, + crossover_length / 2 + outer_length / 2, 0) left_outside = draw.translate( - left_outside, -(crossover_length / 2 + outter_length / 2), 0) + left_outside, -(crossover_length / 2 + outer_length / 2), 0) # Make the bridge structure bridge = draw.rectangle(crossover_length, bridge_width, 0, 0) From ddfb065cd4164e4c1f51a50488cd03f3401e9e18 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 22:47:49 -1000 Subject: [PATCH 49/57] fixed airbridge.py drawing --- qiskit_metal/renderers/renderer_gds/airbridge.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit_metal/renderers/renderer_gds/airbridge.py b/qiskit_metal/renderers/renderer_gds/airbridge.py index b60cccfe1..d56128111 100644 --- a/qiskit_metal/renderers/renderer_gds/airbridge.py +++ b/qiskit_metal/renderers/renderer_gds/airbridge.py @@ -29,7 +29,7 @@ class Airbridge_forGDS(QComponent): """Default drawing options""" # Name prefix of component, if user doesn't provide name - component_metadata = Dict(short_name='component') + component_metadata = Dict(short_name='airbridge') """Component metadata""" def make(self): @@ -44,10 +44,10 @@ def make(self): # Make the inner square structure left_inside = draw.rectangle(inner_length, inner_length, 0, 0) right_inside = draw.translate(left_inside, - crossover_length / 2 + inner_length / 2, + crossover_length / 2 + outer_length / 2, 0) left_inside = draw.translate(left_inside, - -(crossover_length / 2 + inner_length / 2), + -(crossover_length / 2 + outer_length / 2), 0) inside_struct = draw.union(left_inside, right_inside) From 1bbea15a7b5ed20c567c5a81446532c3cdfc5871 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 23:36:47 -1000 Subject: [PATCH 50/57] update QGDS tutorial to include how to use airbridges --- .../3.2 Export your design to GDS.ipynb | 182 +++++++++++++++++- 1 file changed, 181 insertions(+), 1 deletion(-) diff --git a/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb b/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb index 36fd7f85c..14e05f97a 100644 --- a/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb +++ b/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb @@ -1,6 +1,7 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -8,6 +9,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -15,6 +17,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -37,6 +40,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -52,6 +56,7 @@ "import qiskit_metal as metal\n", "from qiskit_metal import designs, draw\n", "from qiskit_metal import MetalGUI, Dict, Headings\n", + "from qiskit_metal.qlibrary.core import QComponent\n", "from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket\n", "from qiskit_metal.qlibrary.qubits.transmon_cross import TransmonCross" ] @@ -117,6 +122,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -150,6 +156,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -191,7 +198,8 @@ " start_straight='0.13mm',\n", " end_straight='0.13mm'\n", " ),\n", - " total_length=length)\n", + " total_length=length,\n", + " gds_make_airbridge=True)\n", " myoptions.update(options)\n", " myoptions.meander.asymmetry = asymmetry\n", " myoptions.meander.lead_direction_inverted = 'true' if flip else 'false'\n", @@ -246,6 +254,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -256,6 +265,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -266,6 +276,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -284,6 +295,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -313,6 +325,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -392,6 +405,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -399,6 +413,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -415,6 +430,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -453,6 +469,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -472,6 +489,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -491,6 +509,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -535,6 +554,160 @@ "a_gds.options['tolerance'] = '0.00001'" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Headings.h1('Airbridges')" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Airbridges are extensions of the ground plane which loop over CPWs. They are meant to increase a CPWs capacitance to ground. Normally preparing the GDS file for airbridges would take someone a couple hours, but Qiskit Metal can renderer in airbridges automatically.\n", + "\n", + "To enable airbridges on a CPW:\n", + "```\n", + "cpw_options = dict(...,\n", + " gds_make_airbridge = True)\n", + "\n", + "CPW_QComponent(design, name, options=cpw_options)\n", + "```\n", + "This was also demonstated in the QComponent design at the beginning of this tutorial." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Starting off, we can change the datatype of our airbridge\n", + "a_gds.options['airbridge']['datatype'] = 0" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Change the geometry of the airbridge\n", + "\n", + "To modify how an airbridge looks on the GDS file, we can create a custom `QComponent` (if you're unfamiliar w/ creating custom components, see [tutorials/2 From components to chip/D. How do I make my custom QComponent](https://github.com/qiskit-community/qiskit-metal/tree/main/tutorials/2%20From%20components%20to%20chip/D.%20How%20do%20I%20make%20my%20custom%20QComponent))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class MyCustomAirbridge(QComponent):\n", + " \"\"\"\n", + " The default airbridge has square poles. \n", + " Let's make an airbridge w/ circular poles.\n", + "\n", + " Args:\n", + " crossover_length:'25um' -- The length of the crossover in micrometers.\n", + " bridge_width: '7.5um' -- The width of the bridge in micrometers.\n", + " inner_radius: '4um' -- The radius of the inner circle in micrometers.\n", + " outer_radius: '5.5um' -- The radius of the outer circle in micrometers.\n", + " inner_layer: 30 -- The GDS layer number of the inner circle.\n", + " outer_layer: 31 -- The GDS layer number of the outer circle and bridge.\n", + " \"\"\"\n", + "\n", + " default_options = Dict(\n", + " crossover_length='25um'\n", + " bridge_width='7.5um'\n", + " inner_radius='4um',\n", + " outer_radius='5.5um',\n", + " inner_layer=30,\n", + " outer_layer=31\n", + " )\n", + "\n", + " def make(self):\n", + " # Parse options\n", + " p = self.p\n", + "\n", + " # Inner circle\n", + " crossover_length = p.crossover_length\n", + " bridge_width = p.bridge_width\n", + " inner_length = p.inner_length\n", + " outer_radius = p.outer_radius\n", + "\n", + " # Make the inner square structure\n", + " inner_circle = draw.shapely.geometry.Point(0, 0).buffer(inner_radius)\n", + " right_inside = draw.translate(inner_circle,\n", + " crossover_length / 2 + outer_radius,\n", + " 0)\n", + " left_inside = draw.translate(inner_circle,\n", + " -(crossover_length / 2 + outer_radius),\n", + " 0)\n", + "\n", + " inside_struct = draw.union(left_inside, right_inside)\n", + "\n", + " # Make the outer square structure\n", + " outer_circle = draw.shapely.geometry.Point(0, 0).buffer(outer_radius)\n", + " right_outside = draw.translate(outer_circle,\n", + " crossover_length / 2 + outer_radius,\n", + " 0)\n", + " left_outside = draw.translate(\n", + " outer_circle, -(crossover_length / 2 + outer_radius), 0)\n", + "\n", + " # Make the bridge structure\n", + " bridge = draw.rectangle(crossover_length, bridge_width, 0, 0)\n", + " bridge_struct = draw.union(bridge, left_outside, right_outside)\n", + "\n", + " ### Final adjustments to allow repositioning\n", + " final_design = [bridge_struct, inside_struct]\n", + " final_design = draw.rotate(final_design, p.orientation, origin=(0, 0))\n", + " final_design = draw.translate(final_design, p.pos_x, p.pos_y)\n", + " bridge_struct, inside_struct = final_design\n", + "\n", + " ### Add everything as a QGeometry\n", + " self.add_qgeometry('poly', {'bridge_struct': bridge_struct},\n", + " layer=p.outer_layer,\n", + " subtract=False)\n", + " self.add_qgeometry('poly', {'inside_struct': inside_struct},\n", + " layer=p.inner_layer,\n", + " subtract=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Use this custom airbridge\n", + "a_gds.options['airbridge']['geometry']['qcomponent_base'] = MyCustomAirbridge\n", + "\n", + "# Modify the geometry from the default options\n", + "# Notice this is the same way we can modify QComponents\n", + "a_gds.options['airbridge']['geometry']['options'] = Dict(\n", + " inner_radius='2um', # inner raidus\n", + " inner_layer=60, # refers to GDS layer\n", + " outer_layer=61 # refers to GDS layer\n", + ") # You can play w/ other options!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Distance between airbridges, measured from center of bridge\n", + "a_gds.options.airbridge.bridge_pitch = '50um'\n", + "\n", + "# Ensures a minimum distance between the center of airbridges\n", + "a_gds.options.airbridge.bridge_minimum_spacing = '10um'" + ] + }, { "cell_type": "code", "execution_count": null, @@ -547,6 +720,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -560,6 +734,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -606,6 +781,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -640,6 +816,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -710,6 +887,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -752,6 +930,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -780,6 +959,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ From 5af5df4462b916f389dae0a644c350f6015f511c Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 23:38:56 -1000 Subject: [PATCH 51/57] update QGDS tutorial to include how to use airbridges --- tutorials/3 Renderers/3.2 Export your design to GDS.ipynb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb b/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb index 14e05f97a..4ea357d64 100644 --- a/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb +++ b/tutorials/3 Renderers/3.2 Export your design to GDS.ipynb @@ -687,12 +687,14 @@ "a_gds.options['airbridge']['geometry']['qcomponent_base'] = MyCustomAirbridge\n", "\n", "# Modify the geometry from the default options\n", - "# Notice this is the same way we can modify QComponents\n", + "# Notice this is the same way we can modify QComponents!\n", "a_gds.options['airbridge']['geometry']['options'] = Dict(\n", " inner_radius='2um', # inner raidus\n", " inner_layer=60, # refers to GDS layer\n", " outer_layer=61 # refers to GDS layer\n", - ") # You can play w/ other options!" + ") \n", + "# You can play w/ other options! \n", + "# Or let them default to whatever is in your custom component." ] }, { From 9bb2f4361fe0520818f3805c29525943b7e81d97 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Mon, 26 Jun 2023 23:45:12 -1000 Subject: [PATCH 52/57] fixed typo in MPL test --- qiskit_metal/tests/test_renderers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index 22203b39d..d04cd1952 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -601,7 +601,7 @@ def test_renderer_gdsrenderer_check_qcomps(self): def test_renderer_mpl_interaction_disconnect(self): """Test disconnect in MplInteraction in mpl_interaction.py.""" mpl = MplInteraction(_plt) - mpl.didsconnect() + mpl.disconnect() self.assertEqual(mpl.figure, None) def test_renderer_gds_check_cheese(self): From ef0e92b8f581c023338b5e58a42e295129f477e1 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Tue, 27 Jun 2023 00:24:39 -1000 Subject: [PATCH 53/57] add robust test to airbridging --- qiskit_metal/tests/test_renderers.py | 52 +++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index d04cd1952..559038d59 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -42,7 +42,9 @@ from qiskit_metal.qgeometries.qgeometries_handler import QGeometryTables from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket -from qiskit_metal.renderers.renderer_gds.airbridge import Airbridge_forGDS +from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround +from qiskit_metal.qlibrary.tlines.mixed_path import RouteMixed +from qiskit_metal.renderers.renderer_gds.make_airbridge import Airbridging from qiskit_metal import draw @@ -604,6 +606,54 @@ def test_renderer_mpl_interaction_disconnect(self): mpl.disconnect() self.assertEqual(mpl.figure, None) + def test_renderer_gds_check_uniform_airbridge(self): + """Tests uniform airbridge placement via Airbridging""" + design = designs.DesignPlanar() + open_start_options = Dict(pos_x='1000um', + pos_y='0um', + orientation='-90') + open_start_meander = OpenToGround(design, + 'Open_meander_start', + options=open_start_options) + open_end_options = Dict(pos_x='1200um', + pos_y='500um', + orientation='0', + termination_gap='10um') + open_end_meander = OpenToGround(design, + 'Open_meander_end', + options=open_end_options) + meander_options = Dict(pin_inputs=Dict( + start_pin=Dict(component='Open_meander_start', pin='open'), + end_pin=Dict(component='Open_meander_end', pin='open')), + fillet='49.99um', + gds_make_airbridge=True) + testMeander = RouteMixed(design, 'meanderTest', options=meander_options) + + airbridging = Airbridging(design=design, + lib=None, + minx=None, + miny=None, + maxx=None, + maxy=None, + chip_name=None, + precision=0.000001) + ab_placement_result = airbridging.find_uniform_ab_placement( + cpw_name='meanderTest', + bridge_pitch=0.3, # in mm + bridge_minimum_spacing=0.005) # in mm + ab_placement_check = [(1.0, 0.4, 90.0), (1.1, 0.5, 0.0), + (1.0146417320084844, 0.4853582679915155, 45.0)] + self.assertEqual(ab_placement_result, ab_placement_check) + + test_ab_qgeom = pd.DataFrame({ + 'geometry': [draw.Polygon([(0, 0), (1, 0), (0, 1)])], + 'layer': [1] + }) + df_result = ab_placement_to_df(ab_placement_result, test_ab_qgeom) + + self.assertIn('MultiPoly', df_result) + self.assertIn('layer', df_result) + def test_renderer_gds_check_cheese(self): """Test check_cheese in gds_renderer.py.""" design = designs.DesignPlanar() From a0ac02c8b9ecb8ad08463068cd8485770c3b557d Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Tue, 27 Jun 2023 00:34:35 -1000 Subject: [PATCH 54/57] fixed tests --- qiskit_metal/tests/test_designs.py | 3 ++- qiskit_metal/tests/test_renderers.py | 11 +++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/qiskit_metal/tests/test_designs.py b/qiskit_metal/tests/test_designs.py index 3cdc312b0..d8f1e8038 100644 --- a/qiskit_metal/tests/test_designs.py +++ b/qiskit_metal/tests/test_designs.py @@ -503,7 +503,7 @@ def test_design_get_list_of_tables_in_metadata(self): result = q1._get_table_values_from_renderers(design) - self.assertEqual(len(result), 17) + self.assertEqual(len(result), 18) self.assertEqual(result['hfss_inductance'], '10nH') self.assertEqual(result['hfss_capacitance'], 0) self.assertEqual(result['hfss_resistance'], 0) @@ -517,6 +517,7 @@ def test_design_get_list_of_tables_in_metadata(self): self.assertEqual(result['q3d_wire_bonds'], False) self.assertEqual(result['aedt_hfss_inductance'], 10e-9) self.assertEqual(result['aedt_hfss_capacitance'], 0) + self.assertEqual(result['gds_make_airbridge'], False) if __name__ == '__main__': diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index 559038d59..62c32c4b0 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -23,7 +23,7 @@ from unittest.mock import MagicMock import matplotlib.pyplot as _plt -from qiskit_metal import designs +from qiskit_metal import designs, Dict, draw from qiskit_metal.renderers import setup_default from qiskit_metal.renderers.renderer_ansys.ansys_renderer import QAnsysRenderer from qiskit_metal.renderers.renderer_ansys.q3d_renderer import QQ3DRenderer @@ -45,7 +45,6 @@ from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround from qiskit_metal.qlibrary.tlines.mixed_path import RouteMixed from qiskit_metal.renderers.renderer_gds.make_airbridge import Airbridging -from qiskit_metal import draw class TestRenderers(unittest.TestCase): @@ -326,7 +325,7 @@ def test_renderer_gdsrenderer_options(self): renderer = QGDSRenderer(design) options = renderer.default_options - self.assertEqual(len(options), 17) + self.assertEqual(len(options), 18) self.assertEqual(options['short_segments_to_not_fillet'], 'True') self.assertEqual(options['check_short_segments_by_scaling_fillet'], '2.0') @@ -553,10 +552,14 @@ def test_renderer_gdsrenderer_high_level(self): self.assertEqual(renderer.name, 'gds') element_table_data = renderer.element_table_data - self.assertEqual(len(element_table_data), 1) + self.assertEqual(len(element_table_data), 2) + self.assertEqual(len(element_table_data['junction']), 1) self.assertEqual(element_table_data['junction']['cell_name'], 'my_other_junction') + + self.assertEqual(len(element_table_data['path'], 1)) + self.assertEqual(element_table_data['path']['make_airbridge'], False) def test_renderer_gdsrenderer_update_units(self): """Test update_units in gds_renderer.py.""" From 9f8edd5b84bfb5ac7cd655ed03e50acbe22577e0 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Tue, 27 Jun 2023 00:38:45 -1000 Subject: [PATCH 55/57] fixed yapf in tests --- qiskit_metal/tests/test_renderers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index 62c32c4b0..00a851170 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -44,6 +44,8 @@ from qiskit_metal.qlibrary.qubits.transmon_pocket import TransmonPocket from qiskit_metal.qlibrary.terminations.open_to_ground import OpenToGround from qiskit_metal.qlibrary.tlines.mixed_path import RouteMixed +from qiskit_metal.renderers.renderer_gds.airbridge import Airbridge_forGDS + from qiskit_metal.renderers.renderer_gds.make_airbridge import Airbridging @@ -557,7 +559,7 @@ def test_renderer_gdsrenderer_high_level(self): self.assertEqual(len(element_table_data['junction']), 1) self.assertEqual(element_table_data['junction']['cell_name'], 'my_other_junction') - + self.assertEqual(len(element_table_data['path'], 1)) self.assertEqual(element_table_data['path']['make_airbridge'], False) From 4e95215591e342c797f78e78cf4b21de238082f6 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Tue, 27 Jun 2023 00:43:18 -1000 Subject: [PATCH 56/57] typo in test_renderer_gdsrenderer_high_level --- qiskit_metal/tests/test_renderers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index 00a851170..9503897ba 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -22,6 +22,7 @@ import unittest from unittest.mock import MagicMock import matplotlib.pyplot as _plt +import pandas as pd from qiskit_metal import designs, Dict, draw from qiskit_metal.renderers import setup_default @@ -560,7 +561,7 @@ def test_renderer_gdsrenderer_high_level(self): self.assertEqual(element_table_data['junction']['cell_name'], 'my_other_junction') - self.assertEqual(len(element_table_data['path'], 1)) + self.assertEqual(len(element_table_data['path']), 1) self.assertEqual(element_table_data['path']['make_airbridge'], False) def test_renderer_gdsrenderer_update_units(self): From 9b5e9bffdc5e16b2a0eb37943f01dd1e7f50b286 Mon Sep 17 00:00:00 2001 From: clarkmiyamoto Date: Tue, 27 Jun 2023 00:47:50 -1000 Subject: [PATCH 57/57] typo in test --- qiskit_metal/tests/test_renderers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit_metal/tests/test_renderers.py b/qiskit_metal/tests/test_renderers.py index 9503897ba..df2cb3b73 100644 --- a/qiskit_metal/tests/test_renderers.py +++ b/qiskit_metal/tests/test_renderers.py @@ -655,7 +655,8 @@ def test_renderer_gds_check_uniform_airbridge(self): 'geometry': [draw.Polygon([(0, 0), (1, 0), (0, 1)])], 'layer': [1] }) - df_result = ab_placement_to_df(ab_placement_result, test_ab_qgeom) + df_result = airbridging.ab_placement_to_df( + ab_placement=ab_placement_result, ab_qgeom=test_ab_qgeom) self.assertIn('MultiPoly', df_result) self.assertIn('layer', df_result)