Skip to content

Commit

Permalink
Etch opposite face feature
Browse files Browse the repository at this point in the history
If 'etch_opposite_face' parameter is true there will be a gap etched into the
opposite face metal like the base metal gap shape in the first face but
increased with 'etch_opposite_face_margin'.

Issue #1347
  • Loading branch information
iqmtestd committed Jan 30, 2024
1 parent 150a018 commit 2293add
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 27 deletions.
32 changes: 13 additions & 19 deletions klayout_package/python/kqcircuits/chips/quality_factor_twoface.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ class QualityFactorTwoface(Chip):
cap_res_distance = Param(pdt.TypeDouble, "Distance between spiral resonator and capacitor", 200)
waveguide_indentation = Param(pdt.TypeDouble, "Waveguide indentation from top chip edge", 500)
extra_resonator_avoidance = Param(pdt.TypeList, "Added avoidance", [0, 0, 0, 0, 0, 0], unit="[μm]",
docstring="Added avoidance around resonators [μm]")
etch_opposite_face_margin = Param(pdt.TypeDouble, "Margin around the waveguide to etch on the opposite face " +
"for 'etched' type resonators", 5)
docstring="Added avoidance around resonators. At both faces.")
extra_resonator_etch = Param(pdt.TypeList, "Added opposite face etch", [0, 0, 0, 0, 0, 0], unit="μm",
docstring="Extra opposite side etching margin around resonators.")

def build(self):
self._produce_resonators()
Expand Down Expand Up @@ -105,14 +105,15 @@ def _produce_resonators(self):

# Create resonators
for i in range(n_resonators):
extra_resonator_etch = float(self.extra_resonator_etch[i]) if i < len(self.extra_resonator_etch) else 0.0
self.produce_resonator(i, float(self.res_a[i]), float(self.res_b[i]), float(self.res_lengths[i]),
float(self.n_fingers[i]), float(self.l_fingers[i]), self.type_coupler[i],
resonator_face_ids, self.resonator_types[i], float(self.connector_distances[i]),
float(self.extra_resonator_avoidance[i]), mirror=(i % 2 == 1))
float(self.extra_resonator_avoidance[i]), extra_resonator_etch, mirror=(i % 2 == 1))

def produce_resonator(self, i, a, b, length, n_fingers, l_fingers, type_coupler, face_ids,
resonator_type="capped", connector_distance=0.0,
extra_resonator_avoidance=0.0, mirror=False):
extra_resonator_avoidance=0.0, extra_resonator_etch=0.0, mirror=False):
"""
Produce a single spiral resonator and corresponding input capacitor.
Expand All @@ -132,6 +133,7 @@ def produce_resonator(self, i, a, b, length, n_fingers, l_fingers, type_coupler,
resonator_type: String, type of resonator, one of ``etched``, ``capped``, ``solid`` or ``twoface``
connector_distance: For ``twoface`` resonators, distance of the flip chip connector starting from capacitor
extra_resonator_avoidance: Extra ``ground_grid_avoidance`` margin around the resonator
extra_resonator_etch: Extra etching on top of ``etch_opposite_face_margin``
mirror: Turn clockwise if False, or counter-clockwise if True.
"""

