Skip to content

Commit

Permalink
Merge pull request #263 from Hang-Bobby-Zou/master
Browse files Browse the repository at this point in the history
Added PCell - Bobby
  • Loading branch information
lukasc-ubc authored Nov 10, 2023
2 parents d9012c5 + 7a7c465 commit deed76b
Show file tree
Hide file tree
Showing 3 changed files with 683 additions and 0 deletions.
271 changes: 271 additions & 0 deletions klayout/EBeam/pymacros/pcells_EBeam_Beta/e_skid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
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: V2.0
# Date: 2023-11-09
#====================================================================================================

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.TypeNone, '==============Core Parameter==============')

self.param('w', self.TypeDouble, 'Core Waveguide Width [um]' , default = 0.3)

self.param('divider1', self.TypeNone, '==============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.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.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.TypeNone, '=====================================')

# 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)'])

def display_text_impl(self):
# Provide a descriptive text for the cell
return "configurable_e_skid"

# 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)

# 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 + 0.5,
length + taperL,
-clad_end_point_position - 0.5)

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 + 0.5,
length,
-w/2 - p_num*p - 0.5)

shapes(LayerDevRecN).insert(dev)

#====================================================================================================
# END OF DOCUMENT
#====================================================================================================
Loading

0 comments on commit deed76b

Please sign in to comment.