Skip to content

Commit

Permalink
Merge pull request #224 from SiEPIC/FaML
Browse files Browse the repository at this point in the history
FaML function and tests
  • Loading branch information
lukasc-ubc authored Oct 26, 2024
2 parents b259f4a + 678ec01 commit 97cbf32
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 16 deletions.
37 changes: 37 additions & 0 deletions klayout_dot_config/python/SiEPIC/utils/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -1332,3 +1332,40 @@ def strip2rib(cell, trans, w_slab, w_rib, w_slab_tip, w_strip, length, LayerRib,
nLayerSlab = cell.layout().layer(cell.layout().TECHNOLOGY[LayerSlab])
poly = DPolygon([DPoint(length,-w_slab/2), DPoint(length,w_slab/2), DPoint(0, w_slab_tip/2), DPoint(0, -w_slab_tip/2)])
cell.shapes(nLayerSlab).insert(poly.transformed(trans))


def FaML_two(cell,
label='opt_in_TE_1550_FaML_TestCircuit',
x_offset=0,
y_offset=127e3/2-5e3,
pitch = 127e3,
cell_name = 'ebeam_dream_FaML_SiN_1550_BB',
cell_library = 'EBeam-Dream',
cell_params = {'num_channels':1,
'ref_wg':False},
):
'''
Create a layout consisting of two facet-attached micro-lenses (FaML)
return the two instances
'''
from pya import Trans, CellInstArray, Text
ly = cell.layout()
# Load cell from library
if cell_params:
cell_ebeam_faml = ly.create_cell(cell_name, cell_library, cell_params)
else:
cell_ebeam_faml = ly.create_cell(cell_name, cell_library)
if not cell_ebeam_faml:
raise Exception ('Cannot load cell (%s) from library (%s) with parameters (%s).' % (cell_name, cell_library, cell_params))
# lens for the output to the detector
t = Trans(Trans.R0, x_offset, y_offset)
inst_faml2 = cell.insert(CellInstArray(cell_ebeam_faml.cell_index(), t))
# lens for the input from the laser
t = Trans(Trans.R0,x_offset,pitch + y_offset)
inst_faml1 = cell.insert(CellInstArray(cell_ebeam_faml.cell_index(), t))
# automated test label
text = Text (label, t)
cell.shapes(ly.layer(ly.TECHNOLOGY['Text'])).insert(text).text_size = 5/ly.dbu
return [inst_faml1, inst_faml2]


19 changes: 3 additions & 16 deletions klayout_dot_config/tech/GSiP/GSiP.lyt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
<description/>
<group/>
<dbu>0.001</dbu>
<default-grids/>
<base-path/>
<original-base-path>/home/lukasc/Documents/GitHub/SiEPIC-Tools/klayout_dot_config/tech/GSiP</original-base-path>
<original-base-path>/Users/lukasc/Documents/GitHub/SiEPIC-Tools/klayout_dot_config/tech/GSiP</original-base-path>
<layer-properties_file>klayout_Layers_GSiP.lyp</layer-properties_file>
<add-other-layers>true</add-other-layers>
<reader-options>
Expand Down Expand Up @@ -70,23 +71,9 @@
<read-lef-with-def>true</read-lef-with-def>
<macro-resolution-mode>default</macro-resolution-mode>
<separate-groups>false</separate-groups>
<joined-paths>false</joined-paths>
<map-file/>
</lefdef>
<mebes>
<invert>false</invert>
<subresolution>true</subresolution>
<produce-boundary>true</produce-boundary>
<num-stripes-per-cell>64</num-stripes-per-cell>
<num-shapes-per-cell>0</num-shapes-per-cell>
<data-layer>1</data-layer>
<data-datatype>0</data-datatype>
<data-name>DATA</data-name>
<boundary-layer>0</boundary-layer>
<boundary-datatype>0</boundary-datatype>
<boundary-name>BORDER</boundary-name>
<layer-map>layer_map()</layer-map>
<create-other-layers>true</create-other-layers>
</mebes>
<dxf>
<dbu>0.001</dbu>
<unit>1</unit>
Expand Down
5 changes: 5 additions & 0 deletions klayout_dot_config/tech/GSiP/WAVEGUIDES.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
<width>0.5</width>
<offset>0.0</offset>
</component>
<component>
<layer>DevRec</layer>
<width>1.5</width>
<offset>0.0</offset>
</component>
</waveguide>
<waveguide>
<name>Slot</name>
Expand Down
18 changes: 18 additions & 0 deletions klayout_dot_config/tech/GSiP/klayout_Layers_GSiP.lyp
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,24 @@
<name>DevRec</name>
<source>68/0@1</source>
</properties>
<properties>
<frame-color>#004080</frame-color>
<fill-color>#004080</fill-color>
<frame-brightness>0</frame-brightness>
<fill-brightness>0</fill-brightness>
<dither-pattern>I0</dither-pattern>
<line-style/>
<valid>true</valid>
<visible>true</visible>
<transparent>false</transparent>
<width>1</width>
<marked>false</marked>
<xfill>false</xfill>
<animation>0</animation>
<name>BlackBox</name>
<source>998/0@1</source>
</properties>

<properties>
<frame-color/>
<fill-color/>
Expand Down
184 changes: 184 additions & 0 deletions klayout_dot_config/tech/GSiP/pymacros/pcells_GSiP/FaML_Si_1550_BB.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import pya
import math
from SiEPIC._globals import PIN_LENGTH as pin_length
from SiEPIC.extend import to_itype
from SiEPIC.scripts import path_to_waveguide, connect_pins_with_waveguide, connect_cell
from SiEPIC.utils import get_technology_by_name, load_Waveguides_by_Tech, get_layout_variables

class FaML_Si_1550_BB(pya.PCellDeclarationHelper):
"""
The PCell declaration for black box cell
Facet-attached Micro-Lens (FaML)
for Silicon
for 1550 nm operation
Authors: Dream Photonics
"""

def __init__(self):

# Important: initialize the super class
super(FaML_Si_1550_BB, self).__init__()

self.technology_name = 'GSiP'
TECHNOLOGY = get_technology_by_name(self.technology_name)

# declare the parameters
self.param("num_channels", self.TypeInt, "Number of Channels (0 - 16)", default = 2)

self.param("ref_wg", self.TypeBoolean, "Include reference waveguide", default=False)

#declare the layers
self.param("silayer", self.TypeLayer, "Si Layer", default = TECHNOLOGY['Si'], hidden=False)
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("fibertarget", self.TypeLayer, "Fiber Target Layer", default=TECHNOLOGY['FbrTgt'], hidden=True)
self.param("textl", self.TypeLayer, "Text Layer", default=TECHNOLOGY['Text'], hidden=True)
self.param("bb",self.TypeLayer,"BB Layer", default=TECHNOLOGY['BlackBox'], hidden=True)

def can_create_from_shape_impl(self):
return False


def produce(self, layout, layers, parameters, cell):
# This is the main part of the implementation: create the layout
self.cell = cell
self._param_values = parameters
self.layout = layout

#fetch the parameters
dbu = self.layout.dbu
ly = self.layout
shapes = self.cell.shapes

LayerSiN = ly.layer(self.silayer)
LayerPinRecN = ly.layer(self.pinrec)
LayerDevRecN = ly.layer(self.devrec)
LayerFbrTgtN = ly.layer(self.fibertarget)
LayerTEXTN = ly.layer(self.textl)
LayerBBN = ly.layer(self.bb)

num_channels = self.num_channels
offset = to_itype(0,dbu)
pitch = to_itype(127,dbu)
l_taper = 60e3
Lw2 = to_itype(15,dbu)
Lw3 = Lw2 + to_itype(20,dbu)

wavelength = 1550

waveguide_type = 'Strip'
w_waveguide = 500 # nm

if num_channels < 0:
num_channels = 0
if num_channels > 16:
num_channels = 16

def circle(x,y,r):
npts = 180
theta = 2*math.pi/npts
pts = []
for i in range(0,npts):
pts.append(pya.Point.from_dpoint(pya.DPoint((x+r*math.cos(i*theta))/1,(y+r*math.sin(i*theta))/1)))
return pts

#draw one loopback device
if self.ref_wg:
for ref_loop in range(2):
#draw fibre target circle
align_circle = circle(offset,-pitch*(ref_loop+1),2/dbu)
#place fibre target circle
shapes(LayerFbrTgtN).insert(pya.Polygon(align_circle))

if self.ref_wg:
#create waveguide to for loopback
loopback_path = pya.DPath([pya.DPoint(0,-127),pya.DPoint((offset + l_taper + Lw2)*dbu+15,-127),pya.DPoint((offset + l_taper + Lw2)*dbu+15,-254),pya.DPoint(0,-254)],0.5)
self.layout.technology_name = self.technology_name #required otherwise "create_cell" doesn't load
pcell = self.layout.create_cell("Waveguide",self.technology_name,{"path": loopback_path, "waveguide_type": waveguide_type})
t = pya.Trans(pya.Trans.R0,0,0)
self.cell.copy(pcell,LayerSiN,LayerBBN)
wg = self.cell.insert(pya.CellInstArray(pcell.cell_index(),t))
wg.flatten()
self.cell.clear(LayerDevRecN)
self.cell.clear(LayerPinRecN)
self.cell.clear(LayerSiN)


##########################################################################################################################################################################
#draw N tapers
x = offset + l_taper + Lw3
for n_ch in range(int(num_channels)):

#draw the taper
taper_pts = [pya.Point(0,-w_waveguide/2+pitch*n_ch),pya.Point(0,w_waveguide/2+pitch*n_ch),pya.Point(offset + l_taper + Lw3,w_waveguide/2+pitch*n_ch),pya.Point(offset + l_taper + Lw3,-w_waveguide/2+pitch*n_ch)]

#place the taper
shapes(LayerBBN).insert(pya.Polygon(taper_pts))

#draw and place pin on the waveguide:
t = pya.Trans(pya.Trans.R0, x, pitch*n_ch)
pin = pya.Path([pya.Point(-pin_length/2,0),pya.Point(pin_length/2,0)], w_waveguide)
pin_t = pin.transformed(t)
shapes(LayerPinRecN).insert(pin_t)
text = pya.Text(f"opt{n_ch+1}",t)
shape = shapes(LayerPinRecN).insert(text)
shape.text_size = 3/dbu

#draw fibre target circle
align_circle = circle(offset,pitch*n_ch,2/dbu)

#place fibre target circle
shapes(LayerFbrTgtN).insert(pya.Polygon(align_circle))

#draw devrec box
n_ch = (num_channels-1)
if self.ref_wg:
devrec_pts = [pya.Point(0,pitch*n_ch+30/dbu),pya.Point(x,pitch*n_ch+30/dbu),pya.Point(x,-pitch*2-30/dbu),pya.Point(0,-pitch*2-30/dbu)]
else:
devrec_pts = [pya.Point(0,pitch*n_ch+30/dbu),pya.Point(x,pitch*n_ch+30/dbu),pya.Point(x,-30/dbu),pya.Point(0,-30/dbu)]

#place devrec box
shapes(LayerDevRecN).insert(pya.Polygon(devrec_pts))

#edge of chip text
t = pya.Trans(pya.Trans.R0,0,1/dbu)
text = pya.Text("<- Edge of chip",t)
shape = shapes(LayerTEXTN).insert(text)
shape.text_size = 3/dbu

#BB description
t = pya.Trans(pya.Trans.R0,0,-15/dbu)
text = pya.Text(" Number of Channel(s): " + str(num_channels) + "\n Center Wavelength: " + str(wavelength) + " nm",t)
shape = shapes(LayerTEXTN).insert(text)
shape.text_size = 3/dbu

#BB description
t = pya.Trans(pya.Trans.R0, 0,-25/dbu)
text = pya.Text("<- 25 MFD lens",t)
shape = shapes(LayerTEXTN).insert(text)
shape.text_size = 3/dbu

#draw lenses
width_lens = to_itype(50, dbu)
length_lens = to_itype(50, dbu)

if self.ref_wg:
for n_ch in range(int(num_channels+2)):
lens_pts = [pya.Point(0,-width_lens/2+pitch*n_ch-2*pitch), pya.Point(0,width_lens/2+pitch*n_ch-2*pitch), pya.Point(-length_lens,width_lens/2+pitch*n_ch-2*pitch),pya.Point(-length_lens,-width_lens/2+pitch*n_ch-2*pitch)]
shapes(LayerBBN).insert(pya.Polygon(lens_pts))
lens = circle(-length_lens,pitch*n_ch-2*pitch,25/dbu)
shapes(LayerBBN).insert(pya.Polygon(lens))
else:
for n_ch in range(int(num_channels)):
lens_pts = [pya.Point(0,-width_lens/2+pitch*n_ch), pya.Point(0,width_lens/2+pitch*n_ch), pya.Point(-length_lens,width_lens/2+pitch*n_ch),pya.Point(-length_lens,-width_lens/2+pitch*n_ch)]
shapes(LayerBBN).insert(pya.Polygon(lens_pts))
lens = circle(-length_lens,pitch*n_ch,25/dbu)
shapes(LayerBBN).insert(pya.Polygon(lens))

def display_text_impl(self):
# Provide a descriptive text for the cell
return "FaML_Si_1550_BB_%s" % (
self.num_channels,
)

Loading

0 comments on commit 97cbf32

Please sign in to comment.