Expand All @@ -151,7 +153,8 @@ def produce_resonator(self, i, a, b, length, n_fingers, l_fingers, type_coupler,
cplr_params = cap_params(
n_fingers, l_fingers, type_coupler, protect_opposite_face=protect_opposite_face,
face_ids=face_ids, a=self.a_capped, b=self.b_capped, a2=a, b2=b, element_key='cell')
inst_cplr, cplr_refpoints = self.insert_cell(**cplr_params, align="port_a", align_to=start,
_, cplr_refpoints = self.insert_cell(**cplr_params, align="port_a", align_to=start,
etch_opposite_face=(resonator_type == "etched"),
trans=pya.DCplxTrans(1, start_angle, False, 0, 0))

# Spiral resonator
Expand All @@ -161,15 +164,17 @@ def produce_resonator(self, i, a, b, length, n_fingers, l_fingers, type_coupler,
res_params = {
"airbridge_type": "Airbridge Multi Face",
"include_bumps": False,
"bridge_length": a + 2 * (b + self.etch_opposite_face_margin + extra_resonator_avoidance),
"bridge_length": a + 2 * (b + self.etch_opposite_face_margin + extra_resonator_etch),
"bridge_width": 2,
"pad_length": 2,
"bridge_spacing": self.bridge_spacing,
"etch_opposite_face": True,
"etch_opposite_face_margin": self.etch_opposite_face_margin + extra_resonator_etch,
}
else:
res_params = {"bridge_spacing": 0}

inst_res, _ = self.insert_cell(
self.insert_cell(
SpiralResonatorPolygon,
margin=self.margin + extra_resonator_avoidance,
input_path=pya.DPath([
Expand All @@ -190,14 +195,3 @@ def produce_resonator(self, i, a, b, length, n_fingers, l_fingers, type_coupler,
inst_name=f'resonator{i}',
trans=pya.DCplxTrans(1, start_angle, mirror, cplr_refpoints["port_b"])
)

# Top chip etching and grid avoidance above resonator
if resonator_type == "etched":
l0 = self.get_layer("ground_grid_avoidance", int(self.resonator_faces[0]))
region = pya.Region(inst_res.cell.begin_shapes_rec(l0)).transformed(inst_res.trans)
region += pya.Region(inst_cplr.cell.begin_shapes_rec(l0)).transformed(inst_cplr.trans)
region = region.sized((self.etch_opposite_face_margin - self.margin) / self.layout.dbu)
protection_region = region.sized(self.margin / self.layout.dbu)
opposite_face = int(self.resonator_faces[1])
self.cell.shapes(self.get_layer("ground_grid_avoidance", opposite_face)).insert(protection_region)
self.cell.shapes(self.get_layer("base_metal_gap_wo_grid", opposite_face)).insert(region)
19 changes: 18 additions & 1 deletion klayout_package/python/kqcircuits/elements/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ class Element(pya.PCellDeclarationHelper):
"metal between gaps.")
opposing_face_id_groups = Param(pdt.TypeList, "Opposing face ID groups (list of lists)", [["1t1", "2b1"]],
hidden=True)
etch_opposite_face = Param(pdt.TypeBoolean, "Etch avoidance shaped gap on the opposite face too", False)
etch_opposite_face_margin = Param(pdt.TypeDouble, "Margin of the opposite face etch shape", 5, unit="μm")

def __init__(self):
""
Expand Down Expand Up @@ -409,11 +411,26 @@ def produce_impl(self):
text = pya.DText(name, refpoint.x, refpoint.y)
self.cell.shapes(self.get_layer("refpoints")).insert(text)

def _etch_opposite_face(self):
"""Add opposite face etching, if enabled."""
if self.etch_opposite_face:
etch_shape = pya.Region(self.cell.begin_shapes_rec(self.get_layer("ground_grid_avoidance"))).merged()
etch_shape.size((self.etch_opposite_face_margin - self.margin) / self.layout.dbu)
protection = etch_shape.sized(self.margin / self.layout.dbu)
face = self.face_ids[0]
for group in self.opposing_face_id_groups:
if face in group:
for other_face in group:
if other_face != face:
self.cell.shapes(self.get_layer("base_metal_gap_wo_grid", other_face)).insert(etch_shape)
self.cell.shapes(self.get_layer("ground_grid_avoidance", other_face)).insert(protection)

def build(self):
"""Child classes re-define this method to build the PCell."""

def post_build(self):
"""Child classes re-define this method for post-build operations"""
"""Child classes may re-define this method for post-build operations."""
self._etch_opposite_face()

def display_text_impl(self):
if self.display_name:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ def polygon_min_diameter(path):
else:
max_spacing = spacing
self._produce_resonator(optimal_points)
self.add_port("a", optimal_points[0], optimal_points[0] - optimal_points[1])

def _produce_resonator_manual_spacing(self):
"""Produces polygon spiral resonator with spacing defined by `self.manual_spacing`.
Expand All @@ -125,7 +124,6 @@ def _produce_resonator_manual_spacing(self):
self.raise_error_on_cell("Cannot create a resonator with the given parameters. Try decreasing the spacings "
"or the turn radius.", (self.input_path.bbox() + self.poly_path.bbox()).center())
self._produce_resonator(points)
self.add_port("a", points[0], points[0] - points[1])

def _produce_path_points(self, spacing):
"""Creates resonator path points with the given spacing.
Expand Down Expand Up @@ -280,6 +278,8 @@ def _produce_resonator(self, points):
else:
self.insert_cell(WaveguideCoplanar, path=points, term2=term2)

self.add_port("a", points[0], points[0] - points[1])

def _fix_waveguide_end(self, points, current_length):
"""Modifies the last points and places a WaveguideCoplanarCurved element at the end if needed.
Expand Down
4 changes: 3 additions & 1 deletion klayout_package/python/kqcircuits/simulations/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ def produce_waveguide_to_port(self, location, towards, port_nr, side=None,
use_internal_ports=None, waveguide_length=None,
term1=0, turn_radius=None,
a=None, b=None, over_etching=None,
airbridge=False, face=0):
airbridge=False, face=0, etch_opposite_face=False):
"""Create a waveguide connection from some `location` to a port, and add the corresponding port to
`simulation.ports`.
Expand Down Expand Up @@ -793,6 +793,7 @@ def produce_waveguide_to_port(self, location, towards, port_nr, side=None,
term2=0,
a=waveguide_a,
b=waveguide_b,
etch_opposite_face=etch_opposite_face,
face_ids=[self.face_ids[face]]
)

Expand All @@ -806,6 +807,7 @@ def produce_waveguide_to_port(self, location, towards, port_nr, side=None,
b=b,
term1=a-4*over_etching,
term2=0,
etch_opposite_face=etch_opposite_face,
face_ids=[self.face_ids[face]]
)
self.cell.insert(pya.DCellInstArray(port_end_piece.cell_index(), pya.DTrans()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class WaveGuidesSim(Simulation):
add_bumps = Param(pdt.TypeBoolean, "Add ground bumps", False)
port_termination_end = Param(pdt.TypeBoolean, "Port termination end", True)
use_edge_ports = Param(pdt.TypeBoolean, "Use edge ports", True)
etch_opposite_face = Param(pdt.TypeBoolean, "Remove the whole opposite face metal if flip chip", False)
etch_whole_opposite_face = Param(pdt.TypeBoolean, "Remove the whole opposite face metal if flip chip", False)


def build(self):
Expand Down Expand Up @@ -80,7 +80,7 @@ def produce_guides(self):
term2=self.b, face_ids=[guide_face_id])
self.insert_cell(wg_cell)

if self.etch_opposite_face:
if self.etch_whole_opposite_face:
region = pya.Region(self.box.to_itype(self.layout.dbu))
self.cell.shapes(self.get_layer("base_metal_gap_wo_grid", face_id=1)).insert(region)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
'box': pya.DBox(pya.DPoint(-cpw_length/2., -sim_box_height/2.), pya.DPoint(cpw_length/2., sim_box_height/2.)),
'cpw_length': cpw_length,
'face_stack': ['1t1', '2b1'] if multiface else ['1t1'],
'etch_opposite_face': args.etch_opposite_face,
'etch_whole_opposite_face': args.etch_whole_opposite_face,
}

workflow = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
'box': pya.DBox(pya.DPoint(-cpw_length/2., -sim_box_height/2.), pya.DPoint(cpw_length/2., sim_box_height/2.)),
'cpw_length': cpw_length,
'face_stack': ['1t1', '2b1'] if multiface else ['1t1'],
'etch_opposite_face': args.etch_opposite_face,
'etch_whole_opposite_face': args.etch_whole_opposite_face,
'n_guides': 1,
}

Expand Down

0 comments on commit 2293add

Please sign in to comment.