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

Merged
merged 13 commits into from
Oct 27, 2024
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
merge/EBeam.oas
merge/EBeam.txt

*.lyrdb

# Byte-compiled / optimized / DLL files
*/*.pyc
Expand Down
56 changes: 56 additions & 0 deletions DFT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

# Design for Test rules

- All design submissions must follow the Design for Test (DFT) rules. Three optical interfaces are available: surface grating couplers (GC), facet-attached micro-lenses (FaML), and facet-attached vertical emitters (FAVE).

## Grating Couplers

- area design maximum: 1000 µm wide, 500 µm high
- grating coupler cells:
- SiEPIC_EBeam_PDK -> EBeam-SiN ->
- GC_SiN_TE_1310_8degOxide_BB
- GC_SiN_TE_1550_8degOxide_BB
- 127 µm pitch, verically aligned, single column, connected circuits
- up to 4 grating couplers
- opt_in label format: opt_in_TE_1550_device_designerUniqueIndentifier
- opt_in label location: the tip (0,0) of the grating coupler cell at the input
- Fiber Array test consists of:
- 1 (top GC): output, to detector
- 2: input, laser
- 3: output, to detector
- 4 (bottom GC): output, to detector
- See example: EBeam_LukasChrostowski_MZI_1550.oas

## Facet-attached Micro-Lenses (FaML)

- area design maximum: 1000 µm wide, 500 µm high
- FaML coupler cells:
- SiEPIC_EBeam_PDK -> EBeam-Dream ->
- ebeam_dream_FaML_SiN_1550_BB
- 127 µm pitch, verically aligned, single column, connected circuits
- up to 4 lenses
- opt_in label format: opt_in_TE_1550_FaML_designerUniqueIndentifier
- opt_in label location: the lens and chip edge (0,0) of the FaML cell at the input
- Fiber Array test consists of:
- 1 (top FaML): input, laser
- 2 (middle FaML): output, to detector
- 3 (middle FaML): output, to detector
- 4 (bottom FaML): output, to detector
- See example: EBeam_LukasChrostowski_MZI1_1550_FaML.oas

## Facet-attached Vertical Emitters (FAVE)

- area design maximum: 1000 µm wide, 500 µm high
- FaML coupler cells:
- SiEPIC_EBeam_PDK -> EBeam-Dream ->
- ebeam_dream_FAVE_SiN_1550_BB
- 127 µm pitch, verically aligned, single column, connected circuits
- up to 4 lenses
- opt_in label format: opt_in_TE_1550_FAVE_designerUniqueIndentifier
- opt_in label location: the edge (0,0) of the FAVE cell at the input
- Fiber Array test consists of:
- 1 (top FAVE): input, laser
- 2 (middle FAVE): output, to detector
- 3 (middle FAVE): output, to detector
- 4 (bottom FAVE): output, to detector
- See example: EBeam_LukasChrostowski_MZI_1550_FAVE.oas
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
- Baseline process:
- Single full etch, using a negative resist (HSQ)
- Oxide cladding
- Edge coupling
- Facet-attached micro-lenses and vertical emitters
- Process Design Kit: [SiEPIC-EBeam-PDK](https://github.com/siepic/SiEPIC_EBeam_PDK)
- [Design for Test rules](DFT.md)

## Layer table
| Name | Layer/datatype | Description |
Expand Down
142 changes: 112 additions & 30 deletions merge/EBeam_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
tech_name = 'EBeam'
top_cell_name = 'EBeam_2024_10_SiN'
cell_Width = 1000e3
cell_Height = 410000
cell_Gap_Width = 8000
cell_Gap_Height = 8000
cell_FaML_width_extra = 100e3
cell_Height = 500e3
cell_Gap_Width = 8e3
cell_Gap_Height = 8e3
chip_Width = 8650000
chip_Height1 = 8490000
chip_Height2 = 8780000
Expand All @@ -32,7 +33,7 @@
tr_cutout_y = 8494000

filename_out = 'EBeam'
layers_keep = ['1/5', '4/0', '1/10', '68/0', '81/0', '10/0', '99/0', '26/0', '31/0', '32/0', '33/0', '998/0']
layers_keep = ['1/5', '4/0', '1/10', '68/0', '81/0', '10/0', '99/0', '26/0', '31/0', '32/0', '33/0', '201/0','998/0']
layer_text = '10/0'
layer_SEM = '200/0'
layer_SEM_allow = ['edXphot1x', 'ELEC413','SiEPIC_Passives'] # which submission folder is allowed to include SEM images
Expand All @@ -51,7 +52,7 @@

# KLayout
import pya
from pya import *
from pya import Trans, CellInstArray, Text

# SiEPIC-Tools
import SiEPIC
Expand Down Expand Up @@ -115,12 +116,18 @@ def log(text):
path2 = os.path.abspath(os.path.join(path,"../submissions"))
_, _, files = next(os.walk(path2), (None, None, []))
for f in sorted(files):
files_in.append(os.path.join(path2,f))
if 'FaML' in f:
files_in.append(os.path.join(path2,f))
for f in sorted(files):
if 'FaML' not in f:
files_in.append(os.path.join(path2,f))

# Create course cells using the folder name under the top cell
cell_edXphot1x = layout.create_cell("edX")
t = Trans(Trans.R0, 0,0)
top_cell.insert(CellInstArray(cell_edXphot1x.cell_index(), t))
cell_FaML = layout.create_cell("FaML")
top_cell.insert(CellInstArray(cell_FaML.cell_index(), t))
cell_ELEC413 = layout.create_cell("ELEC413")
top_cell.insert(CellInstArray(cell_ELEC413.cell_index(), t))
cell_SiEPIC_Passives = layout.create_cell("SiEPIC_Passives")
Expand All @@ -137,6 +144,7 @@ def log(text):

# Origins for the layouts
x,y = 110e3,cell_Height+cell_Gap_Height
previous_top_FaML = None

import subprocess
import pandas as pd
Expand All @@ -160,16 +168,17 @@ def log(text):
layout2 = pya.Layout()
layout2.read(f)

course = 'openEBL'
if 'ebeam' in basefilename.lower():
course = 'edXphot1x'
elif 'elec413' in basefilename.lower():
if 'faml' in basefilename.lower():
course = 'FaML'
if 'elec413' in basefilename.lower():
course = 'ELEC413'
elif 'openebl' in basefilename.lower():
if 'openebl' in basefilename.lower():
course = 'openEBL'
elif 'siepic_passives' in basefilename.lower():
if 'siepic_passives' in basefilename.lower():
course = 'SiEPIC_Passives'
else:
course = 'openEBL'

cell_course = eval('cell_' + course)
log(" - course name: %s" % (course) )
Expand All @@ -193,7 +202,15 @@ def log(text):
# check that there is one top cell in the layout
num_top_cells = len(layout2.top_cells())
if num_top_cells > 1:
log(' - layout should only contain one top cell; contains (%s): %s' % (num_top_cells, [c.name for c in layout2.top_cells()]) )
log(' - WARNING: layout should only contain one top cell; contains (%s): %s' % (num_top_cells, [c.name for c in layout2.top_cells()]) )
top_cells = layout2.top_cells()
top_cells.sort(key=lambda x: x.child_instances())
log(' - top cell (%s) has %s child_instances (highest one); renaming to "top".' % (top_cells[-1].name, top_cells[-1].child_instances()) )
top_cells[-1].name = 'top'
'''
for cell in layout2.top_cells():
log(' - top cell (%s) has %s hierarchy levels' % (cell.name, cell.hierarchy_levels()) )
'''
if num_top_cells == 0:
log(' - layout does not contain a top cell')

Expand Down Expand Up @@ -258,6 +275,7 @@ def log(text):
shapes_to_delete.append( s.shape() )
s.next()
for s in shapes_to_delete:
# need to delete the shapes all together, since the list of shapes in the shape recursive iterator changes if you delete one
s.delete()

# bounding box of the cell
Expand All @@ -269,24 +287,24 @@ def log(text):
t = Trans(Trans.R0, -bbox.left,-bbox.bottom)
subcell2.insert(CellInstArray(subcell.cell_index(), t))

# clip cells
cell2 = layout2.clip(cell.cell_index(), pya.Box(bbox.left,bbox.bottom,bbox.left+cell_Width,bbox.bottom+cell_Height))
# clip / crop cells
cell2 = layout2.clip(cell.cell_index(), pya.Box(bbox.left,bbox.bottom,bbox.left+cell_Width+(cell_FaML_width_extra if course == 'FaML' else 0),bbox.bottom+cell_Height))
bbox2 = layout2.cell(cell2).bbox()
if bbox != bbox2:
log(' - WARNING: Cell was clipped to maximum size of %s X %s' % (cell_Width, cell_Height) )
log(' - WARNING: Cell was clipped to maximum size of %s X %s' % (cell_Width +(cell_FaML_width_extra if course == 'FaML' else 0), cell_Height) )
log(' - clipped bounding box: %s' % bbox2.to_s() )

# copy
subcell.copy_tree(layout2.cell(cell2))

subcell.copy_tree(cell)
'''
if course is not 'FaML':
# copy
subcell.copy_tree(layout2.cell(cell2))
else:
subcell.copy_tree(cell)
'''

# Check if this cell would overlap with other Floorplans, then move if necessary
def next_position(x, y, subcell, cell_Gap_Height, cell_Gap_Width, chip_Height, cell_Height, cell_Width):
# Measure the height of the cell that was added, and move up
y += cell_Gap_Height
if y + cell_Height > chip_Height:
y = cell_Height + cell_Gap_Height
x += cell_Width + cell_Gap_Width
return x, y

# Get Floorplan regions for the entire chip so far
Layer_FP = layout.find_layer(99,0) # or use "layer"
iter1 = pya.RecursiveShapeIterator(layout, top_cell, Layer_FP )
Expand All @@ -297,23 +315,85 @@ def next_position(x, y, subcell, cell_Gap_Height, cell_Gap_Width, chip_Height, c
iter1.next()
r1.merge()
# print(" - Floorplan merged: %s" % r1)

# offset for the facet-attached micro lenses
if course == 'FaML':
x_offset = -100e3
# Find the FaML cells, and make sure they are on a 127 µm pitch
def sub_instances(instance,name):
found_instances = []
if type(instance) == pya.Cell:
cell = instance
else:
cell = instance.cell()
for inst in cell.each_inst():
# log(' - looking for FaML instance: %s' % (inst.to_s()))
if inst.cell.name == name:
found_instances.append(inst)
# log(' - Found FaML instance: %s, %s' % (inst.to_s(), inst.cell.name))
elif inst.cell.child_instances() > 0:
for f in sub_instances(inst,name):
if f.cell.name == name:
found_instances.append(f)
return found_instances

found_faml_instances = sub_instances(layout2.top_cells()[0], name = 'ebeam_dream_FaML_SiN_1550_BB')
#for f in found_faml_instances:
# log(' - Found FaML instance: %s, %s' % (f.to_s(), f.cell.name))
found_faml_instances.sort(key=lambda x: -x.cplx_trans.disp.y)
for f in found_faml_instances:
log(' - Found FaML instance (sorted): %s, %s' % (f.to_s(), f.cell.name))
top_FaML = found_faml_instances[0].cplx_trans.disp.y

else:
x_offset = 0

def next_position(x, y, cell_Gap_Height, cell_Gap_Width, chip_Height, cell_Height, cell_Width):
# Measure the height of the cell that was added, and move up
y += cell_Gap_Height
if y + cell_Height > chip_Height:
y = cell_Height + cell_Gap_Height
x += cell_Width + cell_Gap_Width
return x, y

interacting = True
while interacting:
r2 = pya.Region(pya.Box(x,y, x+bbox2.width(),y+bbox2.height()))
r2 = pya.Region(pya.Box(x+x_offset,y, x+x_offset+bbox2.width(),y+bbox2.height()))
interacting = r2.interacting(r1)
if interacting:
# print(" - Overlapping Floorplan: %s" % r2.interacting(r1))
x,y = next_position(x, y, subcell, cell_Gap_Height, cell_Gap_Width, chip_Height2, cell_Height, cell_Width)
x,y = next_position(x, y, cell_Gap_Height, cell_Gap_Width, chip_Height2, cell_Height, cell_Width)

if course == 'FaML':
# Check and snap to 127 µm pitch
if previous_top_FaML:
FaML_delta = top_FaML+y - previous_top_FaML
log(' - FaML count: %s' % (FaML_delta/127e3) )
if FaML_delta % 127e3 > 0:
# log(' - Adjancent designs do not have matching FaML pitch: %s error' % (FaML_delta) )
y_add = 127e3 - FaML_delta % 127e3
log(' - shifting design up by %s µm, to have matching FaML pitch.' % (y_add/1e3) )
y += y_add


# Insert cell instance in the chip
t = Trans(Trans.R0, x,y)
t = Trans(Trans.R0, x+x_offset,y)
cell_course.insert(CellInstArray(subcell2.cell_index(), t))

log(' - Placed at position: %s, %s' % (x,y) )
log(' - Design placed at position: %s, %s' % (x,y) )

if course == 'FaML':
# record placement of FaML
previous_top_FaML = found_faml_instances[0].cplx_trans.disp.y + y
log(' - top FaML position: %s' % (previous_top_FaML) )

# Measure the height of the cell that was added, and move up
y += max (cell_Height, subcell.bbox().height()) + cell_Gap_Height
#y += max (cell_Height, subcell.bbox().height()) + cell_Gap_Height
if course == 'FaML':
from math import ceil
y += ceil(subcell.bbox().height()/127e3)*127e3
else:
y += subcell.bbox().height() + cell_Gap_Height
# move right and bottom when we reach the top of the chip
if y + cell_Height > chip_Height1 and x == 0:
y = cell_Height + cell_Gap_Height
Expand All @@ -332,6 +412,8 @@ def next_position(x, y, subcell, cell_Gap_Height, cell_Gap_Width, chip_Height, c
# Check bottom right cutout #2 for PCM
if x + cell_Width > br_cutout2_x and y < br_cutout2_y:
y = br_cutout2_y
else:
log(" - WARNING: Top cell not merged (%s)" % cell.name)

'''
text_out,opt_in = find_automated_measurement_labels(topcell=top_cell, LayerTextN=layerTextN)
Expand Down
16 changes: 12 additions & 4 deletions run_verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@

"""

cell_Width = 1000e3
cell_Height = 500e3
cell_FaML_width_extra = 100e3


# gds file to run verification on
gds_file = sys.argv[1]


try:
# load into layout
layout = pya.Layout()
Expand Down Expand Up @@ -52,11 +58,13 @@
num_errors = layout_check(cell = top_cell, verbose=False, GUI=True, file_rdb=file_lyrdb)

# Make sure layout extent fits within the allocated area.
cell_Width = 1000e3
cell_Height = 410000
if 'faml' in filename.lower():
cell_Width_check = cell_Width + cell_FaML_width_extra
else:
cell_Width_check = cell_Width
bbox = top_cell.bbox()
if bbox.width() > cell_Width or bbox.height() > cell_Height:
print('Error: Cell bounding box / extent (%s, %s) is larger than the maximum size of %s X %s microns' % (bbox.width()/1000, bbox.height()/1000, cell_Width/1000, cell_Height/1000) )
if bbox.width() > cell_Width_check or bbox.height() > cell_Height:
print('Error: Cell bounding box / extent (%s, %s) is larger than the maximum size of %s X %s microns' % (bbox.width()/1000, bbox.height()/1000, cell_Width_check/1000, cell_Height/1000) )
num_errors += 1
except:
print('Unknown error occurred')
Expand Down
Binary file not shown.
Binary file not shown.
Binary file modified submissions/EBeam_LukasChrostowski_MZI_1550.oas
Binary file not shown.
Binary file not shown.
Binary file removed submissions/EBeam_LukasChrostowski_MZI_1550_FaML.oas
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading