Skip to content

Commit

Permalink
Merge pull request #179 from jevillegasd/SBend
Browse files Browse the repository at this point in the history
Automatic Waveguide SBend
  • Loading branch information
mustafacc authored Aug 26, 2022
2 parents 8e02cd9 + 12ee599 commit efebfbb
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
9 changes: 6 additions & 3 deletions klayout_dot_config/python/SiEPIC/utils/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,12 @@ def _bezier_optimal(angle0, angle3):
except:
from SiEPIC.install import install_scipy
install_scipy()

from scipy.optimize import minimize


try:
from scipy.optimize import minimize
except:
opt = scipy.optimize()
minimize = opt.minimize()


angle0 = fix_angle(angle0)
Expand Down
41 changes: 35 additions & 6 deletions klayout_dot_config/python/SiEPIC/utils/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
TODO: enhance documentation
TODO: make some of the functions in util use these.
"""

from itertools import repeat
import pya
import numpy as np
from numpy import cos, sin, pi, sqrt
import math as m

from functools import reduce
from .sampling import sample_function
from .geometry import rotate90, rotate, bezier_optimal, curve_length
Expand Down Expand Up @@ -243,8 +244,10 @@ def layout_waveguide3(cell, pts, params, debug=True):
'error: this function cannot handle compound waveguides (%s)' % waveguide_type)

# draw the waveguide
sbends = params['sbends'].lower() in ['true', '1', 't', 'y', 'yes'] if 'sbends' in params.keys() else False
waveguide_length = layout_waveguide2(TECHNOLOGY, layout, cell, [wg['layer'] for wg in params['component']], [
wg['width'] for wg in params['component']], [wg['offset'] for wg in params['component']], pts, radius, params['adiabatic'], params['bezier'])
wg['width'] for wg in params['component']], [wg['offset'] for wg in params['component']],
pts, radius, params['adiabatic'], params['bezier'], sbends)

# Draw the marking layers
from SiEPIC.utils import angle_vector
Expand Down Expand Up @@ -338,18 +341,20 @@ def layout_waveguide3(cell, pts, params, debug=True):
- radius: in Microns, e.g., 5
- adiab: 1 = Bezier curve, 0 = radial bend (arc)
- bezier: the bezier parameter, between 0 and 0.45 (almost a radial bend)
- sbends (optional): sbends (Boolean)
Note: bezier parameters need to be simulated and optimized, and will depend on
wavelength, polarization, width, etc. TM and rib waveguides don't benefit from bezier curves
most useful for TE
by Lukas Chrostowski
'''


def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier):
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier, sbends = True):
from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal
from SiEPIC.extend import to_itype
from SiEPIC.utils.geometry import bezier_parallel
from pya import Path, Polygon, Trans

dbu = layout.dbu

if 'Errors' in TECHNOLOGY:
Expand All @@ -365,14 +370,39 @@ def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, ra
layer = layout.layer(TECHNOLOGY[layers[lr]])
width = to_itype(widths[lr], dbu)
offset = to_itype(offsets[lr], dbu)
for i in range(1, len(pts)-1):

it = iter(range(1, len(pts)-1))
for i in it:
turn = ((angle_b_vectors(pts[i]-pts[i-1], pts[i+1]-pts[i])+90) % 360-90)/90
dis1 = pts[i].distance(pts[i-1])
dis2 = pts[i].distance(pts[i+1])
angle = angle_vector(pts[i]-pts[i-1])/90
pt_radius = to_itype(radius, dbu)
error_seg1 = False
error_seg2 = False

#determine if waveguide does an S-Shape
if (sbends) and i < len(pts)-2:
angle2 = angle_vector(pts[i+2]-pts[i+1])/90
if angle == angle2 and dis2<2*pt_radius: # An SBend may be inserted
dis3 = pts[i+2].distance(pts[i+1])
h = pts[i+1].y- pts[i].y if not (angle%2) else pts[i+1].x- pts[i].x
theta = m.acos(float(pt_radius-abs(h/2))/pt_radius)*180/pi
curved_l = int(2*pt_radius*sin(theta/180.0*pi))
if (i > len(pts)-3 or i<3) and (dis1 < curved_l/2 or dis3 < curved_l/2): pass# Check if there is partial clearance for the bend when there is an end near
elif (dis1 - pt_radius) < curved_l/2 or (dis3 - pt_radius) < curved_l/2: pass # Check if there is full clearance for the bend
else:

if not (angle%2):
t = pya.Trans(angle, (angle == 2), pts[i].x+(angle-1)*int(curved_l/2), pts[i].y)
else:
t = pya.Trans(angle, (angle == 1), pts[i].x, pts[i].y-(angle)*int(curved_l/2))
bend_pts = pya.DPath(bezier_parallel(pya.DPoint(0, 0), pya.DPoint(curved_l*dbu, h*dbu), 0),0).to_itype(dbu).transformed(t)
wg_pts += bend_pts.each_point()
turn = 0
i = next(it) #skip the step that was replaced by the SBend
continue

# determine the radius, based on how much space is available
if len(pts) == 3:
# simple corner, limit radius by the two edges
Expand Down Expand Up @@ -402,7 +432,6 @@ def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, ra
if dis2/2 < pt_radius:
error_seg2 = True
pt_radius = min(dis1/2, dis2/2, pt_radius)

if error_seg1 or error_seg2:
if not error_layer:
# we have an error, but no Error layer
Expand Down

0 comments on commit efebfbb

Please sign in to comment.