Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FaML function and tests #224

Merged
merged 1 commit into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading