Skip to content

Commit

Permalink
Create and use evaluation functions for a2 and b2
Browse files Browse the repository at this point in the history
Move static methods `Element.left_and_right_waveguides` and `Element.face_changer_waveguides` to `FingerCapacitorSquare.get_sim_ports` and `FlipChipConnectorRf.get_sim_ports`, respectively. These are the logical places for them.
  • Loading branch information
jukkarabina committed Dec 20, 2024
1 parent e4224c8 commit 3353e3a
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 86 deletions.
11 changes: 4 additions & 7 deletions klayout_package/python/kqcircuits/elements/circular_capacitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from kqcircuits.util.parameters import Param, pdt, add_parameters_from
from kqcircuits.util.geometry_helper import circle_polygon, arc_points
from kqcircuits.elements.element import Element
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare, eval_a2, eval_b2


@add_parameters_from(FingerCapacitorSquare, "fixed_length", "a2", "b2")
Expand Down Expand Up @@ -57,11 +57,8 @@ class CircularCapacitor(Element):
ground_gap = Param(pdt.TypeDouble, "Ground plane padding", 20, unit="μm")

def build(self):
self.a2 = self.a if self.a2 < 0 else self.a2
self.b2 = self.b if self.b2 < 0 else self.b2

y_left = self.a / 2
y_right = self.a2 / 2
y_right = eval_a2(self) / 2
x_end = self.r_outer + self.ground_gap

capacitor_region = []
Expand Down Expand Up @@ -147,7 +144,7 @@ def _add_ground_region(self, x_end):
island_ground = circle_polygon(self.r_outer + self.ground_gap, self.n)
ground_region.append(island_ground)
ground_region = pya.Region([poly.to_itype(self.layout.dbu) for poly in ground_region])
self._add_waveguides(ground_region, x_end, self.a / 2 + self.b, self.a2 / 2 + self.b2)
self._add_waveguides(ground_region, x_end, self.a / 2 + self.b, eval_a2(self) / 2 + eval_b2(self))

return ground_region

Expand Down Expand Up @@ -182,4 +179,4 @@ def _add_waveguides(self, region, x_end, y_left, y_right):

@classmethod
def get_sim_ports(cls, simulation):
return Element.left_and_right_waveguides(simulation)
return FingerCapacitorSquare.get_sim_ports(simulation)
36 changes: 1 addition & 35 deletions klayout_package/python/kqcircuits/elements/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from kqcircuits.util.geometry_json_encoder import GeometryJsonDecoder, GeometryJsonEncoder
from kqcircuits.util.library_helper import load_libraries, to_library_name, to_module_name, element_by_class_name
from kqcircuits.util.parameters import Param, pdt
from kqcircuits.util.refpoints import Refpoints, WaveguideToSimPort
from kqcircuits.util.refpoints import Refpoints


def get_refpoints(layer, cell, cell_transf=pya.DTrans(), rec_levels=None):
Expand Down Expand Up @@ -710,40 +710,6 @@ def get_sim_ports(cls, simulation): # pylint: disable=unused-argument
"""
return []

@staticmethod
def left_and_right_waveguides(simulation):
"""A common implementation of get_sim_ports that adds left and right waveguides
to port_a and port_b respectively. The a and b values of right waveguide
can be adjusted separately.
"""
a2 = simulation.a if simulation.a2 < 0 else simulation.a2
b2 = simulation.b if simulation.b2 < 0 else simulation.b2
return [
WaveguideToSimPort("port_a", side="left", a=simulation.a, b=simulation.b),
WaveguideToSimPort("port_b", side="right", a=a2, b=b2),
]

@staticmethod
def face_changer_waveguides(simulation):
"""A common implementation of get_sim_ports that adds waveguides on both sides of a face-changing element.
The port names are '{face_ids[0]}_port' and '{face_ids[1]}_port'.
The first port points to left and the second port orientation is determined by output_rotation parameter.
The a and b values of the second waveguide are adjusted by a2 and b2 parameters.
"""

def diff_to_rotation(x):
return abs(x - (simulation.output_rotation % 360))

side = {0: "left", 90: "bottom", 180: "right", 270: "top", 360: "left"}.get(
min([0, 90, 180, 270, 360], key=diff_to_rotation)
)
a2 = simulation.a if simulation.a2 < 0 else simulation.a2
b2 = simulation.b if simulation.b2 < 0 else simulation.b2
return [
WaveguideToSimPort(f"{simulation.face_ids[0]}_port", side="left"),
WaveguideToSimPort(f"{simulation.face_ids[1]}_port", side=side, face=1, a=a2, b=b2),
]

def _show_epr_cross_section_cuts(self):
if not self._epr_show or self._epr_cross_section_cut_layer is None:
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@
from kqcircuits.util.parameters import Param, pdt, add_parameters_from
from kqcircuits.elements.element import Element
from kqcircuits.elements.finger_capacitor_taper import FingerCapacitorTaper
from kqcircuits.util.refpoints import WaveguideToSimPort


def eval_a2(element):
"""Evaluation function for center conductor width on the other end."""
return element.a if element.a2 < 0 else element.a2


def eval_b2(element):
"""Evaluation function for gap width on the other end."""
return element.b if element.b2 < 0 else element.b2


@add_parameters_from(FingerCapacitorTaper, "*", "taper_length")
Expand Down Expand Up @@ -58,7 +69,7 @@ def can_create_from_shape_impl(self):
def build(self):
y_mid = self.finger_area_width() / 2
y_left = self.a / 2
y_right = (self.a if self.a2 < 0 else self.a2) / 2
y_right = eval_a2(self) / 2
x_mid = self.finger_area_length() / 2
x_left = x_mid + self.finger_width + (self.ground_padding if y_left > y_mid else 0.0)
x_right = x_mid + self.finger_width + (self.ground_padding if y_right > y_mid else 0.0)
Expand Down Expand Up @@ -137,7 +148,7 @@ def get_ground_region(self):
finger_area_width = self.finger_area_width()
y_mid = finger_area_width / 2 + self.ground_padding
y_left = self.a / 2 + self.b
y_right = (self.a if self.a2 < 0 else self.a2) / 2 + (self.b if self.b2 < 0 else self.b2)
y_right = eval_a2(self) / 2 + eval_b2(self)
x_mid = self.finger_area_length() / 2 + self.finger_width
x_left = x_mid + (self.ground_padding if y_left < y_mid else 0.0)
x_right = x_mid + (self.ground_padding if y_right < y_mid else 0.0)
Expand Down Expand Up @@ -235,4 +246,10 @@ def add_waveguides(self, region, x_end, y_left, y_right):

@classmethod
def get_sim_ports(cls, simulation):
return Element.left_and_right_waveguides(simulation)
"""An implementation of get_sim_ports that adds left and right waveguides to port_a and port_b respectively.
The a and b values of right waveguide can be adjusted separately.
"""
return [
WaveguideToSimPort("port_a", side="left", a=simulation.a, b=simulation.b),
WaveguideToSimPort("port_b", side="right", a=eval_a2(simulation), b=eval_b2(simulation)),
]
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
import logging

from kqcircuits.elements.element import Element
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare, eval_a2, eval_b2
from kqcircuits.elements.flip_chip_connectors.flip_chip_connector import FlipChipConnector
from kqcircuits.elements.launcher import Launcher
from kqcircuits.pya_resolver import pya
from kqcircuits.util.parameters import Param, pdt, add_parameters_from
from kqcircuits.util.refpoints import WaveguideToSimPort


@add_parameters_from(FingerCapacitorSquare, "a2", "b2")
Expand Down Expand Up @@ -54,9 +55,6 @@ def build(self):
bump_ref = self.get_refpoints(bump)
logging.debug("bump_ref: %s", bump_ref)

a2 = self.a2 if self.a2 >= 0 else self.a
b2 = self.b2 if self.b2 >= 0 else self.b

if self.round_connector:
# Rounded geometry
def rounded_plate(center_x, width, length):
Expand Down Expand Up @@ -109,7 +107,7 @@ def produce_shape(face, a, b, rotation, trace_rotation):
)

produce_shape(0, self.a, self.b, 0, 0)
produce_shape(1, a2, b2, 180, self.output_rotation - 180)
produce_shape(1, eval_a2(self), eval_b2(self), 180, self.output_rotation - 180)

else:
# Taper geometry
Expand Down Expand Up @@ -175,8 +173,8 @@ def produce_shape(face, a, b, rotation, trace_rotation):
b_launcher=self.connector_b,
launcher_frame_gap=self.connector_b,
face_ids=[self.face_ids[1], self.face_ids[0]],
a=a2,
b=b2,
a=eval_a2(self),
b=eval_b2(self),
add_metal=add_metal,
)

Expand All @@ -196,4 +194,21 @@ def _get_bump(self):

@classmethod
def get_sim_ports(cls, simulation):
return Element.face_changer_waveguides(simulation)
"""An implementation of get_sim_ports that adds waveguides on both sides of a face-changing element.
The port names are '{face_ids[0]}_port' and '{face_ids[1]}_port'.
The first port points to left and the second port orientation is determined by output_rotation parameter.
The a and b values of the second waveguide are adjusted by a2 and b2 parameters.
"""

def diff_to_rotation(x):
return abs(x - (simulation.output_rotation % 360))

side = {0: "left", 90: "bottom", 180: "right", 270: "top", 360: "left"}.get(
min([0, 90, 180, 270, 360], key=diff_to_rotation)
)
return [
WaveguideToSimPort(f"{simulation.face_ids[0]}_port", side="left"),
WaveguideToSimPort(
f"{simulation.face_ids[1]}_port", side=side, face=1, a=eval_a2(simulation), b=eval_b2(simulation)
),
]
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from kqcircuits.pya_resolver import pya
from kqcircuits.util.parameters import Param, pdt, add_parameters_from
from kqcircuits.elements.element import Element
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare, eval_a2, eval_b2


def unit_vector(radians):
Expand Down Expand Up @@ -172,8 +172,7 @@ def build(self):
region_ground = right_fingers + left_fingers
region_ground.size(self.ground_gap / self.layout.dbu, 5)
region_ground += self.middle_gap_fill()
a2 = self.a if self.a2 < 0 else self.a2
b2 = self.b if self.b2 < 0 else self.b2
a2, b2 = eval_a2(self), eval_b2(self)
self.insert_wg_joint(region_ground, xport, x_mid - self.ground_gap, b2 + a2 / 2)
self.insert_wg_joint(region_ground, -xport, -x_mid + self.ground_gap, self.b + self.a / 2)
region_ground = self.super_smoothen_region(region_ground, self.finger_gap + self.ground_gap)
Expand Down Expand Up @@ -220,4 +219,4 @@ def build(self):

@classmethod
def get_sim_ports(cls, simulation):
return Element.left_and_right_waveguides(simulation)
return FingerCapacitorSquare.get_sim_ports(simulation)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from math import pi, cos, sqrt

from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare, eval_a2, eval_b2
from kqcircuits.elements.smooth_capacitor import SmoothCapacitor, unit_vector, segment_points
from kqcircuits.pya_resolver import pya
from kqcircuits.util.geometry_helper import get_angle
Expand Down Expand Up @@ -120,8 +121,7 @@ def port_position(position, direction, distance):
return position + (distance - direction.sprod(position.to_v())) * direction

# Process terms on the right
a2 = self.a if self.a2 < 0 else self.a2
b2 = self.b if self.b2 < 0 else self.b2
a2, b2 = eval_a2(self), eval_b2(self)
finger_width2 = self.finger_width if self.finger_width2 < 0 else self.finger_width2
ground_gap2 = self.ground_gap if self.ground_gap2 < 0 else self.ground_gap2
spiral_angle2 = self.spiral_angle if self.spiral_angle2 < 0 else self.spiral_angle2
Expand Down Expand Up @@ -178,4 +178,4 @@ def port_position(position, direction, distance):

@classmethod
def get_sim_ports(cls, simulation):
return Element.left_and_right_waveguides(simulation)
return FingerCapacitorSquare.get_sim_ports(simulation)
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from kqcircuits.elements.element import Element
from kqcircuits.pya_resolver import pya
from kqcircuits.util.parameters import Param, pdt, add_parameters_from
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare
from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare, eval_a2, eval_b2
from kqcircuits.elements.waveguide_coplanar_straight import WaveguideCoplanarStraight


Expand All @@ -38,30 +38,30 @@ class WaveguideCoplanarTaper(Element):
m2 = Param(pdt.TypeDouble, "Margin of right waveguide protection layer", 5 * 2, unit="μm")

def build(self):
#
a2, b2 = eval_a2(self), eval_b2(self)
# gap 1
pts = [
pya.DPoint(0, self.a / 2 + 0),
pya.DPoint(self.taper_length, self.a2 / 2 + 0),
pya.DPoint(self.taper_length, self.a2 / 2 + self.b2),
pya.DPoint(self.taper_length, a2 / 2 + 0),
pya.DPoint(self.taper_length, a2 / 2 + b2),
pya.DPoint(0, self.a / 2 + self.b),
]
shape = pya.DPolygon(pts)
self.cell.shapes(self.get_layer("base_metal_gap_wo_grid")).insert(shape)
# gap 2
pts = [
pya.DPoint(0, -self.a / 2 + 0),
pya.DPoint(self.taper_length, -self.a2 / 2 + 0),
pya.DPoint(self.taper_length, -self.a2 / 2 - self.b2),
pya.DPoint(self.taper_length, -a2 / 2 + 0),
pya.DPoint(self.taper_length, -a2 / 2 - b2),
pya.DPoint(0, -self.a / 2 - self.b),
]
shape = pya.DPolygon(pts)
self.cell.shapes(self.get_layer("base_metal_gap_wo_grid")).insert(shape)
# Protection layer
pts = [
pya.DPoint(0, -self.a / 2 - self.b - self.margin),
pya.DPoint(self.taper_length, -self.a2 / 2 - self.b2 - self.m2),
pya.DPoint(self.taper_length, self.a2 / 2 + self.b2 + self.m2),
pya.DPoint(self.taper_length, -a2 / 2 - b2 - self.m2),
pya.DPoint(self.taper_length, a2 / 2 + b2 + self.m2),
pya.DPoint(0, self.a / 2 + self.b + self.margin),
]
self.add_protection(pya.DPolygon(pts))
Expand All @@ -71,8 +71,8 @@ def build(self):
shape = pya.DPolygon(
[
pya.DPoint(0, self.a / 2),
pya.DPoint(self.taper_length, self.a2 / 2),
pya.DPoint(self.taper_length, -self.a2 / 2),
pya.DPoint(self.taper_length, a2 / 2),
pya.DPoint(self.taper_length, -a2 / 2),
pya.DPoint(0, -self.a / 2),
]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from kqcircuits.simulations.partition_region import PartitionRegion
from kqcircuits.simulations.simulation import Simulation
from kqcircuits.util.geometry_helper import arc_points
from kqcircuits.elements.finger_capacitor_square import eval_a2, eval_b2

# Partition region and correction cuts definitions for CircularCapacitor element

Expand Down Expand Up @@ -53,13 +54,6 @@ def _waveguide_end_dist(simulation):
return simulation.box.width() / 2


def _get_ab2(simulation):
"""Get the correct a2 and b2 used in the geometry"""
a2 = simulation.a if simulation.a2 < 0 else simulation.a2
b2 = simulation.b if simulation.b2 < 0 else simulation.b2
return a2, b2


def partition_regions(simulation: EPRTarget, prefix: str = "") -> list[PartitionRegion]:

mer_x_dim = 3.0
Expand Down Expand Up @@ -169,7 +163,7 @@ def _angle_from_x(p, origin=center):
center + pya.DPoint(-r_tot - metal_edge_margin, -simulation.a / 2 - metal_edge_margin),
center + pya.DPoint(-simulation.r_inner + metal_edge_margin, simulation.a / 2 + metal_edge_margin),
)
a2, b2 = _get_ab2(simulation)
a2, b2 = eval_a2(simulation), eval_b2(simulation)
lead2_region = pya.DBox(
center + pya.DPoint(r_coupler_out - metal_edge_margin, -a2 / 2 - metal_edge_margin),
center + pya.DPoint(r_tot + metal_edge_margin, a2 / 2 + metal_edge_margin),
Expand Down Expand Up @@ -241,7 +235,7 @@ def correction_cuts(simulation: EPRTarget, prefix: str = "") -> dict[str, dict]:
s_to_s_gap = simulation.chip_distance + 2 * simulation.metal_height
z_me = -simulation.substrate_height[1] - s_to_s_gap if is_flip_chip else 0

a2, b2 = _get_ab2(simulation)
a2, b2 = eval_a2(simulation), eval_b2(simulation)

def _coupler_cut_lim(unit_vec, start_p, origin_p, rlim):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from kqcircuits.simulations.partition_region import PartitionRegion
from kqcircuits.simulations.epr.utils import in_gui, EPRTarget
from kqcircuits.elements.smooth_capacitor import SmoothCapacitor
from kqcircuits.elements.finger_capacitor_square import eval_a2, eval_b2


# Partition region and correction cuts definitions for Swissmon qubit
Expand All @@ -32,8 +33,7 @@ def partition_regions(simulation: EPRTarget, prefix: str = "") -> list[Partition
port_a_rf = simulation.refpoints["port_a"]
port_b_rf = simulation.refpoints["port_b"]

a2 = simulation.a if simulation.a2 < 0 else simulation.a2
b2 = simulation.b if simulation.b2 < 0 else simulation.b2
a2, b2 = eval_a2(simulation), eval_b2(simulation)

# Make a stub SmoothCapacitor instance, copy some attributes
# then use some region generating functions to create a partition region shape overlapping finger edges
Expand Down Expand Up @@ -180,8 +180,7 @@ def correction_cuts(simulation: EPRTarget, prefix: str = "") -> dict[str, dict]:
port_a_rf = simulation.refpoints["port_a"]
port_b_rf = simulation.refpoints["port_b"]

a2 = simulation.a if simulation.a2 < 0 else simulation.a2
b2 = simulation.b if simulation.b2 < 0 else simulation.b2
a2, b2 = eval_a2(simulation), eval_b2(simulation)

gaps = pya.Region(simulation.cell.begin_shapes_rec(simulation.get_layer("base_metal_gap_wo_grid")))
finger_top = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from kqcircuits.pya_resolver import pya
from kqcircuits.simulations.epr.utils import in_gui, EPRTarget
from kqcircuits.simulations.partition_region import PartitionRegion
from kqcircuits.elements.finger_capacitor_square import eval_a2, eval_b2

vertical_dimension = 1.0
metal_edge_dimension = 1.0
Expand Down Expand Up @@ -52,9 +53,7 @@ def partition_regions(simulation: EPRTarget, prefix: str = "") -> list[Partition
]
).to_itype(simulation.layout.dbu)
)
a2 = simulation.a if simulation.a2 < 0 else simulation.a2
b2 = simulation.b if simulation.b2 < 0 else simulation.b2
rb = a2 / 2 + b2 + waveguide_margin
rb = eval_a2(simulation) / 2 + eval_b2(simulation) + waveguide_margin
port_b = simulation.refpoints["port_b"]
dir_b = waveguide_length_scale * (simulation.refpoints["port_b_corner"] - port_b)
cross_b = rb / dir_b.abs() * pya.DVector(dir_b.y, -dir_b.x)
Expand Down

0 comments on commit 3353e3a

Please sign in to comment.