-
Notifications
You must be signed in to change notification settings - Fork 150
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #55 from luzeqin/master
Master Former-commit-id: 00fb32b
- Loading branch information
Showing
5 changed files
with
297 additions
and
41 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
257 changes: 257 additions & 0 deletions
257
klayout_dot_config/pymacros/INTERCONNECT - WithinWafer MC simulation.lym
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<klayout-macro> | ||
<description>Lumerical INTERCONNECT - DtD Monte Carlo simulations</description> | ||
<version/> | ||
<category>pymacros</category> | ||
<prolog/> | ||
<epilog/> | ||
<doc/> | ||
<autorun>false</autorun> | ||
<autorun-early>false</autorun-early> | ||
<shortcut/> | ||
<show-in-menu>true</show-in-menu> | ||
<group-name/> | ||
<menu-path>siepic_menu.end</menu-path> | ||
<interpreter>python</interpreter> | ||
<dsl-interpreter-name/> | ||
<text># Python script | ||
# SiEPIC_EBeam_functions | ||
|
||
""" | ||
This file is part of the SiEPIC_EBeam_PDK | ||
by Lukas Chrostowski (c) 2015 | ||
|
||
This Python file extract the circuit netlist from the physical layout, saves it to Spice file, | ||
and launches Lumerical INTERCONNECT for circuit simulations. | ||
|
||
Version history: | ||
|
||
Lukas Chrostowski 2015/11/19 | ||
- initial version | ||
- generating a Spice netlist including Optical Network Analyzer; launch Lumerical INTERCONNECT simulation | ||
|
||
Zeqin Lu 2016/2/18 | ||
- Within Wafer Monte Carlo simulation | ||
|
||
""" | ||
|
||
import os | ||
print(os.name) | ||
|
||
import platform | ||
print(platform.system()) | ||
print(platform.release()) | ||
|
||
import sys | ||
version = sys.version | ||
|
||
import string | ||
|
||
SIMULATION = 2 # INTERCONNECT simulation | ||
|
||
INTERCONNECT_VISUALIZER = 1 # Plot the data using the Lumerical visualizer, or a regular plot? | ||
|
||
|
||
# find the currently selected cell: | ||
topcell = pya.Application.instance().main_window().current_view().active_cellview().cell | ||
if topcell == None: | ||
raise Exception("No cell") | ||
layout = topcell.layout() | ||
dbu = layout.dbu | ||
|
||
# initialize the arrays to keep track of layout objects | ||
optical_components = [] | ||
optical_waveguides = [] | ||
optical_pins = [] | ||
optical_nets = [] | ||
|
||
# Define layers based on the PDK: | ||
LayerSiN = layout.layer(LayerSi) | ||
LayerTextN = layout.layer(LayerText) | ||
LayerPinRecN = layout.layer(LayerPinRec) | ||
LayerDevRecN = layout.layer(LayerDevRec) | ||
LayerFbrTgtN = layout.layer(LayerFbrTgt) | ||
LayerErrorN = layout.layer(LayerError) | ||
LayerINTERCONNECTN = layout.layer(LayerINTERCONNECT) | ||
|
||
|
||
# extract the circuit netlist from the physical layout: | ||
optical_waveguides, optical_components = netlist_extraction(topcell)[:2] | ||
|
||
# Output the Spice netlist: | ||
text_Spice, num_detectors = generate_Spice_file(topcell, optical_waveguides, optical_components) | ||
print(text_Spice) | ||
|
||
if sys.platform.startswith("win"): | ||
|
||
folder_name = app.application_data_path() | ||
if not os.path.isdir(folder_name+'/tmp'): | ||
os.makedirs(folder_name+"/tmp") | ||
filename = folder_name + '/tmp/%s.spi' % topcell.name | ||
filename2 = folder_name + '/tmp/%s.lsf' % topcell.name | ||
else: | ||
|
||
filename = '/tmp/%s.spi' % topcell.name | ||
filename2 = '/tmp/%s.lsf' % topcell.name | ||
|
||
# Write the Spice netlist to file | ||
file = open(filename, 'w') | ||
file.write (text_Spice) | ||
file.close() | ||
|
||
# Write the Lumerical INTERCONNECT start-up script. | ||
file = open(filename2, 'w') | ||
text_lsf = '###DEVELOPER:Zeqin Lu, University of British Columbia, Feb. 2016 \n' | ||
|
||
text_lsf += 'switchtolayout;\n' | ||
text_lsf += 'deleteall;\n' | ||
text_lsf += 'importnetlist("%s");\n' % filename | ||
text_lsf += 'addproperty("::Root Element", "wafer_uniformity_thickness", "wafer", "Matrix");\n' | ||
text_lsf += 'addproperty("::Root Element", "wafer_uniformity_width", "wafer", "Matrix");\n' | ||
text_lsf += 'addproperty("::Root Element", "N", "wafer", "Number");\n' | ||
text_lsf += 'addproperty("::Root Element", "die_num", "wafer", "Number");\n' | ||
text_lsf += 'addproperty("::Root Element", "wafer_length", "wafer", "Number");\n' | ||
|
||
text_lsf += 'addproperty("::Root Element::%s", "MC_uniformity_thickness", "wafer", "Matrix");\n' % topcell.name | ||
text_lsf += 'addproperty("::Root Element::%s", "MC_uniformity_width", "wafer", "Matrix");\n' % topcell.name | ||
text_lsf += 'addproperty("::Root Element::%s", "MC_grid", "wafer", "Number");\n' % topcell.name | ||
text_lsf += 'addproperty("::Root Element::%s", "MC_resolution_x", "wafer", "Number");\n' % topcell.name | ||
text_lsf += 'addproperty("::Root Element::%s", "MC_resolution_y", "wafer", "Number");\n' % topcell.name | ||
text_lsf += 'addproperty("::Root Element::%s", "MC_non_uniform", "wafer", "Number");\n' % topcell.name | ||
|
||
############################## Wafer generation ########################################### | ||
text_lsf += 'wafer_length = 100000e-6; \n' #100x100 mm^2 wafer | ||
text_lsf += 'clx = 4500e-6; \n' # Correlation length in x | ||
text_lsf += 'cly = 4500e-6; \n' # Correlation length in y | ||
text_lsf += 'N = 500; \n' | ||
text_lsf += 'wafer_grid=wafer_length/N; \n' | ||
|
||
text_lsf += 'sigma_rms_width = 15/3; \n' | ||
text_lsf += 'sigma_rms_thickness = 6/3; \n' | ||
|
||
text_lsf += 'x = linspace(-wafer_length/2,wafer_length/2,N); \n' | ||
text_lsf += 'y = linspace(-wafer_length/2,wafer_length/2,N); \n' | ||
text_lsf += 'xx = meshgridx(x,y) ; \n' | ||
text_lsf += 'yy = meshgridy(x,y) ; \n' | ||
|
||
text_lsf += 'Z_thickness = sigma_rms_thickness*randnmatrix(N,N); \n' | ||
text_lsf += 'F_thickness = exp(-(abs(xx)/(clx/2)+abs(yy)/(cly/2))); \n' # exponential filter | ||
text_lsf += 'wafer_uniformity_thickness = real( 2*wafer_length/N/sqrt(clx*cly)*invfft(fft(Z_thickness,1,0)*fft(F_thickness,1,0), 1, 0) ); \n' # wafer created using exponential filter | ||
#text_lsf += 'F_thickness = exp(-(xx^2/(clx^2/2)+yy^2/(cly^2/2))); \n' # Gaussian filter | ||
#text_lsf += 'wafer_uniformity_thickness = real( 2/sqrt(pi)*wafer_length/N/sqrt(clx)/sqrt(cly)*invfft(fft(Z_thickness,1,0)*fft(F_thickness,1,0), 1, 0) ); \n' # wafer created using Gaussian filter | ||
|
||
text_lsf += 'Z_width = sigma_rms_width*randnmatrix(N,N); \n' | ||
text_lsf += 'F_width = exp(-(abs(xx)/(clx/2)+abs(yy)/(cly/2))); \n' # exponential filter | ||
text_lsf += 'wafer_uniformity_width = real( 2*wafer_length/N/sqrt(clx*cly)*invfft(fft(Z_width,1,0)*fft(F_width,1,0), 1, 0) ); \n' # wafer created using exponential filter | ||
#text_lsf += 'F_width = exp(-(xx^2/(clx^2/2)+yy^2/(cly^2/2))); \n' # Gaussian filter | ||
#text_lsf += 'wafer_uniformity_width = real( 2/sqrt(pi)*wafer_length/N/sqrt(clx)/sqrt(cly)*invfft(fft(Z_width,1,0)*fft(F_width,1,0), 1, 0) ); \n' # wafer created using Gaussian filter | ||
|
||
##################################### pass wafers to root ################### | ||
text_lsf += '#pass wafers to object \n' | ||
text_lsf += 'select("::Root Element"); \n' | ||
text_lsf += 'set("wafer_uniformity_thickness", wafer_uniformity_thickness); \n' | ||
text_lsf += 'set("wafer_uniformity_width", wafer_uniformity_width); \n' | ||
text_lsf += 'set("N",N); \n' | ||
text_lsf += 'set("wafer_length",wafer_length); \n' | ||
|
||
text_lsf += 'select("::Root Element");\n' | ||
text_lsf += 'set("setup script",'+ "'" + ' \n' | ||
text_lsf += '######################## high resolution interpolation for dies ################# \n' | ||
text_lsf += 'MC_grid = 5e-6; \n' | ||
text_lsf += 'die_span_x = 5000e-6; \n' | ||
text_lsf += 'die_span_y = 5000e-6; \n' | ||
text_lsf += 'MC_resolution_x = die_span_x/MC_grid; \n' | ||
text_lsf += 'MC_resolution_y = die_span_y/MC_grid; \n' | ||
text_lsf += 'die_num_x = floor(wafer_length/die_span_x); \n' | ||
text_lsf += 'die_num_y = floor(wafer_length/die_span_y); \n' | ||
text_lsf += 'die_num_total = die_num_x*die_num_y; \n' | ||
text_lsf += 'x = linspace(-wafer_length/2,wafer_length/2,N); \n' | ||
text_lsf += 'y = linspace(-wafer_length/2,wafer_length/2,N); \n' | ||
|
||
# pick die for simulation | ||
text_lsf += 'if (die_num<=die_num_total) { \n' | ||
text_lsf += 'j=die_num; \n' | ||
text_lsf += 'die_min_x = -wafer_length/2+(j-1)*die_span_x -floor((j-1)/die_num_x)*wafer_length; \n' | ||
text_lsf += 'die_max_x = -wafer_length/2+j*die_span_x -floor((j-1)/die_num_x)*wafer_length; \n' | ||
text_lsf += 'die_min_y = wafer_length/2-ceil(j/die_num_y)*die_span_y; \n' | ||
text_lsf += 'die_max_y = wafer_length/2-(ceil(j/die_num_y)-1)*die_span_y; \n' | ||
|
||
text_lsf += 'x_die = linspace(die_min_x, die_max_x, MC_resolution_x); \n' | ||
text_lsf += 'y_die = linspace(die_min_y, die_max_y, MC_resolution_y); \n' | ||
|
||
text_lsf += 'MC_uniformity_thickness = interp(wafer_uniformity_thickness, x, y, x_die, y_die); # interpolation \n' | ||
text_lsf += 'MC_uniformity_width = interp(wafer_uniformity_width, x, y, x_die, y_die); # interpolation \n' | ||
text_lsf += '} \n' | ||
|
||
text_lsf += '#pass wafers to object \n' | ||
text_lsf += 'select("::Root Element::%s"); \n' % topcell.name | ||
text_lsf += 'set("MC_uniformity_thickness",MC_uniformity_thickness); \n' | ||
text_lsf += 'set("MC_uniformity_width",MC_uniformity_width); \n' | ||
text_lsf += 'set("MC_resolution_x",MC_resolution_x); \n' | ||
text_lsf += 'set("MC_resolution_y",MC_resolution_y); \n' | ||
text_lsf += 'set("MC_grid",MC_grid); \n' | ||
text_lsf += 'set("MC_non_uniform",1); \n' | ||
|
||
text_lsf += "'"+'); \n' | ||
|
||
|
||
text_lsf += '#Run Monte Carlo simulations; \n' | ||
if INTERCONNECT_VISUALIZER: | ||
for i in range(0, num_detectors): | ||
text_lsf += 'mc%s = matrixdataset("mc%s"); # initialize visualizer data, mc%s \n' % (i+1, i+1, i+1) | ||
text_lsf += 'seed=randreset; \n' | ||
text_lsf += 'for (simu=1;simu<=5;simu=simu+1) { \n' | ||
text_lsf += ' switchtodesign; \n' | ||
text_lsf += ' select("::Root Element"); \n' | ||
text_lsf += ' set("die_num",simu); \n' | ||
text_lsf += ' run;\n' | ||
|
||
text_lsf += ' select("ONA_1");\n' | ||
text_lsf += ' f_start = get("start frequency");\n' | ||
text_lsf += ' f_stop = get("stop frequency");\n' | ||
text_lsf += ' num_points = get("number of points");\n' | ||
text_lsf += ' wavelength = c/f_start : (c/f_stop-c/f_start)/(num_points-1) : c/f_stop;\n' | ||
|
||
if INTERCONNECT_VISUALIZER: | ||
for i in range(0, num_detectors): | ||
text_lsf += ' if (simu==1) { mc%s.addparameter("wavelength",wavelength);} \n' % (i+1) | ||
text_lsf += ' mc%s.addattribute("run", getattribute ( getresult("ONA_1", "input %s/mode 1/gain"), "TE gain (dB)") );\n' % (i+1, i+1) | ||
else: | ||
text_lsf += ' gain = getattribute( getresult("ONA_1","input 1/mode 1/gain"), "TE gain (dB)" );\n' | ||
text_lsf += ' plot(wavelength,gain);\n' | ||
text_lsf += ' holdon;\n' | ||
|
||
text_lsf += '}\n' | ||
if INTERCONNECT_VISUALIZER: | ||
for i in range(0, num_detectors): | ||
text_lsf += 'visualize(mc%s);\n' % (i+1) | ||
|
||
|
||
file.write (text_lsf) | ||
file.close() | ||
|
||
print(text_lsf) | ||
|
||
if sys.platform.startswith('linux'): | ||
# Linux-specific code here... | ||
if string.find(version,"2.") > -1: | ||
import commands | ||
print("Running INTERCONNECT") | ||
commands.getstatusoutput('/CMC/tools/lumerical/INTERCONNECT-5.0.527/bin/interconnect') | ||
|
||
elif sys.platform.startswith('darwin'): | ||
# OSX specific | ||
if string.find(version,"2.7.") > -1: | ||
import commands | ||
print("Running INTERCONNECT") | ||
#commands.getstatusoutput('open /Applications/Lumerical/INTERCONNECT/INTERCONNECT.app --args %s' % filename) | ||
commands.getstatusoutput('open -n /Applications/Lumerical/INTERCONNECT/INTERCONNECT.app --args -run %s' % filename2) | ||
|
||
elif sys.platform.startswith('win'): | ||
# Windows specific code here | ||
import subprocess | ||
print("Running INTERCONNECT") | ||
subprocess.Popen(args=['C:\\Program Files\\Lumerical\\INTERCONNECT\\bin\\interconnect.exe', '-run', filename2], shell=True) | ||
|
||
</text> | ||
</klayout-macro> |