From 83205fdb0e05617c50d2835dd40187f3403f2d87 Mon Sep 17 00:00:00 2001 From: Hang Zou <45744171+Hang-Bobby-Zou@users.noreply.github.com> Date: Tue, 7 Nov 2023 23:30:04 -0800 Subject: [PATCH 1/2] Added PCell - Bobby --- .../pymacros/pcells_EBeam_Beta/e_skid.py | 310 ++++++++++++++++++ .../pcells_EBeam_Beta/e_skid_left_taper.py | 310 ++++++++++++++++++ .../pymacros/pcells_EBeam_Beta/e_skid_ring.py | 169 ++++++++++ .../pymacros/pcells_EBeam_Beta/strip_taper.py | 90 +++++ 4 files changed, 879 insertions(+) create mode 100644 klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py create mode 100644 klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_left_taper.py create mode 100644 klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py create mode 100644 klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py new file mode 100644 index 00000000..d0cfbb94 --- /dev/null +++ b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py @@ -0,0 +1,310 @@ +import pya +from . import * +from SiEPIC.utils import get_technology_by_name +from SiEPIC._globals import PIN_LENGTH as pin_length +from pya import DPolygon +import math + +#==================================================================================================== +# File: e_skid.py +# Author: Hang (Bobby) Zou +# Purpose: PCell in EBeam library for a common parallel e-skid design that have adjustable period +# and fill factor +# Version: V1.2 +# Date: 2023-05-11 +#==================================================================================================== + +class e_skid(pya.PCellDeclarationHelper): + + def __init__(self): + + # Important: initialize the super class + super(e_skid, self).__init__() + self.technology_name = 'EBeam' + + TECHNOLOGY = get_technology_by_name(self.technology_name) + + # e_skid Parameters: + # core parameter + self.param('divider0', self.TypeBoolean, '==============Core Parameter==============') + + self.param('w', self.TypeDouble, 'Core Waveguide Width [um]' , default = 0.3) + + self.param('divider1', self.TypeBoolean, '==============Clad Parameter==============') + + # clad parameter + self.param('p', self.TypeDouble, 'e-skid Period [um]' , default = 0.1) + self.param('ff', self.TypeDouble, 'e-skid Fill Factor [0.2-0.8]' , default = 0.5) + self.param('p_num', self.TypeInt, 'e-skid Period Number' , default = 5) + self.param('length', self.TypeDouble, 'Length of e-skid Waveguide [um]' , default = 10) + + self.param('divider2', self.TypeBoolean, '==============Taper Parameter=============') + + # taper + self.param('taper_True', self.TypeBoolean, 'Taper [T/F]' , default = True) + self.param('taperL', self.TypeDouble, 'Strip -> e-skid Taper Length [um]' , default = 5) + self.param('taperW', self.TypeDouble, 'Strip Width [um]' , default = 0.5) + + self.param('divider3', self.TypeBoolean, '============Extended Clad Parameter==========') + + # extended clad parameter + self.param('clad_taper_L', self.TypeDouble, 'Extended e-skid Length [um]' , default = 5) + self.param('clad_taper_angle', self.TypeDouble,'Extended e-skid Angle [degree]' , default = 2) + + self.param('divider4', self.TypeBoolean, '=====================================') + + # Layer Parameters - Don't touch + self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si']) + self.param("pinrec", self.TypeLayer, "PinRec Layer", default = TECHNOLOGY['PinRec']) + self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec']) + self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)']) + + + # Creating the layout + def produce_impl(self): + + # Layout Parameters + dbu = self.layout.dbu + ly = self.layout + shapes = self.cell.shapes + + LayerSi = self.layer + LayerSiN = ly.layer(LayerSi) + LayerPinRecN = ly.layer(self.pinrec) + LayerDevRecN = ly.layer(self.devrec) + + w = self.w # Core Waveguide Width [um] + p = self.p # e-skid Period [um] + ff = self.ff # e-skid Duty Cycle [%] + p_num = self.p_num # e-skid Period Number + length = self.length # e-skid Waveguide Length [um] + + taper_True = self.taper_True # e-skid Taper [T/F] + taperW = self.taperW # e-skid Taper Width [um] + taperL = self.taperL # e-skid Taper Length [um] + + clad_taper_L = self.clad_taper_L # Extended e-skid length [nm] + clad_taper_angle_radians = self.clad_taper_angle*math.pi/180 # Extended e-skid angle [degrees] + + + + ############################### + ########### e-skid ############ + ############################### + + # 1. e-skid main body + + # x, y coordinates of the core + x_core = [0, length, length, 0] + y_core = [-w/2, - w/2, w/2, w/2] + + dpts = [pya.DPoint(x_core[i], y_core[i]) for i in range(len(x_core))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # draw multiple clad for both top and bottom + for i in range (1, p_num+1): + + # x, y coordinates of the top clad + x_clad_top = [0, length, length, 0] + y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff), w/2+i*p, w/2+i*p] + + dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # x, y coordinates of the bottom clad + x_clad_bottom = [0, length, length, 0] + y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff), -w/2-i*p, -w/2-i*p] + + dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # 2. taper + Pins + + if taper_True: + # Top clad + if clad_taper_L > taperL: + # Prevent the clad_taper_L to be larger than taperL + clad_taper_L = taperL + + # Calculate the required offset + w_offset = taperW * clad_taper_L / taperL + + # fetch the taper angle at the set point + taper_angle = math.atan(((taperW-w)/2)/(taperL)) + + if clad_taper_angle_radians <= taper_angle: + clad_taper_angle_radians = taper_angle + + + for i in range (1, p_num+1): + + # draw the right clad, angle method + # locate the end points of the extended clad + clad_end_point_position = w/2+i*p + i*(clad_taper_L*math.tan(clad_taper_angle_radians)) + + + # x, y coordinates of the top clad + x_clad_top = [length, length+clad_taper_L, length+clad_taper_L, length] + y_clad_top = [w/2+i*p-(p*ff) , clad_end_point_position-(p*ff),clad_end_point_position, w/2+i*p] + + dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # x, y coordinates of the bottom clad + x_clad_bottom = [length, length+clad_taper_L, length+clad_taper_L, length] + y_clad_bottom = [-w/2-i*p+(p*ff) , -clad_end_point_position+(p*ff),-clad_end_point_position, -w/2-i*p] + + dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + + # draw the left clad, angle method + # locate the end points of the extended clad + clad_end_point_position = w/2+i*p + i*(clad_taper_L*math.tan(clad_taper_angle_radians)) + + # x, y coordinates of the top clad + x_clad_top = [0, -clad_taper_L, -clad_taper_L, 0] + y_clad_top = [w/2+i*p-(p*ff) , clad_end_point_position-(p*ff),clad_end_point_position, w/2+i*p] + + dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # x, y coordinates of the bottom clad + x_clad_bottom = [0, -clad_taper_L, -clad_taper_L, 0] + y_clad_bottom = [-w/2-i*p+(p*ff) , -clad_end_point_position+(p*ff),-clad_end_point_position, -w/2-i*p] + + dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # # draw the right clad, offeset method + # # x, y coordinates of the top clad + # x_clad_top = [length, length+clad_taper_L, length+clad_taper_L, length] + # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] + + # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # # x, y coordinates of the bottom clad + # x_clad_bottom = [length, length+clad_taper_L, length+clad_taper_L, length] + # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] + + # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # draw the left clad + # x, y coordinates of the top clad + # x_clad_top = [0, -clad_taper_L, -clad_taper_L, 0] + # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] + + # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # # x, y coordinates of the bottom clad + # x_clad_bottom = [0, -clad_taper_L, -clad_taper_L, 0] + # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] + + # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # left taper + x_taper_left = [0, 0, -taperL, -taperL] + y_taper_left = [-w/2, w/2, taperW/2, -taperW/2] + + dpts = [pya.DPoint(x_taper_left[i], y_taper_left[i]) for i in range(len(x_taper_left))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # right taper + x_taper_right = [length, length, length+taperL, length+taperL] + y_taper_right = [-w/2, w/2, taperW/2, -taperW/2] + + dpts = [pya.DPoint(x_taper_right[i], y_taper_right[i]) for i in range(len(x_taper_right))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # Adding Pins for mating + # Pin 1 + t = pya.DTrans(pya.Trans.R90, -taperL/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], taperW/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt1", pya.DTrans(pya.Trans.R0, -taperL/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Pin 2 + t = pya.DTrans(pya.Trans.R270, (taperL + length)/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], taperW/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt2", pya.DTrans(pya.Trans.R0, (taperL + length)/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Devbox + dev = pya.DBox(-taperL, + clad_end_point_position, + length + taperL, + -clad_end_point_position) + # dev = pya.DBox(-taperL, + # w/2 + p_num*p + p_num*w_offset, + # length + taperL, + # -w/2 - p_num*p - p_num*w_offset) + + shapes(LayerDevRecN).insert(dev) + + else: + # Adding Pins for mating + # Pin 1 + t = pya.DTrans(pya.Trans.R90, 0, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], w/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt1", pya.DTrans(pya.Trans.R0, 0, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Pin 2 + t = pya.DTrans(pya.Trans.R270, length/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], w/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt2", pya.DTrans(pya.Trans.R0, length/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Devbox + dev = pya.DBox(0, + w/2 + p_num*p, + length, + -w/2 - p_num*p) + + shapes(LayerDevRecN).insert(dev) + +#==================================================================================================== +# END OF DOCUMENT +#==================================================================================================== \ No newline at end of file diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_left_taper.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_left_taper.py new file mode 100644 index 00000000..6fc0b4ad --- /dev/null +++ b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_left_taper.py @@ -0,0 +1,310 @@ +import pya +from . import * +from SiEPIC.utils import get_technology_by_name +from SiEPIC._globals import PIN_LENGTH as pin_length +from pya import DPolygon +import math + +#==================================================================================================== +# File: e_skid.py +# Author: Hang (Bobby) Zou +# Purpose: PCell in EBeam library for a common parallel e-skid design that have adjustable period +# and fill factor +# Version: V1.2 +# Date: 2023-05-11 +#==================================================================================================== + +class e_skid_left_taper(pya.PCellDeclarationHelper): + + def __init__(self): + + # Important: initialize the super class + super(e_skid_left_taper, self).__init__() + self.technology_name = 'EBeam' + + TECHNOLOGY = get_technology_by_name(self.technology_name) + + # e_skid Parameters: + # core parameter + self.param('divider0', self.TypeBoolean, '==============Core Parameter==============') + + self.param('w', self.TypeDouble, 'Core Waveguide Width [um]' , default = 0.3) + + self.param('divider1', self.TypeBoolean, '==============Clad Parameter==============') + + # clad parameter + self.param('p', self.TypeDouble, 'e-skid Period [um]' , default = 0.1) + self.param('ff', self.TypeDouble, 'e-skid Fill Factor [0.2-0.8]' , default = 0.5) + self.param('p_num', self.TypeInt, 'e-skid Period Number' , default = 5) + self.param('length', self.TypeDouble, 'Length of e-skid Waveguide [um]' , default = 10) + + self.param('divider2', self.TypeBoolean, '==============Taper Parameter=============') + + # taper + self.param('taper_True', self.TypeBoolean, 'Taper [T/F]' , default = True) + self.param('taperL', self.TypeDouble, 'Strip -> e-skid Taper Length [um]' , default = 5) + self.param('taperW', self.TypeDouble, 'Strip Width [um]' , default = 0.5) + + self.param('divider3', self.TypeBoolean, '============Extended Clad Parameter==========') + + # extended clad parameter + self.param('clad_taper_L', self.TypeDouble, 'Extended e-skid Length [um]' , default = 5) + self.param('clad_taper_angle', self.TypeDouble,'Extended e-skid Angle [degree]' , default = 2) + + self.param('divider4', self.TypeBoolean, '=====================================') + + # Layer Parameters - Don't touch + self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si']) + self.param("pinrec", self.TypeLayer, "PinRec Layer", default = TECHNOLOGY['PinRec']) + self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec']) + self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)']) + + + # Creating the layout + def produce_impl(self): + + # Layout Parameters + dbu = self.layout.dbu + ly = self.layout + shapes = self.cell.shapes + + LayerSi = self.layer + LayerSiN = ly.layer(LayerSi) + LayerPinRecN = ly.layer(self.pinrec) + LayerDevRecN = ly.layer(self.devrec) + + w = self.w # Core Waveguide Width [um] + p = self.p # e-skid Period [um] + ff = self.ff # e-skid Duty Cycle [%] + p_num = self.p_num # e-skid Period Number + length = self.length # e-skid Waveguide Length [um] + + taper_True = self.taper_True # e-skid Taper [T/F] + taperW = self.taperW # e-skid Taper Width [um] + taperL = self.taperL # e-skid Taper Length [um] + + clad_taper_L = self.clad_taper_L # Extended e-skid length [nm] + clad_taper_angle_radians = self.clad_taper_angle*math.pi/180 # Extended e-skid angle [degrees] + + + + ############################### + ########### e-skid ############ + ############################### + + # 1. e-skid main body + + # x, y coordinates of the core + x_core = [0, length, length, 0] + y_core = [-w/2, - w/2, w/2, w/2] + + dpts = [pya.DPoint(x_core[i], y_core[i]) for i in range(len(x_core))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # draw multiple clad for both top and bottom + for i in range (1, p_num+1): + + # x, y coordinates of the top clad + x_clad_top = [0, length, length, 0] + y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff), w/2+i*p, w/2+i*p] + + dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # x, y coordinates of the bottom clad + x_clad_bottom = [0, length, length, 0] + y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff), -w/2-i*p, -w/2-i*p] + + dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # 2. taper + Pins + + if taper_True: + # Top clad + if clad_taper_L > taperL: + # Prevent the clad_taper_L to be larger than taperL + clad_taper_L = taperL + + # Calculate the required offset + w_offset = taperW * clad_taper_L / taperL + + # fetch the taper angle at the set point + taper_angle = math.atan(((taperW-w)/2)/(taperL)) + + if clad_taper_angle_radians <= taper_angle: + clad_taper_angle_radians = taper_angle + + + for i in range (1, p_num+1): + + # # draw the right clad, angle method + # # locate the end points of the extended clad + # clad_end_point_position = w/2+i*p + i*(clad_taper_L*math.tan(clad_taper_angle_radians)) + + + # # x, y coordinates of the top clad + # x_clad_top = [length, length+clad_taper_L, length+clad_taper_L, length] + # y_clad_top = [w/2+i*p-(p*ff) , clad_end_point_position-(p*ff),clad_end_point_position, w/2+i*p] + + # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # # x, y coordinates of the bottom clad + # x_clad_bottom = [length, length+clad_taper_L, length+clad_taper_L, length] + # y_clad_bottom = [-w/2-i*p+(p*ff) , -clad_end_point_position+(p*ff),-clad_end_point_position, -w/2-i*p] + + # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + + # draw the left clad, angle method + # locate the end points of the extended clad + clad_end_point_position = w/2+i*p + i*(clad_taper_L*math.tan(clad_taper_angle_radians)) + + # x, y coordinates of the top clad + x_clad_top = [0, -clad_taper_L, -clad_taper_L, 0] + y_clad_top = [w/2+i*p-(p*ff) , clad_end_point_position-(p*ff),clad_end_point_position, w/2+i*p] + + dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # x, y coordinates of the bottom clad + x_clad_bottom = [0, -clad_taper_L, -clad_taper_L, 0] + y_clad_bottom = [-w/2-i*p+(p*ff) , -clad_end_point_position+(p*ff),-clad_end_point_position, -w/2-i*p] + + dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # # draw the right clad, offeset method + # # x, y coordinates of the top clad + # x_clad_top = [length, length+clad_taper_L, length+clad_taper_L, length] + # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] + + # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # # x, y coordinates of the bottom clad + # x_clad_bottom = [length, length+clad_taper_L, length+clad_taper_L, length] + # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] + + # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # draw the left clad + # x, y coordinates of the top clad + # x_clad_top = [0, -clad_taper_L, -clad_taper_L, 0] + # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] + + # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # # x, y coordinates of the bottom clad + # x_clad_bottom = [0, -clad_taper_L, -clad_taper_L, 0] + # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] + + # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # left taper + x_taper_left = [0, 0, -taperL, -taperL] + y_taper_left = [-w/2, w/2, taperW/2, -taperW/2] + + dpts = [pya.DPoint(x_taper_left[i], y_taper_left[i]) for i in range(len(x_taper_left))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + # # right taper + # x_taper_right = [length, length, length+taperL, length+taperL] + # y_taper_right = [-w/2, w/2, taperW/2, -taperW/2] + + # dpts = [pya.DPoint(x_taper_right[i], y_taper_right[i]) for i in range(len(x_taper_right))] # Core body + # dpolygon = DPolygon(dpts) + # element = Polygon.from_dpoly(dpolygon*(1/dbu)) + # shapes(LayerSiN).insert(element) + + # Adding Pins for mating + # Pin 1 + t = pya.DTrans(pya.Trans.R90, -taperL/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], taperW/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt1", pya.DTrans(pya.Trans.R0, -taperL/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Pin 2 + t = pya.DTrans(pya.Trans.R270, (length)/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], w/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt2", pya.DTrans(pya.Trans.R0, (length)/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Devbox + dev = pya.DBox(-taperL, + clad_end_point_position, + length, + -clad_end_point_position) + # dev = pya.DBox(-taperL, + # w/2 + p_num*p + p_num*w_offset, + # length + taperL, + # -w/2 - p_num*p - p_num*w_offset) + + shapes(LayerDevRecN).insert(dev) + + else: + # Adding Pins for mating + # Pin 1 + t = pya.DTrans(pya.Trans.R90, 0, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], w/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt1", pya.DTrans(pya.Trans.R0, 0, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Pin 2 + t = pya.DTrans(pya.Trans.R270, length/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], w/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text ("opt2", pya.DTrans(pya.Trans.R0, length/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.2/dbu + + # Devbox + dev = pya.DBox(0, + w/2 + p_num*p, + length, + -w/2 - p_num*p) + + shapes(LayerDevRecN).insert(dev) + +#==================================================================================================== +# END OF DOCUMENT +#==================================================================================================== \ No newline at end of file diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py new file mode 100644 index 00000000..19f82211 --- /dev/null +++ b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py @@ -0,0 +1,169 @@ +from . import * +import pya +from SiEPIC.utils import get_technology_by_name, arc_wg_xy +from SiEPIC._globals import PIN_LENGTH as pin_length +from pya import DPolygon + +class e_skid_ring(pya.PCellDeclarationHelper): + + """ + Author: Ben Cohen (UBC), Hang Bobby Zou (UBC) + bcohenkl@ece.ubc.ca + June 9, 2023 + + - This Pcell creates a single-bus ring resonator modified with e-skid concentric rings + - Design control over number of inner/outer concentric rings. Gap between two rings and width is parameterized + as an input list. + - If a 0 is found in any entry of the list, the cell will automatically delete every element in the list + - If the number of entries in the gap and width lists are different, the list with the minimum number of elements is considered + + - Controllable coupling. Bus length is designed as the outer most radius of the e-skid ring resonator + """ + + def __init__(self): + + # Important: initialize the super class + super(e_skid_ring, self).__init__() + self.technology_name = 'EBeam' + TECHNOLOGY = get_technology_by_name(self.technology_name) + + # Main Ring Parameters + self.param("r", self.TypeDouble, "Ring Radii [um]", default = 10) + self.param("w", self.TypeDouble, "Ring Waveguide Width [um]", default = 0.5) + self.param("cg", self.TypeDouble, "Coupling Gap [um]", default = 0.2) + + # Bus Parameters: + self.param("bus_w", self.TypeDouble, "Bus Waveguide Width [um]", default = 0.5) + + # e-skid parameter + self.param("gap_out", self.TypeList, "Outer Gap List [um] (0 if none)", default = [0]) + self.param("w_out", self.TypeList, "Outer Width List [um] (0 if none)", default = [0]) + + self.param("gap_in", self.TypeList, "Inner Gap List [um] (0 if none)", default = [0.3, 0.3]) + self.param("w_in", self.TypeList, "Inner Width List [um] (0 if none)", default = [0.1, 0.1]) + + # Layer Parameters + self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si'], hidden = True) + self.param("pinrec", self.TypeLayer, "PinRec Layer", default = TECHNOLOGY['PinRec'], hidden = True) + self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec'], hidden = True) + self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)'], hidden = True) + + # Creating the layout + def produce_impl(self): + + # Layout Parameters + dbu = self.layout.dbu + ly = self.layout + shapes = self.cell.shapes + + # Layers + LayerSi = self.layer + LayerSiN = ly.layer(LayerSi) + LayerPinRecN = ly.layer(self.pinrec) + LayerDevRecN = ly.layer(self.devrec) + + # Main Ring Parameters + r = self.r # Ring radii [um] + w = self.w # Ring waveguide width [um] + cg = self.cg # Coupling gap + + # Bus Parameters: + bus_w = self.bus_w # Bus width [um] + bus_l = 2*(r + w) # Bus length [um] + + # e-skid parameters + gap_out = self.gap_out # Gap between different widths for rings outside of the main ring resonator [um] + w_out = self.w_out # Width of each ring outside of the main ring resonator [um] + gap_in = self.gap_in # Gap between different widths for rings inside of the main ring resonator [um] + w_in = self.w_in # Width of each ring inside of the main ring resonator [um] + + + # Converting the list elements from str (klayout default) to float + # No entries in either array should be 0, deleting every entry after 0 is found + for i in range(len(w_out)): + w_out[i] = float(w_out[i]) + if w_out[i] == 0: + w_out = w_out[:i] + break + + for i in range(len(gap_out)): + gap_out[i] = float(gap_out[i]) + if gap_out[i] == 0: + w_out = w_out[:i] + break + + for i in range(len(w_in)): + w_in[i] = float(w_in[i]) + if w_in[i] == 0: + w_in = w_in[:i] + break + + for i in range(len(gap_in)): + gap_in[i] = float(gap_in[i]) + if gap_in[i] == 0: + gap_in = gap_in[:i] + break + + # Ring Resonator + if (r != 0): + shapes(LayerSiN).insert(arc_wg_xy(0, 0, (r + w/2)/dbu, w/dbu, 0, 360)) + + # Bus Waveguide + bus_x = [-bus_l/2, bus_l/2, bus_l/2, -bus_l/2] + bus_y = [r + w + cg, r + w + cg, r + w + cg + bus_w, r + w + cg + bus_w] + + dpts = [pya.DPoint(bus_x[i], bus_y[i]) for i in range(len(bus_x))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + + # Adding outer concetric rings + """ + rad0_out = r + w + for i in range(min(len(gap_out), len(w_out))): + ring = pya.Region() + ring.insert(arc_wg_xy(0, 0, (rad0_out + gap_out[i] + w_out[i]/2)/dbu, w_out[i]/dbu, 0, 360)) + + # CONSIDERATION FOR TAPERS + box_subtract = + shapes(LayerSiN).insert(ring) + + #shapes(LayerSiN).insert(arc_wg_xy(0, 0, (rad0_out + gap_out[i] + w_out[i]/2)/dbu, w_out[i]/dbu, 0, 360)) + rad0_out = rad0_out + gap_out[i] + w_out[i] + """ + + # Adding inner concetric rings + if (r != 0): + rad0_in = r + for i in range(min(len(gap_in), len(w_in))): + + ring = pya.Region() + ring.insert(arc_wg_xy(0, 0, (rad0_in - gap_in[i] - w_in[i]/2)/dbu, w_in[i]/dbu, 0, 360)) + shapes(LayerSiN).insert(ring) + + rad0_in = rad0_in - gap_in[i] - w_in[i] + + + # Pins for mating: + t = pya.DTrans(pya.Trans.R90, min(bus_x)/dbu, (min(bus_y) + max(bus_y))/2/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], bus_w/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text("opt1", pya.DTrans(pya.Trans.R0, min(bus_x)/dbu, (min(bus_y) + max(bus_y))/2/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.4/dbu + + t = pya.DTrans(pya.Trans.R90, max(bus_x)/dbu, (min(bus_y) + max(bus_y))/2/dbu) + pin = pya.Path([pya.DPoint(0, pin_length/2), pya.DPoint(0, -pin_length/2)], bus_w/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text("opt2", pya.DTrans(pya.Trans.R90, max(bus_x)/dbu, (min(bus_y) + max(bus_y))/2/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.4/dbu + + # Dev box + # Encapsulate the pcell within a box for error checking + w = self.w + dev = pya.DBox(-(r + w), r + w + cg + bus_w, r + w, -(r + w)) + shapes(LayerDevRecN).insert(dev) \ No newline at end of file diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py new file mode 100644 index 00000000..a581f665 --- /dev/null +++ b/klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py @@ -0,0 +1,90 @@ +from . import * +import pya +from SiEPIC.utils import get_technology_by_name, arc_wg_xy +from SiEPIC._globals import PIN_LENGTH as pin_length +from pya import DPolygon + +class strip_taper(pya.PCellDeclarationHelper): + + """ + Author: Ben Cohen (UBC) + bcohenkl@ece.ubc.ca + June 26, 2023 + + - This Pcell creates a strip-strip taper + - Strip width 1 - w1 + - Strip width 2 - w2 + - Taper Length - taperL + """ + + def __init__(self): + + # Important: initialize the super class + super(strip_taper, self).__init__() + self.technology_name = 'EBeam' + TECHNOLOGY = get_technology_by_name(self.technology_name) + + # Parameters + self.param("w1", self.TypeDouble, "Waveguide Width 1 [um]", default = 0.5) + self.param("w2", self.TypeDouble, "Waveguide Width 2 [um]", default = 0.4) + self.param("taperL", self.TypeDouble, "Taperl Length [um]", default = 10) + + # Layer Parameters + self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si'], hidden = True) + self.param("pinrec", self.TypeLayer, "PinRec Layer", default = TECHNOLOGY['PinRec'], hidden = True) + self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec'], hidden = True) + self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)'], hidden = True) + + + + # Creating the layout + def produce_impl(self): + + # Layout Parameters + dbu = self.layout.dbu + ly = self.layout + shapes = self.cell.shapes + + # Layers + LayerSi = self.layer + LayerSiN = ly.layer(LayerSi) + LayerPinRecN = ly.layer(self.pinrec) + LayerDevRecN = ly.layer(self.devrec) + + # Main Ring Parameters + w1 = self.w1 # Waveguide Width 1[um] + w2 = self.w2 # Waveguide Width 2[um] + taperL = self.taperL # Taper Length [um] + + x = [0, taperL, taperL, 0] # x-coord + y = [-w1/2, -w2/2, w2/2, w1/2] # y-coord + + dpts = [pya.DPoint(x[i], y[i]) for i in range(len(x))] # Core body + dpolygon = DPolygon(dpts) + element = Polygon.from_dpoly(dpolygon*(1/dbu)) + shapes(LayerSiN).insert(element) + + + # Pins for mating: + t = pya.DTrans(pya.Trans.R90, min(x)/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], w1/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text("opt1", pya.DTrans(pya.Trans.R0, min(x)/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.4/dbu + + t = pya.DTrans(pya.Trans.R90, max(x)/dbu, 0/dbu) + pin = pya.Path([pya.DPoint(0, pin_length/2), pya.DPoint(0, -pin_length/2)], w2/dbu) + pin_t = pin.transformed(t) + shapes(LayerPinRecN).insert(pin_t) + text = pya.Text("opt2", pya.DTrans(pya.Trans.R90, max(x)/dbu, 0/dbu)) + shape = shapes(LayerPinRecN).insert(text) + shape.text_size = 0.4/dbu + + + + # Dev box + # Encapsulate the pcell within a box for error checking + dev = pya.DBox(min(x), max(y), max(x), min(y)) + shapes(LayerDevRecN).insert(dev) \ No newline at end of file From 7a7c465f04681444ddec1e538a2bc8aa8dcb230f Mon Sep 17 00:00:00 2001 From: Hang Zou <45744171+Hang-Bobby-Zou@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:20:31 -0800 Subject: [PATCH 2/2] Updated cells for e_skid, removed the strip_taper cell - Remove strip_taper.py since initially I thought this was a dependency for another PCell - Changed device naming for the e_skid structure with one sided taper (from e_skid_left_taper.py to e_skid_single_side_taper.py - Changed the divider from TypeBoolean to TypeNone so the PCell menu tab looks a bit better - Resolved the naming issue with * at the end - Moved DevRec away from the structures so it does not co-incident with the waveguide anymore --- .../pymacros/pcells_EBeam_Beta/e_skid.py | 67 +++-------- .../pymacros/pcells_EBeam_Beta/e_skid_ring.py | 8 +- ...t_taper.py => e_skid_single_side_taper.py} | 107 +++--------------- .../pymacros/pcells_EBeam_Beta/strip_taper.py | 90 --------------- 4 files changed, 38 insertions(+), 234 deletions(-) rename klayout/EBeam/pymacros/pcells_EBeam_Beta/{e_skid_left_taper.py => e_skid_single_side_taper.py} (65%) delete mode 100644 klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py index d0cfbb94..e1637904 100644 --- a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py +++ b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py @@ -10,8 +10,8 @@ # Author: Hang (Bobby) Zou # Purpose: PCell in EBeam library for a common parallel e-skid design that have adjustable period # and fill factor -# Version: V1.2 -# Date: 2023-05-11 +# Version: V2.0 +# Date: 2023-11-09 #==================================================================================================== class e_skid(pya.PCellDeclarationHelper): @@ -26,11 +26,11 @@ def __init__(self): # e_skid Parameters: # core parameter - self.param('divider0', self.TypeBoolean, '==============Core Parameter==============') + self.param('divider0', self.TypeNone, '==============Core Parameter==============') self.param('w', self.TypeDouble, 'Core Waveguide Width [um]' , default = 0.3) - self.param('divider1', self.TypeBoolean, '==============Clad Parameter==============') + self.param('divider1', self.TypeNone, '==============Clad Parameter==============') # clad parameter self.param('p', self.TypeDouble, 'e-skid Period [um]' , default = 0.1) @@ -38,20 +38,20 @@ def __init__(self): self.param('p_num', self.TypeInt, 'e-skid Period Number' , default = 5) self.param('length', self.TypeDouble, 'Length of e-skid Waveguide [um]' , default = 10) - self.param('divider2', self.TypeBoolean, '==============Taper Parameter=============') + self.param('divider2', self.TypeNone, '==============Taper Parameter=============') # taper self.param('taper_True', self.TypeBoolean, 'Taper [T/F]' , default = True) self.param('taperL', self.TypeDouble, 'Strip -> e-skid Taper Length [um]' , default = 5) self.param('taperW', self.TypeDouble, 'Strip Width [um]' , default = 0.5) - self.param('divider3', self.TypeBoolean, '============Extended Clad Parameter==========') + self.param('divider3', self.TypeNone, '============Extended Clad Parameter==========') # extended clad parameter self.param('clad_taper_L', self.TypeDouble, 'Extended e-skid Length [um]' , default = 5) self.param('clad_taper_angle', self.TypeDouble,'Extended e-skid Angle [degree]' , default = 2) - self.param('divider4', self.TypeBoolean, '=====================================') + self.param('divider4', self.TypeNone, '=====================================') # Layer Parameters - Don't touch self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si']) @@ -59,6 +59,9 @@ def __init__(self): self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec']) self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)']) + def display_text_impl(self): + # Provide a descriptive text for the cell + return "configurable_e_skid" # Creating the layout def produce_impl(self): @@ -189,44 +192,6 @@ def produce_impl(self): dpolygon = DPolygon(dpts) element = Polygon.from_dpoly(dpolygon*(1/dbu)) shapes(LayerSiN).insert(element) - - # # draw the right clad, offeset method - # # x, y coordinates of the top clad - # x_clad_top = [length, length+clad_taper_L, length+clad_taper_L, length] - # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] - - # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - - # # x, y coordinates of the bottom clad - # x_clad_bottom = [length, length+clad_taper_L, length+clad_taper_L, length] - # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] - - # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - - # draw the left clad - # x, y coordinates of the top clad - # x_clad_top = [0, -clad_taper_L, -clad_taper_L, 0] - # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] - - # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - - # # x, y coordinates of the bottom clad - # x_clad_bottom = [0, -clad_taper_L, -clad_taper_L, 0] - # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] - - # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) # left taper x_taper_left = [0, 0, -taperL, -taperL] @@ -267,13 +232,9 @@ def produce_impl(self): # Devbox dev = pya.DBox(-taperL, - clad_end_point_position, + clad_end_point_position + 0.5, length + taperL, - -clad_end_point_position) - # dev = pya.DBox(-taperL, - # w/2 + p_num*p + p_num*w_offset, - # length + taperL, - # -w/2 - p_num*p - p_num*w_offset) + -clad_end_point_position - 0.5) shapes(LayerDevRecN).insert(dev) @@ -299,9 +260,9 @@ def produce_impl(self): # Devbox dev = pya.DBox(0, - w/2 + p_num*p, + w/2 + p_num*p + 0.5, length, - -w/2 - p_num*p) + -w/2 - p_num*p - 0.5) shapes(LayerDevRecN).insert(dev) diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py index 19f82211..58f7dd25 100644 --- a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py +++ b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_ring.py @@ -9,7 +9,7 @@ class e_skid_ring(pya.PCellDeclarationHelper): """ Author: Ben Cohen (UBC), Hang Bobby Zou (UBC) bcohenkl@ece.ubc.ca - June 9, 2023 + Nov 9, 2023 - This Pcell creates a single-bus ring resonator modified with e-skid concentric rings - Design control over number of inner/outer concentric rings. Gap between two rings and width is parameterized @@ -48,6 +48,10 @@ def __init__(self): self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec'], hidden = True) self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)'], hidden = True) + def display_text_impl(self): + # Provide a descriptive text for the cell + return "ring_resonator_with_e_skid_pillar" + # Creating the layout def produce_impl(self): @@ -165,5 +169,5 @@ def produce_impl(self): # Dev box # Encapsulate the pcell within a box for error checking w = self.w - dev = pya.DBox(-(r + w), r + w + cg + bus_w, r + w, -(r + w)) + dev = pya.DBox(-(r + w), r + w + cg + bus_w + 0.5, r + w, -(r + w) - 0.5) shapes(LayerDevRecN).insert(dev) \ No newline at end of file diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_left_taper.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_single_side_taper.py similarity index 65% rename from klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_left_taper.py rename to klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_single_side_taper.py index 6fc0b4ad..48906cee 100644 --- a/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_left_taper.py +++ b/klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid_single_side_taper.py @@ -6,31 +6,31 @@ import math #==================================================================================================== -# File: e_skid.py +# File: e_skid_single_side_taper.py # Author: Hang (Bobby) Zou # Purpose: PCell in EBeam library for a common parallel e-skid design that have adjustable period # and fill factor -# Version: V1.2 -# Date: 2023-05-11 +# Version: V2.0 +# Date: 2023-11-09 #==================================================================================================== -class e_skid_left_taper(pya.PCellDeclarationHelper): +class e_skid_single_side_taper(pya.PCellDeclarationHelper): def __init__(self): # Important: initialize the super class - super(e_skid_left_taper, self).__init__() + super(e_skid_single_side_taper, self).__init__() self.technology_name = 'EBeam' TECHNOLOGY = get_technology_by_name(self.technology_name) # e_skid Parameters: # core parameter - self.param('divider0', self.TypeBoolean, '==============Core Parameter==============') + self.param('divider0', self.TypeNone, '==============Core Parameter==============') self.param('w', self.TypeDouble, 'Core Waveguide Width [um]' , default = 0.3) - self.param('divider1', self.TypeBoolean, '==============Clad Parameter==============') + self.param('divider1', self.TypeNone, '==============Clad Parameter==============') # clad parameter self.param('p', self.TypeDouble, 'e-skid Period [um]' , default = 0.1) @@ -38,20 +38,20 @@ def __init__(self): self.param('p_num', self.TypeInt, 'e-skid Period Number' , default = 5) self.param('length', self.TypeDouble, 'Length of e-skid Waveguide [um]' , default = 10) - self.param('divider2', self.TypeBoolean, '==============Taper Parameter=============') + self.param('divider2', self.TypeNone, '==============Taper Parameter=============') # taper self.param('taper_True', self.TypeBoolean, 'Taper [T/F]' , default = True) self.param('taperL', self.TypeDouble, 'Strip -> e-skid Taper Length [um]' , default = 5) self.param('taperW', self.TypeDouble, 'Strip Width [um]' , default = 0.5) - self.param('divider3', self.TypeBoolean, '============Extended Clad Parameter==========') + self.param('divider3', self.TypeNone, '============Extended Clad Parameter==========') # extended clad parameter self.param('clad_taper_L', self.TypeDouble, 'Extended e-skid Length [um]' , default = 5) self.param('clad_taper_angle', self.TypeDouble,'Extended e-skid Angle [degree]' , default = 2) - self.param('divider4', self.TypeBoolean, '=====================================') + self.param('divider4', self.TypeNone, '=====================================') # Layer Parameters - Don't touch self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si']) @@ -59,6 +59,10 @@ def __init__(self): self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec']) self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)']) + def display_text_impl(self): + # Provide a descriptive text for the cell + return "e_skid_with_a_single_side_taper" + # Creating the layout def produce_impl(self): @@ -143,30 +147,6 @@ def produce_impl(self): for i in range (1, p_num+1): - - # # draw the right clad, angle method - # # locate the end points of the extended clad - # clad_end_point_position = w/2+i*p + i*(clad_taper_L*math.tan(clad_taper_angle_radians)) - - - # # x, y coordinates of the top clad - # x_clad_top = [length, length+clad_taper_L, length+clad_taper_L, length] - # y_clad_top = [w/2+i*p-(p*ff) , clad_end_point_position-(p*ff),clad_end_point_position, w/2+i*p] - - # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - - # # x, y coordinates of the bottom clad - # x_clad_bottom = [length, length+clad_taper_L, length+clad_taper_L, length] - # y_clad_bottom = [-w/2-i*p+(p*ff) , -clad_end_point_position+(p*ff),-clad_end_point_position, -w/2-i*p] - - # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - # draw the left clad, angle method # locate the end points of the extended clad @@ -189,44 +169,6 @@ def produce_impl(self): dpolygon = DPolygon(dpts) element = Polygon.from_dpoly(dpolygon*(1/dbu)) shapes(LayerSiN).insert(element) - - # # draw the right clad, offeset method - # # x, y coordinates of the top clad - # x_clad_top = [length, length+clad_taper_L, length+clad_taper_L, length] - # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] - - # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - - # # x, y coordinates of the bottom clad - # x_clad_bottom = [length, length+clad_taper_L, length+clad_taper_L, length] - # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] - - # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - - # draw the left clad - # x, y coordinates of the top clad - # x_clad_top = [0, -clad_taper_L, -clad_taper_L, 0] - # y_clad_top = [w/2+i*p-(p*ff), w/2+i*p-(p*ff)+i*w_offset, w/2+i*p+i*w_offset, w/2+i*p] - - # dpts = [pya.DPoint(x_clad_top[i], y_clad_top[i]) for i in range(len(x_clad_top))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - - # # x, y coordinates of the bottom clad - # x_clad_bottom = [0, -clad_taper_L, -clad_taper_L, 0] - # y_clad_bottom = [-w/2-i*p+(p*ff), -w/2-i*p+(p*ff)-i*w_offset, -w/2-i*p-i*w_offset, -w/2-i*p] - - # dpts = [pya.DPoint(x_clad_bottom[i], y_clad_bottom[i]) for i in range(len(x_clad_bottom))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) # left taper x_taper_left = [0, 0, -taperL, -taperL] @@ -237,15 +179,6 @@ def produce_impl(self): element = Polygon.from_dpoly(dpolygon*(1/dbu)) shapes(LayerSiN).insert(element) - # # right taper - # x_taper_right = [length, length, length+taperL, length+taperL] - # y_taper_right = [-w/2, w/2, taperW/2, -taperW/2] - - # dpts = [pya.DPoint(x_taper_right[i], y_taper_right[i]) for i in range(len(x_taper_right))] # Core body - # dpolygon = DPolygon(dpts) - # element = Polygon.from_dpoly(dpolygon*(1/dbu)) - # shapes(LayerSiN).insert(element) - # Adding Pins for mating # Pin 1 t = pya.DTrans(pya.Trans.R90, -taperL/dbu, 0/dbu) @@ -267,13 +200,9 @@ def produce_impl(self): # Devbox dev = pya.DBox(-taperL, - clad_end_point_position, + clad_end_point_position + 0.5, length, - -clad_end_point_position) - # dev = pya.DBox(-taperL, - # w/2 + p_num*p + p_num*w_offset, - # length + taperL, - # -w/2 - p_num*p - p_num*w_offset) + -clad_end_point_position - 0.5) shapes(LayerDevRecN).insert(dev) @@ -299,9 +228,9 @@ def produce_impl(self): # Devbox dev = pya.DBox(0, - w/2 + p_num*p, + w/2 + p_num*p + 0.5, length, - -w/2 - p_num*p) + -w/2 - p_num*p - 0.5) shapes(LayerDevRecN).insert(dev) diff --git a/klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py b/klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py deleted file mode 100644 index a581f665..00000000 --- a/klayout/EBeam/pymacros/pcells_EBeam_Beta/strip_taper.py +++ /dev/null @@ -1,90 +0,0 @@ -from . import * -import pya -from SiEPIC.utils import get_technology_by_name, arc_wg_xy -from SiEPIC._globals import PIN_LENGTH as pin_length -from pya import DPolygon - -class strip_taper(pya.PCellDeclarationHelper): - - """ - Author: Ben Cohen (UBC) - bcohenkl@ece.ubc.ca - June 26, 2023 - - - This Pcell creates a strip-strip taper - - Strip width 1 - w1 - - Strip width 2 - w2 - - Taper Length - taperL - """ - - def __init__(self): - - # Important: initialize the super class - super(strip_taper, self).__init__() - self.technology_name = 'EBeam' - TECHNOLOGY = get_technology_by_name(self.technology_name) - - # Parameters - self.param("w1", self.TypeDouble, "Waveguide Width 1 [um]", default = 0.5) - self.param("w2", self.TypeDouble, "Waveguide Width 2 [um]", default = 0.4) - self.param("taperL", self.TypeDouble, "Taperl Length [um]", default = 10) - - # Layer Parameters - self.param("layer", self.TypeLayer, "Layer", default = TECHNOLOGY['Si'], hidden = True) - self.param("pinrec", self.TypeLayer, "PinRec Layer", default = TECHNOLOGY['PinRec'], hidden = True) - self.param("devrec", self.TypeLayer, "DevRec Layer", default = TECHNOLOGY['DevRec'], hidden = True) - self.param("oxideopen", self.TypeLayer, "Oxide Open Layer", default = TECHNOLOGY['Oxide open (to BOX)'], hidden = True) - - - - # Creating the layout - def produce_impl(self): - - # Layout Parameters - dbu = self.layout.dbu - ly = self.layout - shapes = self.cell.shapes - - # Layers - LayerSi = self.layer - LayerSiN = ly.layer(LayerSi) - LayerPinRecN = ly.layer(self.pinrec) - LayerDevRecN = ly.layer(self.devrec) - - # Main Ring Parameters - w1 = self.w1 # Waveguide Width 1[um] - w2 = self.w2 # Waveguide Width 2[um] - taperL = self.taperL # Taper Length [um] - - x = [0, taperL, taperL, 0] # x-coord - y = [-w1/2, -w2/2, w2/2, w1/2] # y-coord - - dpts = [pya.DPoint(x[i], y[i]) for i in range(len(x))] # Core body - dpolygon = DPolygon(dpts) - element = Polygon.from_dpoly(dpolygon*(1/dbu)) - shapes(LayerSiN).insert(element) - - - # Pins for mating: - t = pya.DTrans(pya.Trans.R90, min(x)/dbu, 0/dbu) - pin = pya.Path([pya.DPoint(0, -pin_length/2), pya.DPoint(0, pin_length/2)], w1/dbu) - pin_t = pin.transformed(t) - shapes(LayerPinRecN).insert(pin_t) - text = pya.Text("opt1", pya.DTrans(pya.Trans.R0, min(x)/dbu, 0/dbu)) - shape = shapes(LayerPinRecN).insert(text) - shape.text_size = 0.4/dbu - - t = pya.DTrans(pya.Trans.R90, max(x)/dbu, 0/dbu) - pin = pya.Path([pya.DPoint(0, pin_length/2), pya.DPoint(0, -pin_length/2)], w2/dbu) - pin_t = pin.transformed(t) - shapes(LayerPinRecN).insert(pin_t) - text = pya.Text("opt2", pya.DTrans(pya.Trans.R90, max(x)/dbu, 0/dbu)) - shape = shapes(LayerPinRecN).insert(text) - shape.text_size = 0.4/dbu - - - - # Dev box - # Encapsulate the pcell within a box for error checking - dev = pya.DBox(min(x), max(y), max(x), min(y)) - shapes(LayerDevRecN).insert(dev) \ No newline at end of file