def produce_impl(self): from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal from math import cos, sin, pi, sqrt import pya from SiEPIC.extend import to_itype print("GSiP.Wireguide") TECHNOLOGY = get_technology_by_name( 'GSiP') if op_tag == "GUI" else Tech.load_from_xml( lyp_filepath).layers dbu = self.layout.dbu wg_width = to_itype(self.width, dbu) path = self.path.to_itype(dbu) if not (len(self.layers) == len(self.widths) and len(self.layers) == len(self.offsets) and len(self.offsets) == len(self.widths)): raise Exception( "There must be an equal number of layers, widths and offsets") path.unique_points() turn = 0 for lr in range(0, len(self.layers)): layer = self.layout.layer(TECHNOLOGY[self.layers[lr]]) width = to_itype(self.widths[lr], dbu) offset = to_itype(self.offsets[lr], dbu) pts = path.get_points() wg_pts = [pts[0]] for i in range(1, len(pts) - 1): 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 = self.radius # determine the radius, based on how much space is available if len(pts) == 3: pt_radius = min(dis1, dis2, pt_radius) else: if i == 1: if dis1 <= pt_radius: pt_radius = dis1 elif dis1 < 2 * pt_radius: pt_radius = dis1 / 2 if i == len(pts) - 2: if dis2 <= pt_radius: pt_radius = dis2 elif dis2 < 2 * pt_radius: pt_radius = dis2 / 2 # wireguide bends: if (self.adiab): wg_pts += Path( arc_bezier( pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), self.bezier, DevRec='DevRec' in self.layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path( arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), DevRec='DevRec' in self.layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Path(wg_pts, wg_width) self.cell.shapes(layer).insert(wg_polygon) # insert the wireguide #if self.layout.layer(TECHNOLOGY['Wireguide']) == layer: waveguide_length = wg_polygon.area() / self.width * dbu**2 pts = path.get_points() LayerPinRecN = self.layout.layer(TECHNOLOGY['PinRecM']) # insert pins to wireguide t1 = Trans(angle_vector(pts[0] - pts[1]) / 90, False, pts[0]) self.cell.shapes(LayerPinRecN).insert( Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t1)) self.cell.shapes(LayerPinRecN).insert(Text("pin1", t1, 0.3 / dbu, -1)) t = Trans(angle_vector(pts[-1] - pts[-2]) / 90, False, pts[-1]) self.cell.shapes(LayerPinRecN).insert( Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t)) self.cell.shapes(LayerPinRecN).insert(Text("pin2", t, 0.3 / dbu, -1)) LayerDevRecN = self.layout.layer(TECHNOLOGY['DevRec']) # Compact model information angle_vec = angle_vector(pts[0] - pts[1]) / 90 halign = 0 # left angle = 0 pt2 = pts[0] pt3 = pts[0] if angle_vec == 0: # horizontal halign = 2 # right angle = 0 pt2 = pts[0] + Point(0, wg_width) pt3 = pts[0] + Point(0, -wg_width) if angle_vec == 2: # horizontal halign = 0 # left angle = 0 pt2 = pts[0] + Point(0, wg_width) pt3 = pts[0] + Point(0, -wg_width) if angle_vec == 1: # vertical halign = 2 # right angle = 1 pt2 = pts[0] + Point(wg_width, 0) pt3 = pts[0] + Point(-wg_width, 0) if angle_vec == -1: # vertical halign = 0 # left angle = 1 pt2 = pts[0] + Point(wg_width, 0) pt3 = pts[0] + Point(-wg_width, 0)
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier): ''' Create a waveguide, in a specific technology inputs - TECHNOLOGY, layout, cell: from SiEPIC.utils import get_layout_variables TECHNOLOGY, lv, layout, cell = get_layout_variables() - layers: list of text names, e.g., ['Waveguide'] - widths: list of floats in units Microns, e.g., [0.50] - offsets: list of floats in units Microns, e.g., [0] - pts: a list of pya.Points, e.g. L=15/dbu pts = [Point(0,0), Point(L,0), Point(L,L)] - 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) 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 ''' 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 pya import Path, Polygon, Trans dbu = layout.dbu width=widths[0] turn=0 waveguide_length = 0 for lr in range(0, len(layers)): wg_pts = [pts[0]] 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): 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) # determine the radius, based on how much space is available if len(pts)==3: pt_radius = min (dis1, dis2, pt_radius) else: if i==1: if dis1 <= pt_radius: pt_radius = dis1 elif dis1 < 2*pt_radius: pt_radius = dis1/2 if i==len(pts)-2: if dis2 <= pt_radius: pt_radius = dis2 elif dis2 < 2*pt_radius: pt_radius = dis2/2 # waveguide bends: if abs(turn)==1: if(adiab): wg_pts += Path(arc_bezier(pt_radius, 270, 270 + inner_angle_b_vectors(pts[i-1]-pts[i], pts[i+1]-pts[i]), bezier, DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path(arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors(pts[i-1]-pts[i], pts[i+1]-pts[i]),DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Polygon(translate_from_normal(wg_pts, width/2 + (offset if turn > 0 else - offset))+translate_from_normal(wg_pts, -width/2 + (offset if turn > 0 else - offset))[::-1]) cell.shapes(layer).insert(wg_polygon) if layout.layer(TECHNOLOGY['Waveguide']) == layer: waveguide_length = wg_polygon.area() / width * dbu return waveguide_length
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier): 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 pya import Path, Polygon, Trans dbu = layout.dbu if 'Errors' in TECHNOLOGY: error_layer = layout.layer(TECHNOLOGY['Errors']) else: error_layer = None width = widths[0] turn = 0 waveguide_length = 0 for lr in range(0, len(layers)): wg_pts = [pts[0]] 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): 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 the radius, based on how much space is available if len(pts) == 3: # simple corner, limit radius by the two edges if dis1 < pt_radius: error_seg1 = True if dis2 < pt_radius: error_seg2 = True pt_radius = min(dis1, dis2, pt_radius) else: if i == 1: # first corner, limit radius by first edge, or 1/2 of second one if dis1 < pt_radius: error_seg1 = True if dis2 / 2 < pt_radius: error_seg2 = True pt_radius = min(dis1, dis2 / 2, pt_radius) elif i == len(pts) - 2: # last corner, limit radius by second edge, or 1/2 of first one if dis1 / 2 < pt_radius: error_seg1 = True if dis2 < pt_radius: error_seg2 = True pt_radius = min(dis1 / 2, dis2, pt_radius) else: if dis1 / 2 < pt_radius: error_seg1 = True 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 print('- SiEPIC:layout_waveguide2: missing Error layer') # and pt_radius < to_itype(radius,dbu): elif layer == layout.layer(TECHNOLOGY['Waveguide']): # add an error polygon to flag the incorrect bend if error_seg1: error_pts = pya.Path([pts[i - 1], pts[i]], width) cell.shapes(error_layer).insert(error_pts) if error_seg2: error_pts = pya.Path([pts[i], pts[i + 1]], width) cell.shapes(error_layer).insert(error_pts) # error_pts = pya.Path([pts[i-1], pts[i], pts[i+1]], width) # cell.shapes(error_layer).insert(error_pts) # waveguide bends: if abs(turn) == 1: if (adiab): wg_pts += Path( arc_bezier( pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), float(bezier), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path( arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Polygon( translate_from_normal( wg_pts, width / 2 + (offset if turn > 0 else -offset)) + translate_from_normal( wg_pts, -width / 2 + (offset if turn > 0 else -offset))[::-1]) cell.shapes(layer).insert(wg_polygon) if layout.layer(TECHNOLOGY['Waveguide']) == layer: waveguide_length = wg_polygon.area() / width * dbu return waveguide_length
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier): 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 pya import Path, Polygon, Trans dbu = layout.dbu width = widths[0] turn = 0 waveguide_length = 0 for lr in range(0, len(layers)): wg_pts = [pts[0]] 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): 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) # determine the radius, based on how much space is available if len(pts) == 3: pt_radius = min(dis1, dis2, pt_radius) else: if i == 1: if dis1 <= pt_radius: pt_radius = dis1 elif dis1 < 2 * pt_radius: pt_radius = dis1 / 2 if i == len(pts) - 2: if dis2 <= pt_radius: pt_radius = dis2 elif dis2 < 2 * pt_radius: pt_radius = dis2 / 2 # waveguide bends: if abs(turn) == 1: if (adiab): wg_pts += Path( arc_bezier( pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), float(bezier), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path( arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Polygon( translate_from_normal( wg_pts, width / 2 + (offset if turn > 0 else -offset)) + translate_from_normal( wg_pts, -width / 2 + (offset if turn > 0 else -offset))[::-1]) cell.shapes(layer).insert(wg_polygon) if layout.layer(TECHNOLOGY['Waveguide']) == layer: waveguide_length = wg_polygon.area() / width * dbu return waveguide_length
def produce_impl(self): # This is the main part of the implementation: create the layout from math import pi, cos, sin from SiEPIC.utils import arc_wg, arc_wg_xy, arc_xy from SiEPIC._globals import PIN_LENGTH from SiEPIC.extend import to_itype, to_dtype # fetch the parameters dbu = self.layout.dbu ly = self.layout shapes = self.cell.shapes LayerSiN = ly.layer(self.silayer) LayerSiRibN = ly.layer(self.siriblayer) LayerNN = ly.layer(self.nlayer) LayerNPPN = ly.layer(self.npplayer) LayerVCN = ly.layer(self.vclayer) LayerMN = ly.layer(self.mlayer) LayerPinRecN = ly.layer(self.pinrec) LayerDevRecN = ly.layer(self.devrec) TextLayerN = ly.layer(self.textl) w = to_itype(self.w, dbu) r = to_itype(self.r, dbu) g = to_itype(self.g, dbu) n_w = to_itype(self.n_w, dbu) npp_si = to_itype(self.npp_si, dbu) npp_w = to_itype(self.npp_w, dbu) theta_start = self.n_theta_start theta_stop = self.n_theta_stop vc_cw = to_itype(self.vc_cw, dbu) vc_aw = to_itype(self.vc_aw, dbu) overlay_ebl = to_itype(self.overlay_ebl, dbu) m_cw = to_itype(self.m_cw, dbu) m_aw = to_itype(self.m_aw, dbu) x = 0 y = 0 #draw ring self.cell.shapes(LayerSiN).insert(arc_wg_xy(x, y, r, w, 0, 360)) #draw bus waveguides #bottom waveguide xtop = -2 / 3 * r ytop = -1 * (r + g + w / 2) xbottom = 4 / 3 * r ybottom = ytop - w wg1 = Box(xtop, ytop, xbottom, ybottom) shapes(LayerSiN).insert(wg1) #left waveguide wg1 = Box(ytop, xtop, ybottom, xbottom) shapes(LayerSiN).insert(wg1) # Pins on the bottom waveguide side: pin = Path([ Point(xtop + PIN_LENGTH, ytop - w / 2), Point(xtop - PIN_LENGTH, ytop - w / 2) ], w) shapes(LayerPinRecN).insert(pin) text = Text("pin1", Trans(Trans.R0, xtop, ytop - w / 2)) shape = shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu pin = Path([ Point(xbottom - PIN_LENGTH, ytop - w / 2), Point(xbottom + PIN_LENGTH, ytop - w / 2) ], w) shapes(LayerPinRecN).insert(pin) text = Text("pin2", Trans(Trans.R0, xbottom, ytop - w / 2)) shape = shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu # Pins on the left waveguide side: pin = Path([ Point(ytop - w / 2, xtop + PIN_LENGTH), Point(ytop - w / 2, xtop - PIN_LENGTH) ], w) shapes(LayerPinRecN).insert(pin) text = Text("pin3", Trans(Trans.R0, ytop - w / 2, xtop)) shape = shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu pin = Path([ Point(ybottom + w / 2, xbottom - PIN_LENGTH), Point(ybottom + w / 2, xbottom + PIN_LENGTH) ], w) shapes(LayerPinRecN).insert(pin) text = Text("pin4", Trans(Trans.R0, ybottom + w / 2, xbottom)) shape = shapes(LayerPinRecN).insert(text) shape.text_size = 0.4 / dbu #draw N arc_pts = arc_xy(x, y, n_w, theta_start, theta_stop) arc_pts.append(pya.Point.from_dpoint(pya.DPoint( 0, 0))) #adding center point for polygon shapes(LayerNN).insert(pya.Polygon(arc_pts)) #draw NPP #center arc_pts = arc_xy(x, y, r - npp_si - w / 2, 0, 360) arc_pts.append(pya.Point.from_dpoint(pya.DPoint( 0, 0))) #adding center point for polygon shapes(LayerNPPN).insert(pya.Polygon(arc_pts)) #outer donut shapes(LayerNPPN).insert( arc_wg_xy(x, y, r + w / 2 + npp_si + npp_w / 2, npp_w, theta_start, theta_stop)) #draw via #center arc_pts = arc_xy(x, y, vc_cw, 0, 360) arc_pts.append(pya.Point.from_dpoint(pya.DPoint( 0, 0))) #adding center point for polygon shapes(LayerVCN).insert(pya.Polygon(arc_pts)) #outer donut shapes(LayerVCN).insert( arc_wg_xy(x, y, 4 / dbu + r + npp_w / 2, vc_aw, theta_start + 10, theta_stop - 10)) #draw metal #center arc_pts = arc_xy(x, y, m_cw, 0, 360) arc_pts.append(pya.Point.from_dpoint(pya.DPoint( 0, 0))) #adding center point for polygon shapes(LayerMN).insert(pya.Polygon(arc_pts)) #outer donut shapes(LayerMN).insert( arc_wg_xy(x, y, 4 / dbu + r + npp_w / 2, m_aw, theta_start, theta_stop)) #devrec layer xtop = -2 / 3 * r ytop = -1 * (r + g + w) xbottom = 4 / 3 * r ybottom = ytop dev_array = [ Point(ytop + 3.5 * w, xbottom + npp_w), Point(ytop + 3.5 * w, xbottom), Point(ytop - 3.5 * w, xbottom), Point(ytop - 3.5 * w, xtop), Point(ytop + 3.5 * w, xtop), Point(xtop, ybottom + 3.5 * w), Point(xtop, ybottom - 3 * w), Point(xbottom, ybottom - 3.5 * w), Point(xbottom, ybottom + 3.5 * w), Point(xbottom + npp_w, ybottom + 3.5 * w), Point(xbottom + npp_w, xbottom + npp_w) ] shapes(LayerDevRecN).insert(pya.Polygon(dev_array)) if self.io_wg_type == 0: # strip converter taper_long = to_itype(10, dbu) taper_short = to_itype(3, dbu) dev_array = [ Point(ytop + 3.5 * w, xbottom + npp_w), Point(ytop + 3.5 * w, xbottom - taper_long), Point(ytop + 2.5 * w, xbottom - taper_long), Point(ytop + w / 2 - overlay_ebl * 2, xbottom), Point(ytop - w / 2 + overlay_ebl * 2, xbottom), Point(ytop - 2.5 * w, xbottom - taper_long), Point(ytop - 3.5 * w, xbottom - taper_long), Point(ytop - 3.5 * w, xtop + taper_short), Point(ytop - 1.5 * w, xtop + taper_short), Point(ytop - w / 2 + overlay_ebl * 2, xtop), Point(ytop + w / 2 - overlay_ebl * 2, xtop), Point(ytop + 1.5 * w, xtop + taper_short), Point(ytop + 3.5 * w, xtop + taper_short), Point((ytop + 3.5 * w + xtop) / 2, (xtop + ybottom + 3.5 * w) / 2), Point(xtop + taper_short, ybottom + 3.5 * w), Point(xtop + taper_short, ybottom + 1.5 * w), Point(xtop, ybottom + w / 2 - overlay_ebl * 2), Point(xtop, ybottom - w / 2 + overlay_ebl * 2), Point(xtop + taper_short, ybottom - 1.5 * w), Point(xtop + taper_short, ybottom - 3.5 * w), Point(xbottom - taper_long, ybottom - 3.5 * w), Point(xbottom - taper_long, ybottom - 2.5 * w), Point(xbottom, ybottom - w / 2 + overlay_ebl * 2), Point(xbottom, ybottom + w / 2 - overlay_ebl * 2), Point(xbottom - taper_long, ybottom + 2.5 * w), Point(xbottom - taper_long, ybottom + 3.5 * w), Point(xbottom + npp_w, ybottom + 3.5 * w), Point(xbottom + npp_w, xbottom + npp_w) ] # Si rib layer shapes(LayerSiRibN).insert(pya.Polygon(dev_array)) t = Trans(Trans.R0, 0, 0) text = Text('Component=ebeam_irph_mrr', t) shape = shapes(LayerDevRecN).insert(text) shape.text_size = self.r * 0.07 / dbu print("Done drawing the layout for - ebeam_IRPH_MRR: %.3f-%g" % (self.r, self.g))