From 3860c18e38b6f2135dcabc52a7dfa3ca7afff536 Mon Sep 17 00:00:00 2001 From: Jukka Date: Wed, 25 Sep 2024 12:21:41 +0300 Subject: [PATCH] Modify curved waveguide discretization method such that length is conserved --- .../elements/waveguide_coplanar_curved.py | 26 ++++++++++++++----- .../test_waveguide_length.py | 10 ++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/klayout_package/python/kqcircuits/elements/waveguide_coplanar_curved.py b/klayout_package/python/kqcircuits/elements/waveguide_coplanar_curved.py index c1fdf76c6..4502e48e4 100644 --- a/klayout_package/python/kqcircuits/elements/waveguide_coplanar_curved.py +++ b/klayout_package/python/kqcircuits/elements/waveguide_coplanar_curved.py @@ -17,7 +17,7 @@ # and organizations (meetiqm.com/iqm-organization-contributor-license-agreement). -from math import pi, sin, cos +from math import pi, sin, cos, ceil from kqcircuits.elements.element import Element from kqcircuits.pya_resolver import pya @@ -26,7 +26,7 @@ from kqcircuits.elements.waveguide_coplanar_straight import WaveguideCoplanarStraight -def arc(r, start, stop, n): +def arc(r, start, stop, n, mode=1): """Returns list of points of an arc Args: @@ -34,16 +34,29 @@ def arc(r, start, stop, n): start: begin angle in radians stop: end angle in radians n: number of corners in full circle + mode: discretization method, 0=shortcut, 1=match length, other=detour .. MARKERS_FOR_PNG 0,91 0,100 """ - n_steps = max(round(abs(stop - start) * n / (2 * pi)), 1) - step = (stop - start) / n_steps - r_corner = r / cos(step / 2) + match mode: + case 0: # shortcut method, where points are on the arc + end_ratio = 1.0 + r_scale = lambda _: 1.0 + case 1: # matching length method, where combined length of segments equals the analytical length of the arc + end_ratio = 0.7339449 # based on trigonometric calculations and a few degree Taylor series approximation + r_scale = lambda x: 1 + x**2 / 24 + x**4 * 7 / 5760 # approximation for x/2 / sin(x/2) that accepts x=0 + case _: # detour method, where segments are tangents on the arc + end_ratio = 0.5 + r_scale = lambda x: 1.0 / cos(x / 2) + + c_steps = 2 * end_ratio - 1 # nominal constant steps at start and end + n_steps = max(round(abs(stop - start) * n / (2 * pi) - c_steps), ceil(1 - c_steps)) + step = (stop - start) / (n_steps + c_steps) + r_corner = r * r_scale(step) pts = [pya.DPoint(r * cos(start), r * sin(start))] for i in range(n_steps): - alpha = start + step * (i + 0.5) + alpha = start + step * (i + end_ratio) pts.append(pya.DPoint(r_corner * cos(alpha), r_corner * sin(alpha))) pts.append(pya.DPoint(r * cos(stop), r * sin(stop))) return pts @@ -88,6 +101,7 @@ def build_geometry(element, trans, alpha): shape = round_dpath_width(pya.DPath(pts, element.a), element.layout.dbu) element.cell.shapes(element.get_layer("waveguide_path")).insert(trans * shape) if element.add_metal: + shape = pya.DPolygon(left_inner_arc + list(reversed(right_inner_arc))) element.cell.shapes(element.get_layer("base_metal_addition")).insert(trans * shape) # Protection layer diff --git a/tests/elements/waveguide_coplanar/test_waveguide_length.py b/tests/elements/waveguide_coplanar/test_waveguide_length.py index 1fb4db694..54ee6ea6b 100644 --- a/tests/elements/waveguide_coplanar/test_waveguide_length.py +++ b/tests/elements/waveguide_coplanar/test_waveguide_length.py @@ -16,10 +16,11 @@ # Please see our contribution agreements for individuals (meetiqm.com/iqm-individual-contributor-license-agreement) # and organizations (meetiqm.com/iqm-organization-contributor-license-agreement). +import pytest from kqcircuits.pya_resolver import pya from kqcircuits.elements.waveguide_coplanar import WaveguideCoplanar -from kqcircuits.elements.finger_capacitor_square import FingerCapacitorSquare +from kqcircuits.elements.waveguide_coplanar_curved import WaveguideCoplanarCurved def test_presence_of_length(): @@ -28,3 +29,10 @@ def test_presence_of_length(): waveguide_cell = WaveguideCoplanar.create(layout, path=pya.DPath([pya.DPoint(0, 0), pya.DPoint(0, 99)], 0)) assert hasattr(waveguide_cell, "length") assert waveguide_cell.length() == 99 + + +@pytest.mark.parametrize("n, alpha", [(16, 3), (32, 1), (64, 2), (128, 0.5)]) +def test_length_of_curve(n, alpha): + layout = pya.Layout() + waveguide_cell = WaveguideCoplanarCurved.create(layout, n=n, alpha=alpha, r=100) + assert abs(waveguide_cell.length() - 100 * alpha) <= 0.001