diff --git a/SiEPIC_EBeam_PDK_Verification_Check.gds b/SiEPIC_EBeam_PDK_Verification_Check.gds
index 67c61a03..45e6afd3 100644
Binary files a/SiEPIC_EBeam_PDK_Verification_Check.gds and b/SiEPIC_EBeam_PDK_Verification_Check.gds differ
diff --git a/klayout_dot_config/libraries/SiEPIC-EBeam.gds b/klayout_dot_config/libraries/SiEPIC-EBeam.gds
index 55862933..baf74a6a 100644
Binary files a/klayout_dot_config/libraries/SiEPIC-EBeam.gds and b/klayout_dot_config/libraries/SiEPIC-EBeam.gds differ
diff --git a/klayout_dot_config/pymacros/INTERCONNECT.lym b/klayout_dot_config/pymacros/INTERCONNECT.lym
index d12ecadb..8c0ca355 100644
--- a/klayout_dot_config/pymacros/INTERCONNECT.lym
+++ b/klayout_dot_config/pymacros/INTERCONNECT.lym
@@ -44,7 +44,7 @@ version = sys.version
import string
-
+"""
def netlist_extraction(topcell):
# Collection of functions to extract the circuit netlist from the physical layout
@@ -66,7 +66,7 @@ def netlist_extraction(topcell):
identify_all_nets(optical_pins, optical_waveguides, optical_components)
return optical_waveguides, optical_components
-
+"""
@@ -94,10 +94,10 @@ LayerINTERCONNECTN = layout.layer(LayerINTERCONNECT)
# extract the circuit netlist from the physical layout:
-optical_waveguides, optical_components = netlist_extraction(topcell)
+optical_waveguides, optical_components = netlist_extraction(topcell)[:2]
# Output the Spice netlist:
-text_Spice = generate_Spice_file(topcell, optical_waveguides, optical_components)
+text_Spice, num_detectors = generate_Spice_file(topcell, optical_waveguides, optical_components)
print text_Spice
filename = '/tmp/%s.spi' % topcell.name
@@ -112,11 +112,17 @@ text_lsf = 'switchtolayout;\n'
text_lsf += 'deleteall;\n'
text_lsf += 'importnetlist("%s");\n' % filename
text_lsf += 'run;\n'
-text_lsf += 't1 = getresult("ONA_1", "input 1/mode 1/gain");\n'
-text_lsf += 'visualize(t1);\n'
+for i in range(0, num_detectors):
+ text_lsf += 't%s = getresult("ONA_1", "input %s/mode 1/gain");\n' % (i+1, i+1)
+text_lsf += 'visualize(t1'
+for i in range(1, num_detectors):
+ text_lsf += ', t%s' % (i+1)
+text_lsf += ');\n'
+
file.write (text_lsf)
file.close()
+print(text_lsf)
if sys.platform.startswith('freebsd'):
# FreeBSD-specific code here...
diff --git a/klayout_dot_config/pymacros/ResultsMarker_tests.lym b/klayout_dot_config/pymacros/ResultsMarker_tests.lym
new file mode 100644
index 00000000..5cc587c2
--- /dev/null
+++ b/klayout_dot_config/pymacros/ResultsMarker_tests.lym
@@ -0,0 +1,63 @@
+
+
+
+
+ pymacros
+
+
+
+ false
+ false
+
+ false
+
+
+ python
+
+ import pya
+
+# Experimenting with the Results database Rdb.
+
+
+
+# Configure variables to draw structures in the presently selected cell:
+lv = pya.Application.instance().main_window().current_view()
+if lv == None:
+ raise Exception("No view selected")
+# Find the currently selected layout.
+ly = pya.Application.instance().main_window().current_view().active_cellview().layout()
+if ly == None:
+ raise Exception("No layout")
+cv = pya.Application.instance().main_window().current_view().active_cellview()
+# find the currently selected cell:
+cell = pya.Application.instance().main_window().current_view().active_cellview().cell
+if cell == None:
+ raise Exception("No cell")
+# fetch the database parameters
+dbu = ly.dbu
+
+
+rdb_i = lv.create_rdb("SiEPIC_Verification")
+rdb = lv.rdb(rdb_i)
+
+rdb_cat_id_wg = rdb.create_category("Waveguide errors")
+rdb_cat_id_wg_disc = rdb.create_category(rdb_cat_id_wg, "Disconnected Waveguides")
+rdb_cat_id_wg_disc.description = "Disconnected waveguides"
+
+rdb.top_cell_name = cell.name
+rdb_cell = rdb.create_cell(cell.name)
+
+rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_wg_disc.rdb_id())
+rdb_item.add_value(pya.RdbItemValue(pya.DBox.new(0.0, 0.0, 100.0, 200.0)))
+
+#rdb_item.add_value(pya.RdbItemValue(DPath))
+
+
+
+#marker = pya.Marker.new(lv)
+#marker.set(pya.DBox.new(0.0, 0.0, 100.0, 200.0))
+# to hide the marker:
+
+
+lv.show_rdb(rdb_i, cv.cell_index)
+
diff --git a/klayout_dot_config/pymacros/SiEPIC_EBeam_Path_to_Waveguide.lym b/klayout_dot_config/pymacros/SiEPIC_EBeam_Path_to_Waveguide.lym
index c567fd01..e1732c6a 100644
--- a/klayout_dot_config/pymacros/SiEPIC_EBeam_Path_to_Waveguide.lym
+++ b/klayout_dot_config/pymacros/SiEPIC_EBeam_Path_to_Waveguide.lym
@@ -119,7 +119,8 @@ for o in object_selection:
print ("Selected object is a shape")
if o.shape.is_path():
c = o.shape.cell
- if c.name == "ROUND_PATH" and c.is_pcell_variant() and c.pcell_parameters_by_name()['layer'] == LayerSi:
+ print (c.basic_name())
+ if c.basic_name() == "ROUND_PATH" and c.is_pcell_variant() and c.pcell_parameters_by_name()['layer'] == LayerSi:
# we have a waveguide GUIDING_LAYER selected
print ("GUIDING_LAYER in ROUND_PATH on LayerSi. We will not convert this to waveguide!")
else:
diff --git a/klayout_dot_config/pymacros/SiEPIC_EBeam_Verification.lym b/klayout_dot_config/pymacros/SiEPIC_EBeam_Verification.lym
index 89fbd992..4bdbc7d5 100644
--- a/klayout_dot_config/pymacros/SiEPIC_EBeam_Verification.lym
+++ b/klayout_dot_config/pymacros/SiEPIC_EBeam_Verification.lym
@@ -1,6 +1,6 @@
- SiEPIC: Verification and Netlist generation
+ SiEPIC: Verification (rdb)
0.1.2
pymacros
@@ -22,7 +22,7 @@ This file is part of the SiEPIC_EBeam_PDK
by Lukas Chrostowski (c) 2015
This Python file implements layout verification and netlist extraction
-
+displays results in Marker Database Browser, using Results Database (rdb)
Version history:
@@ -60,235 +60,12 @@ Lukas Chrostowski 2015/11/18
Lukas Chrostowski 2015/11/19
- moved some functions to SiEPIC_EBeam_functions
-
-"""
-
-
-import pya
-import math
-#import numpy
-MODULE_NUMPY = False
-import math
-import string
-
-
-
-def flag_waveguide_error(dpoints, text, optical_waveguide, topcell):
- # global variable "layout_errors" of class "Layout_error" used for storing all the errors.
- a1 = []
- for p in dpoints:
- a1.append (pya.Point(int(p[0]), int(p[1])))
- path = pya.Path(a1, optical_waveguide.wg_width*4/dbu)
- topcell.shapes(LayerErrorN).insert(path)
- x,y = xy_mean_mult(dpoints, dbu)
- layout_errors.append(Layout_error(text, x, y) )
- print (text)
- wtext.insertHtml('%s<br>' %text)
-
+Lukas Chrostowski 2015/11/21
+ - adding Results Database (rdb) and Marker Database Browser, for error viewing
-def check_waveguides(optical_waveguides, topcell, error_layer):
- # check waveguides for basic errors.
- num_errors=0
- for o in optical_waveguides:
- found_error = False
-
- # Check for paths with > 2 vertices
- if (o.wg_type == 0 and o.num_points > 2):
- text = " *** Layout error. Waveguide path (%s, %s): Only 2 points allowed in a path. Convert to a waveguide (ROUND_PATH) if necessary. " \
- % ( o.points[0][0]*dbu, o.points[0][1]*dbu)
- dpoints = o.points
- found_error = True
- flag_waveguide_error(dpoints, text, o, topcell)
-
- # find the minimum segment to make sure that the bends have large enough radius
- if (o.wg_type == 1):
- # first segment:
- segment = distance_xy ( o.points[0], o.points[1] )
- if segment < o.radius:
- text = " *** Layout warning. Not enough space (%s) to accommodate the desired bend radius (%s) for waveguide end." % (segment, o.radius)
- dpoints=[ o.points[0], o.points[1] ]
- found_error = True
- flag_waveguide_error(dpoints, text, o, topcell)
- # last segment:
- segment = distance_xy ( o.points[len(o.points)-2], o.points[len(o.points)-1] )
- if segment < o.radius:
- text = " *** Layout warning. Not enough space (%s) to accommodate the desired bend radius (%s) for waveguide end." % (segment, o.radius)
- dpoints=[ o.points[len(o.points)-2], o.points[len(o.points)-1] ]
- flag_waveguide_error(dpoints, text, o, topcell)
- found_error = True
- # go through each of the middle segments:
- for j in range(1, len(o.points)-2):
- segment = distance_xy ( o.points[j], o.points[j+1] )
- if segment < 2*o.radius and segment != 0:
- text = " *** Layout warning. Not enough space (%s) to accommodate the desired bend radius (%s) for a mid-segment." % (segment, o.radius)
- dpoints=[ o.points[j], o.points[j+1] ]
- flag_waveguide_error(dpoints, text, o, topcell)
- found_error = True
-
- # Check for waveguides with too few bend points
- recommended_points = points_per_circle(o.radius)
- if o.bend_pts < 0.75 * recommended_points:
- text = " *** Layout warning. Waveguide bends should have at least %s points per circle for a %s micron radius." \
- % (int(recommended_points), o.radius)
- dpoints=o.points
- found_error = True
- flag_waveguide_error(dpoints, text, o, topcell)
-
-
-
-
-
-def check_components(cell, LayerDevRecN):
- # function to go through all the cells
- # check that the cell has at most ONE DevRec shape.
- return False
-
-
-def flag_component_error(box, text, x, y):
- # global variable "layout_errors" of class "Layout_error" used for storing all the errors.
- topcell.shapes(LayerErrorN).insert(box)
- layout_errors.append(Layout_error(text, x, y) )
- print text
- wtext.insertHtml('%s<br>' %text)
-
-
-def check_connectivity(optical_components, topcell, LayerErrorN):
- # Make sure that all pins/waveguides are connected, i.e., dangling pins/waveguides.
- # Flag disconnected pins
- # Flag disconnected waveguides
- # Make sure that waveguides / pins are connected in the correct direction
-
- for k in range(0,len(optical_components)):
- if optical_components[k].npins != len(optical_components[k].nets):
- text = " *** Connectivity error. Mismatch between the number of pins (%s) on the component (%s, %s) at (%s, %s), and the number of nets (%s)." \
- % ( optical_components[k].npins, optical_components[k].component, optical_components[k].index, \
- optical_components[k].x, optical_components[k].y, len(optical_components[k].nets) )
- bbox = layout.cell(optical_components[k].instance).bbox()
- box = bbox.transformed(pya.Trans(optical_components[k].rotate, optical_components[k].flip, \
- optical_components[k].x/dbu,optical_components[k].y/dbu))
-# flag_component_error(box, text, optical_components[k].x, optical_components[k].y)
-
- # go through all the pins in the component, and check if they aren't assigned to a net
- for m in range(0,optical_components[k].npins):
- pin = optical_pins[optical_components[k].pins[m]]
- if pin.net == 0 and pin.pin_type == 1: # disconnected pin on a pin_type = 1 (component)
- text = " *** Found disconnected pin #%s at (%s, %s)." % (pin.index, pin.x*dbu, pin.y*dbu)
- box = pya.Box(pin.x-3000, pin.y-3000, pin.x+3000, pin.y+3000)
-# flag_component_error(box, text, pin.x*dbu, pin.y*dbu)
-
- for pin in optical_pins:
- if pin.net == -1 and pin.pin_type != 2: # disconnected pin not on a pin_type = 2 (optical IO)
- text = " *** Found disconnected pin #%s, type %s, at (%s, %s), component #%s {%s}" \
- % (pin.index, pin.pin_type, pin.x*dbu, pin.y*dbu, \
- pin.component_n, optical_components[pin.component_n].component)
- box = pya.Box(pin.x-3000, pin.y-3000, pin.x+3000, pin.y+3000)
- flag_component_error(box, text, pin.x*dbu, pin.y*dbu)
-
- for w1 in optical_waveguides:
- # examine the beginning of the waveguide:
- if w1.net1 == -1:
- text = " *** Found disconnected waveguide at (%s, %s), net1" \
- % (w1.points[0][0]*dbu, w1.points[0][1]*dbu)
- flag_waveguide_error( [w1.points[0], w1.points[1]], text, optical_waveguides[w1.index], topcell)
- # examine the end of the waveguide:
- if w1.net2 == -1:
- text = " *** Found disconnected waveguide at (%s, %s), net2" \
- % (w1.points[len(w1.points)-1][0]*dbu, w1.points[len(w1.points)-1][1]*dbu)
- flag_waveguide_error([w1.points[len(w1.points)-1], w1.points[len(w1.points)-2]], \
- text, optical_waveguides[w1.index], topcell)
-
- # Make sure that waveguides / pins are connected in the correct direction (colinear check)
-
-
-
-def list_optical_components(optical_components):
- # list all Optical_component objects from an array
- # input array, optical_components
- # example output:
- # X_grating_coupler_1 N$7 N$6 grating_coupler library="custom/genericcml" sch_x=-1.42 sch_y=-0.265 sch_r=0 sch_f=false
-
- for o in optical_components:
- nets_str = ""
- for n in o.nets:
- nets_str += " N$" + str(n)
- flip = ' sch_f=true' if o.flip else ''
- if o.rotate > 0:
- rotate = ' sch_r=%s' % str(o.rotate)
- else:
- rotate = ''
-# t = '%s %s %s library="%s" lay_x=%s lay_y=%s sch_x=%s sch_y=%s %s%s' % \
-# ( "X"+o.component+"_"+str(o.index), nets_str, o.component, o.library, str (o.x * 1e-6), o.y * 1e-6, o.x, o.y, rotate, flip)
- t = ' %s %s %s library="%s" sch_x=%s sch_y=%s %s%s' % \
- ( "X"+o.component+"_"+str(o.index), nets_str, o.component, o.library, eng_str(o.x * 5e-2), eng_str(o.y * 5e-2), rotate, flip)
- print (t)
- wtext.insertHtml('%s<br>' %t)
-
-def list_optical_waveguides(list_optical_waveguides):
- # list all Optical_waveguides objects from an array
- # input array, optical_waveguides
- # example output:
- # X5 9 10 ebeam_wg_strip_1550 library="Design kits/ebeam_v1.0" wg_length=7.86299e-06 wg_width=5.085e-07 sch_x=-1.42 sch_y=-0.265
-
- for o in list_optical_waveguides:
- nets_str = "N$%s N$%s" %(o.net1, o.net2)
- x,y = xy_mean_mult(o.points, dbu)
-# t = '%s %s %s library="%s" wg_length=%s wg_width=%s lay_x=%s lay_y=%s sch_x=%5.3f sch_y=%5.3f' % \
-# ( "Xwg" + str(o.index), nets_str, o.component, o.library, eng_str(o.length*1e-6), eng_str(o.wg_width*1e-6), \
-# eng_str(x * 1e-6), eng_str(y * 1e-6), x, y)
- t = ' %s %s %s library="%s" wg_length=%s wg_width=%s sch_x=%s sch_y=%s' % \
- ( "Xwg" + str(o.index), nets_str, o.component, o.library, \
- eng_str(o.length*1e-6), eng_str(o.wg_width*1e-6), eng_str(x * 5e-2), eng_str(y * 5e-2))
- print (t)
- wtext.insertHtml('%s<br>' %t)
-
-
-def gen_ui():
- global wdg
-
- # If the window is already here, destroy it and start over again.
- if 'wdg' in globals():
- if wdg is not None and not wdg.destroyed():
- wdg.destroy()
- global wtext
-
- def button_clicked(checked):
- """ Event handler: "OK" button clicked """
- wdg.destroy()
-
- wdg = pya.QDialog(pya.Application.instance().main_window())
-
- wdg.setAttribute(pya.Qt.WA_DeleteOnClose)
- wdg.setWindowTitle("SiEPIC-EBeam-PDK Verification and Netlist Generation")
-
- wdg.resize(1200, 2500)
- wdg.move(1, 1)
-
- grid = pya.QGridLayout(wdg)
-
- windowlabel1 = pya.QLabel(wdg)
- windowlabel1.setText("Verification output:")
- wtext = pya.QTextEdit(wdg)
- wtext.enabled = True
- wtext.setText('')
- wtext.LineWrapMode = pya.QTextEdit.NoWrap
-
- ok = pya.QPushButton("OK", wdg)
- ok.clicked(button_clicked) # attach the event handler
- netlist = pya.QPushButton("Netlist Export", wdg) # not implemented
-
- grid.addWidget(windowlabel1, 0, 0, 1, 3)
- grid.addWidget(wtext, 1, 1, 3, 3)
- grid.addWidget(netlist, 4, 2)
- grid.addWidget(ok, 4, 3)
-
- grid.setRowStretch(3, 1)
- grid.setColumnStretch(1, 1)
-
- wdg.show()
-
-
+"""
# ************************************************************************
# ************************************************************************
@@ -296,16 +73,6 @@ def gen_ui():
# ************************************************************************
# ************************************************************************
-#from time import strftime, clock
-import time
-
-# Create a GUI for the output:
-gen_ui()
-print(wdg)
-wtext.insertHtml('Running SiEPIC-EBeam-PDK Verification and Netlist Generation.<br>')
-wtext.insertHtml('* KLayout SiEPIC_EBeam_PDK v%s, %s.<br>' % (SiEPIC_Version, time.strftime("%Y-%m-%d %H:%M:%S") ) )
-clock_start = time.clock()
-
# Configure variables to draw structures in the presently selected cell:
lv = pya.Application.instance().main_window().current_view()
@@ -315,6 +82,7 @@ if lv == None:
layout = pya.Application.instance().main_window().current_view().active_cellview().layout()
if layout == None:
raise Exception("No layout")
+cv = pya.Application.instance().main_window().current_view().active_cellview()
# find the currently selected cell:
topcell = pya.Application.instance().main_window().current_view().active_cellview().cell
if topcell == None:
@@ -322,7 +90,6 @@ if topcell == None:
# fetch the database parameters
dbu = layout.dbu
-
# Define layers based on PDK_functions:
LayerSiN = layout.layer(LayerSi)
LayerTextN = layout.layer(LayerText)
@@ -332,8 +99,6 @@ LayerFbrTgtN = layout.layer(LayerFbrTgt)
LayerErrorN = layout.layer(LayerError)
LayerINTERCONNECTN = layout.layer(LayerINTERCONNECT)
-# Clear the previous errors:
-clear_ErrorLayer(topcell, LayerErrorN)
# initialize the arrays to keep track of layout objects
reset_Optical_classes()
@@ -342,91 +107,49 @@ optical_waveguides = []
optical_pins = []
optical_nets = []
+# Create a Results Database
+rdb_i = lv.create_rdb("SiEPIC_Verification")
+rdb = lv.rdb(rdb_i)
+rdb.top_cell_name = topcell.name
+rdb_cell = rdb.create_cell(topcell.name)
-# Search the layout for the components and waveguides:
-print ("")
-print ("* calling find_all_components() – DevRec:")
-find_all_components(topcell, LayerDevRecN, LayerPinRecN, LayerFbrTgtN)
-clock_find_all_components = time.clock()
-print ("")
-print ("* calling find_all_waveguides():")
-find_all_waveguides(topcell, LayerSiN)
-clock_find_all_waveguides = time.clock()
-print ("")
-print ("* print_Optical_all, after find_all_{components, waveguides}:")
-print_Optical_all(optical_components, optical_waveguides, optical_pins, optical_nets)
+if 'wtext' in globals():
+ # don't use the text window for output.
+ del(wtext)
+# Search the layout for the components and waveguides:
# Search the arrays to identify all the nets:
-print ("")
-print ("* calling identify_all_nets():")
-clock_identify_all_nets0 = time.clock()
-identify_all_nets(optical_pins, optical_waveguides, optical_components)
-clock_identify_all_nets = time.clock()
-print ("")
-print ("print_Optical_all, after identify_all_nets:")
-print_Optical_all(optical_components, optical_waveguides, optical_pins, optical_nets)
-clock_identify_layout = time.clock()
+optical_waveguides, optical_components = netlist_extraction(topcell)[:2]
+# ********* Verification *********
# Check the layout for errors, using the above arrays:
print ("")
print ("Checking layout for errors: ")
-wtext.insertHtml('<br>* Checking layout for errors:<br><br>')
layout_errors=[]
# Check components - overlapping
-check_components(topcell, LayerDevRecN)
-clock_check_components = time.clock()
+number_errors = check_components(rdb, topcell, LayerDevRecN)
# Check waveguides for waveguide-specific problems:
-check_waveguides(optical_waveguides, topcell, LayerErrorN)
-clock_check_waveguides = time.clock()
+number_errors += check_waveguides(rdb, optical_waveguides, topcell, LayerErrorN)
# Check connectivity between components and waveguides:
-check_connectivity(optical_components, topcell, LayerErrorN)
-clock_check_connectivity = time.clock()
+number_errors += check_connectivity(rdb, optical_components, topcell, LayerErrorN)
lv.add_missing_layers()
print ("*** Number of errors found: %s." % len(layout_errors) )
-wtext.insertHtml('<br>*** Number of errors found: %s.<br>' % len(layout_errors) )
-clock_verify_layout = time.clock()
-
-
-# Output the Spice netlist:
-text_Spice = generate_Spice_file(topcell, optical_waveguides, optical_components)
-wtext.insertPlainText(text_Spice)
-clock_netlist = time.clock()
-
-
-# Find the automated measurement coordinates:
-wtext.insertHtml('<br>* Automated measurement coordinates:<br><br>')
-print ("")
-print ("Automated measurement coordinates: ")
-print ("")
-t = find_automated_measurement_labels(topcell, LayerTextN)
-wtext.insertHtml (t)
-clock_automated_measurements = time.clock()
+print ("*** Number of errors found: %s." % number_errors )
-
-wtext.insertHtml('<br>CPU time for searching layout: find_all_components %s, find_all_waveguides %s<br>' \
-% (clock_find_all_components-clock_start, clock_find_all_waveguides-clock_find_all_components) )
-
-wtext.insertHtml('<br>CPU time for identify_all_nets %s<br>' \
-% (clock_identify_all_nets-clock_identify_all_nets0) )
-
-wtext.insertHtml('<br>CPU time for verification: check_components %s, check_waveguides %s, check_connectivity %s<br>' \
-% (clock_check_components-clock_identify_all_nets, clock_check_waveguides-clock_check_components, clock_check_connectivity-clock_check_waveguides) )
-
-wtext.insertHtml('<br>CPU time for Spice netlist %s, automated measurements %s<br>' \
-% (clock_netlist-clock_verify_layout, clock_automated_measurements-clock_netlist) )
-
-wtext.insertHtml('<br>total CPU time: %s. <br>' % (time.clock() - clock_start) )
-
-
-# Done
-wtext.insertHtml('<br>Done.<br>')
+
print ("")
print ("Done. ")
print ("")
+#displays results in Marker Database Browser, using Results Database (rdb)
+if number_errors>0:
+ v = pya.MessageBox.warning("Errors", "%s layout errors detected. \nPlease review errors using the 'Marker Database Browser'." % number_errors, pya.MessageBox.Ok)
+ lv.show_rdb(rdb_i, cv.cell_index)
+else:
+ v = pya.MessageBox.warning("Errors", "No layout errors detected.", pya.MessageBox.Ok)
diff --git a/klayout_dot_config/pymacros/SiEPIC_EBeam_Verification_text.lym b/klayout_dot_config/pymacros/SiEPIC_EBeam_Verification_text.lym
new file mode 100644
index 00000000..3832264d
--- /dev/null
+++ b/klayout_dot_config/pymacros/SiEPIC_EBeam_Verification_text.lym
@@ -0,0 +1,258 @@
+
+
+ SiEPIC: Verification and Netlist generation
+
+ pymacros
+
+
+
+ false
+ false
+
+ true
+
+
+ python
+
+ # Python script
+# SiEPIC_EBeam_Verification
+
+"""
+This file is part of the SiEPIC_EBeam_PDK
+by Lukas Chrostowski (c) 2015
+
+This Python file implements layout verification and netlist extraction
+displays results in a text window
+
+
+Version history:
+
+Lukas Chrostowski 2015/11/11
+ - Optical_net class
+ - find all LayerSi paths and waveguides, and save optical net vertices
+ - find all PinRec paths
+ - find all DevRec polygons and boxes
+ - check_waveguides
+ - waveguide bend minimum
+ - paths with corners (more than 2 points)
+ - bend radius less than specified
+ - error marker layer and class; clear errors
+
+Lukas Chrostowski 2015/11/12
+ - determining where pins/waveguides overlap to generate a netlist
+ - initial Spice output for components including waveguides and nets.
+ - check nets & components
+ - incorrect number of nets connected to a component (disconnected, or too many)
+
+Lukas Chrostowski 2015/11/15
+ - fix for Python 3.4: print ("xxx")
+ - moved some functions from here, to the common "SiEPIC_EBeam_functions file, so they are accessible elsewhere.
+ - added pin# text label on PinRec layer; sort pins in Spice output using these names.
+
+Lukas Chrostowski 2015/11/16
+ - fixes for component pin_type = Optical IO / FbrTgt being incorrectly handled; added Optical_pin.pin_type
+
+Lukas Chrostowski 2015/11/17
+ - debugging & fixing Verification problems
+
+Lukas Chrostowski 2015/11/18
+ - removed need for numpy.array
+
+Lukas Chrostowski 2015/11/19
+ - moved some functions to SiEPIC_EBeam_functions
+
+Lukas Chrostowski 2015/11/21
+ - adding Results Database (rdb) and Marker Database Browser, for error viewing
+
+
+
+"""
+
+
+def gen_ui():
+ global wdg
+
+ # If the window is already here, destroy it and start over again.
+ if 'wdg' in globals():
+ if wdg is not None and not wdg.destroyed():
+ wdg.destroy()
+ global wtext
+
+ def button_clicked(checked):
+ """ Event handler: "OK" button clicked """
+ wdg.destroy()
+
+ wdg = pya.QDialog(pya.Application.instance().main_window())
+
+ wdg.setAttribute(pya.Qt.WA_DeleteOnClose)
+ wdg.setWindowTitle("SiEPIC-EBeam-PDK Verification and Netlist Generation")
+
+ wdg.resize(1200, 2500)
+ wdg.move(1, 1)
+
+ grid = pya.QGridLayout(wdg)
+
+ windowlabel1 = pya.QLabel(wdg)
+ windowlabel1.setText("Verification output:")
+ wtext = pya.QTextEdit(wdg)
+ wtext.enabled = True
+ wtext.setText('')
+ wtext.LineWrapMode = pya.QTextEdit.NoWrap
+
+ ok = pya.QPushButton("OK", wdg)
+ ok.clicked(button_clicked) # attach the event handler
+ netlist = pya.QPushButton("Netlist Export", wdg) # not implemented
+
+ grid.addWidget(windowlabel1, 0, 0, 1, 3)
+ grid.addWidget(wtext, 1, 1, 3, 3)
+ grid.addWidget(netlist, 4, 2)
+ grid.addWidget(ok, 4, 3)
+
+ grid.setRowStretch(3, 1)
+ grid.setColumnStretch(1, 1)
+
+ wdg.show()
+
+
+
+# ************************************************************************
+# ************************************************************************
+# Main script:
+# ************************************************************************
+# ************************************************************************
+
+#from time import strftime, clock
+import time
+
+# Create a GUI for the output:
+gen_ui()
+
+if 'wtext' in globals():
+ wtext.insertHtml('Running SiEPIC-EBeam-PDK Verification and Netlist Generation.<br>')
+ wtext.insertHtml('* KLayout SiEPIC_EBeam_PDK v%s, %s.<br>' % (SiEPIC_Version, time.strftime("%Y-%m-%d %H:%M:%S") ) )
+clock_start = time.clock()
+
+
+# Configure variables to draw structures in the presently selected cell:
+lv = pya.Application.instance().main_window().current_view()
+if lv == None:
+ raise Exception("No view selected")
+# Find the currently selected layout.
+layout = pya.Application.instance().main_window().current_view().active_cellview().layout()
+if layout == None:
+ raise Exception("No layout")
+cv = pya.Application.instance().main_window().current_view().active_cellview()
+# find the currently selected cell:
+topcell = pya.Application.instance().main_window().current_view().active_cellview().cell
+if topcell == None:
+ raise Exception("No cell")
+# fetch the database parameters
+dbu = layout.dbu
+
+
+# Define layers based on PDK_functions:
+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)
+
+# Clear the previous errors:
+clear_ErrorLayer(topcell, LayerErrorN)
+
+# initialize the arrays to keep track of layout objects
+reset_Optical_classes()
+optical_components = []
+optical_waveguides = []
+optical_pins = []
+optical_nets = []
+
+# Create a Results Database
+rdb_i = lv.create_rdb("SiEPIC_Verification")
+rdb = lv.rdb(rdb_i)
+rdb.top_cell_name = topcell.name
+rdb_cell = rdb.create_cell(topcell.name)
+
+
+# Search the layout for the components and waveguides:
+# Search the arrays to identify all the nets:
+optical_waveguides, optical_components, clock_find_all_components, clock_find_all_waveguides, clock_identify_all_nets \
+ = netlist_extraction(topcell)
+
+clock_identify_layout = time.clock()
+
+
+# ********* Verification *********
+# Check the layout for errors, using the above arrays:
+print ("")
+print ("Checking layout for errors: ")
+if 'wtext' in globals():
+ wtext.insertHtml('<br>* Checking layout for errors:<br><br>')
+layout_errors=[]
+# Check components - overlapping
+check_components(rdb, topcell, LayerDevRecN)
+clock_check_components = time.clock()
+# Check waveguides for waveguide-specific problems:
+check_waveguides(rdb, optical_waveguides, topcell, LayerErrorN)
+clock_check_waveguides = time.clock()
+# Check connectivity between components and waveguides:
+check_connectivity(rdb, optical_components, topcell, LayerErrorN)
+clock_check_connectivity = time.clock()
+lv.add_missing_layers()
+print ("*** Number of errors found: %s." % len(layout_errors) )
+if 'wtext' in globals():
+ wtext.insertHtml('<br>*** Number of errors found: %s.<br>' % len(layout_errors) )
+clock_verify_layout = time.clock()
+
+
+# Output the Spice netlist:
+text_Spice = generate_Spice_file(topcell, optical_waveguides, optical_components)
+if 'wtext' in globals():
+ wtext.insertPlainText(text_Spice)
+clock_netlist = time.clock()
+
+
+# Find the automated measurement coordinates:
+if 'wtext' in globals():
+ wtext.insertHtml('<br>* Automated measurement coordinates:<br><br>')
+print ("")
+print ("Automated measurement coordinates: ")
+print ("")
+t = find_automated_measurement_labels(topcell, LayerTextN)
+if 'wtext' in globals():
+ wtext.insertHtml (t)
+clock_automated_measurements = time.clock()
+
+if 'wtext' in globals():
+
+ wtext.insertHtml('<br>CPU time for searching layout: find_all_components %s, find_all_waveguides %s<br>' \
+ % (clock_find_all_components-clock_start, clock_find_all_waveguides-clock_find_all_components) )
+
+ wtext.insertHtml('<br>CPU time for identify_all_nets %s<br>' \
+ % (clock_identify_all_nets-clock_find_all_components) )
+
+ wtext.insertHtml('<br>CPU time for verification: check_components %s, check_waveguides %s, check_connectivity %s<br>' \
+ % (clock_check_components-clock_identify_all_nets, clock_check_waveguides-clock_check_components, clock_check_connectivity-clock_check_waveguides) )
+
+ wtext.insertHtml('<br>CPU time for Spice netlist %s, automated measurements %s<br>' \
+ % (clock_netlist-clock_verify_layout, clock_automated_measurements-clock_netlist) )
+
+ wtext.insertHtml('<br>total CPU time: %s. <br>' % (time.clock() - clock_start) )
+
+
+# Done
+if 'wtext' in globals():
+ wtext.insertHtml('<br>Done.<br>')
+
+print ("")
+print ("Done. ")
+print ("")
+
+
+#lv.show_rdb(rdb_i, cv.cell_index)
+
+
+
+
diff --git a/klayout_dot_config/pymacros/SiEPIC_EBeam_Waveguide_to_Path.lym b/klayout_dot_config/pymacros/SiEPIC_EBeam_Waveguide_to_Path.lym
index 1120d630..6bf781ef 100644
--- a/klayout_dot_config/pymacros/SiEPIC_EBeam_Waveguide_to_Path.lym
+++ b/klayout_dot_config/pymacros/SiEPIC_EBeam_Waveguide_to_Path.lym
@@ -102,7 +102,7 @@ for o in object_selection:
elif o.shape:
print ("Selected object is a shape.")
c = o.shape.cell
- if c.name == "ROUND_PATH" and c.is_pcell_variant() and c.pcell_parameters_by_name()['layer'] == LayerSi:
+ if c.basic_name() == "ROUND_PATH" and c.is_pcell_variant() and c.pcell_parameters_by_name()['layer'] == LayerSi:
# we have a waveguide GUIDING_LAYER selected
print ("Selected object is a GUIDING_LAYER in ROUND_PATH on LayerSi.")
trans = o.source_trans().s_trans()
diff --git a/klayout_dot_config/pymacros/SiEPIC_EBeam_functions.lym b/klayout_dot_config/pymacros/SiEPIC_EBeam_functions.lym
index a2320047..2bb8d00d 100644
--- a/klayout_dot_config/pymacros/SiEPIC_EBeam_functions.lym
+++ b/klayout_dot_config/pymacros/SiEPIC_EBeam_functions.lym
@@ -65,6 +65,10 @@ Lukas Chrostowski 2015/11/19
- finding the laser and detectors in the layout
- generating a Spice netlist including Optical Network Analyzer; ready for Lumerical INTERCONNECT
- Added Python 2 & 3 compatibility for iter.next() vs. next(iter)
+
+Lukas Chrostowski 2015/11/21
+ - bug fix in points_mult, that argument in the function was being modified. needed to copy it.
+
"""
@@ -72,6 +76,14 @@ SiEPIC_Version = '0.1.6'
import pya
import math
+import string
+
+try:
+ import numpy
+except ImportError:
+ #import numpy
+ print ("no numpy")
+ MODULE_NUMPY = False
# SiEPIC-EBeam-PDK Layers:
@@ -85,8 +97,6 @@ LayerINTERCONNECT = pya.LayerInfo(733,0)
-#import numpy
-MODULE_NUMPY = False
# Determine whether we have Python 2 or Python 3
import sys
@@ -216,14 +226,17 @@ def reset_Optical_classes():
Layout_error.n = 0
# multiply an array of points by a constant
-def points_mult(dpoints, mult):
+def points_mult(dpoints1, mult):
+ # create a new empty list. Otherwise, this function would modify the original list
+ # http://stackoverflow.com/questions/240178/python-list-of-lists-changes-reflected-across-sublists-unexpectedly
+ newlist = [[0]*2 for n in range(len(dpoints1))]
if MODULE_NUMPY:
- return numpy.array(dpoints)*mult
+ return numpy.array(dpoints1)*mult
else:
for i in range(0,2):
- for j in range(0,len(points)):
- dpoints[j][i] *= mult
- return dpoints
+ for j in range(0,len(dpoints1)):
+ newlist[j][i] = dpoints1[j][i]*mult
+ return newlist
# calculate the mean in (x,y) for an array of points
def xy_mean_mult(dpoints,dbu):
@@ -355,8 +368,6 @@ def find_all_components(cell, LayerDevRecN, LayerPinRecN, LayerFbrTgtN):
path= iter2.shape().path.transformed(iter2.itrans())
path= path.transformed(iter1.itrans())
points = path_to_points(path)
- x = points[0][0]
- y = points[0][1]
#print ( "%s: PinRec in cell {%s}, path -- %s" % (i, iter2.cell().name, path) )
path_points.append(points)
path_shape.append(iter2.shape())
@@ -373,8 +384,8 @@ def find_all_components(cell, LayerDevRecN, LayerPinRecN, LayerFbrTgtN):
pya.Point( pin_info2[p1].pin_x, pin_info2[p1].pin_y ) )
if check_text_in_pin:
points = path_points[p2]
- x = points[0][0]
- y = points[0][1]
+ x = (points[0][0]+points[1][0])/2 # midpoint of pin path
+ y = (points[0][1]+points[1][1])/2
pin_index = len(optical_pins)
optical_pins.append (Optical_pin (pin_index, points, component_index, x, y, 1) )
optical_components[component_index].npins += 1
@@ -469,8 +480,8 @@ def points_to_Dpath(points, w):
a1 = []
for p in points:
a1.append (pya.DPoint(p[0], p[1]))
- wg_path = pya.DPath(a1, w)
- return wg_path
+ wg_path1 = pya.DPath(a1, w)
+ return wg_path1
def points_to_path(points, w):
@@ -482,7 +493,7 @@ def points_to_path(points, w):
def polygon_to_points(polygon):
- # for some reason, you assign points to a polygon, but not read them!
+ # for some reason, you can assign points to a polygon, but not read them!
# http://www.klayout.de/doc/code/class_SimplePolygon.html
# This function reads the points one by one and returns an array of points
npts = polygon.to_simple_polygon().points
@@ -959,7 +970,7 @@ def generate_Spice_file(topcell, optical_waveguides, optical_components):
# main circuit
text += '%s%s %s sch_x=-1 sch_y=-1\n\n' % (topcell.name, opticalIO_pins, topcell.name)
- return text
+ return text, len(detector_nets)
def eng_str(x):
@@ -989,8 +1000,264 @@ def eng_str(x):
#return sign+str(z)+'E'+str(engr_exponent)
# return sign+ '%3.3f' % z +str(str_engr_exponent)
return sign+ str(z) +str(str_engr_exponent)
+
+
+def netlist_extraction(topcell):
+ # Collection of functions to extract the circuit netlist from the physical layout
+
+ import time
+
+ # Search the layout for the components and waveguides:
+ print ("")
+ print ("* calling find_all_components() – DevRec:")
+ find_all_components(topcell, LayerDevRecN, LayerPinRecN, LayerFbrTgtN)
+ clock_find_all_components = time.clock()
+
+ print ("")
+ print ("* calling find_all_waveguides():")
+ find_all_waveguides(topcell, LayerSiN)
+ clock_find_all_waveguides = time.clock()
+
+# print ("")
+# print ("* print_Optical_all, after find_all_{components, waveguides}:")
+# print_Optical_all(optical_components, optical_waveguides, optical_pins, optical_nets)
+
+ # Search the arrays to identify all the nets:
+ print ("")
+ print ("* calling identify_all_nets():")
+ identify_all_nets(optical_pins, optical_waveguides, optical_components)
+ clock_identify_all_nets = time.clock()
+
+ print ("")
+ print ("print_Optical_all, after identify_all_nets:")
+ print_Optical_all(optical_components, optical_waveguides, optical_pins, optical_nets)
+
+ return optical_waveguides, optical_components, \
+ clock_find_all_components, clock_find_all_waveguides, clock_identify_all_nets
+
+
+
+def flag_waveguide_error(dpoints, text, optical_waveguide, topcell):
+ # global variable "layout_errors" of class "Layout_error" used for storing all the errors.
+ a1 = []
+ for p in dpoints:
+ a1.append (pya.Point(int(p[0]), int(p[1])))
+ path = pya.Path(a1, optical_waveguide.wg_width*4/dbu)
+ x,y = xy_mean_mult(dpoints, dbu)
+ layout_errors.append(Layout_error(text, x, y) )
+ print (text)
+ if 'wtext' in globals():
+ topcell.shapes(LayerErrorN).insert(path)
+ wtext.insertHtml('%s<br>' %text)
+
+
+def check_waveguides(rdb, optical_waveguides, topcell, error_layer):
+ # check waveguides for basic errors.
+ num_errors=0
+
+ rdb_cell = next(rdb.each_cell())
+
+ rdb_cat_id_wg = rdb.create_category("Waveguide errors")
+
+ rdb_cat_id_wg_path = rdb.create_category(rdb_cat_id_wg, "Path")
+ rdb_cat_id_wg_path.description = "Waveguide path: Only 2 points allowed in a path. Convert to a waveguide (ROUND_PATH) if necessary."
+
+ rdb_cat_id_wg_radius = rdb.create_category(rdb_cat_id_wg, "Radius")
+ rdb_cat_id_wg_radius.description = "Not enough space to accommodate the desired bend radius for the waveguide end."
+
+ rdb_cat_id_wg_bendpts = rdb.create_category(rdb_cat_id_wg, "Bend points")
+ rdb_cat_id_wg_bendpts.description = "Waveguide bend should have more points per circle."
+
+
+ for o in optical_waveguides:
+
+ # Check for paths with > 2 vertices
+ if (o.wg_type == 0 and o.num_points > 2):
+ text = " *** Layout error. Waveguide path (%s, %s): Only 2 points allowed in a path. Convert to a waveguide (ROUND_PATH) if necessary. " \
+ % ( o.points[0][0]*dbu, o.points[0][1]*dbu)
+ dpoints = o.points
+ num_errors += 1
+ flag_waveguide_error(dpoints, text, o, topcell)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_wg_path.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( points_to_Dpath(points_mult(dpoints, dbu),o.wg_width) ) )
+
+ # find the minimum segment to make sure that the bends have large enough radius
+ if (o.wg_type == 1):
+ # first segment:
+ segment = distance_xy ( o.points[0], o.points[1] )
+ if segment < o.radius:
+ text = " *** Layout warning. Not enough space (%s) to accommodate the desired bend radius (%s) for waveguide end." % (segment, o.radius)
+ dpoints=[ o.points[0], o.points[1] ]
+ num_errors += 1
+ flag_waveguide_error(dpoints, text, o, topcell)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_wg_radius.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( points_to_Dpath(points_mult(dpoints, dbu),o.wg_width) ) )
+ # last segment:
+ segment = distance_xy ( o.points[len(o.points)-2], o.points[len(o.points)-1] )
+ if segment < o.radius:
+ text = " *** Layout warning. Not enough space (%s) to accommodate the desired bend radius (%s) for waveguide end." % (segment, o.radius)
+ dpoints=[ o.points[len(o.points)-2], o.points[len(o.points)-1] ]
+ num_errors += 1
+ flag_waveguide_error(dpoints, text, o, topcell)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_wg_radius.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( points_to_Dpath(points_mult(dpoints, dbu),o.wg_width) ) )
+ # go through each of the middle segments:
+ for j in range(1, len(o.points)-2):
+ segment = distance_xy ( o.points[j], o.points[j+1] )
+ if segment < 2*o.radius and segment != 0:
+ text = " *** Layout warning. Not enough space (%s) to accommodate the desired bend radius (%s) for a mid-segment." % (segment, o.radius)
+ dpoints=[ o.points[j], o.points[j+1] ]
+ num_errors += 1
+ flag_waveguide_error(dpoints, text, o, topcell)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_wg_radius.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( points_to_Dpath(points_mult(dpoints, dbu),o.wg_width) ) )
+
+ # Check for waveguides with too few bend points
+ recommended_points = points_per_circle(o.radius)
+ if o.bend_pts < 0.75 * recommended_points:
+ text = " *** Layout warning. Waveguide bends should have at least %s points per circle for a %s micron radius." \
+ % (int(recommended_points), o.radius)
+ dpoints=o.points
+ num_errors += 1
+ flag_waveguide_error(dpoints, text, o, topcell)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_wg_bendpts.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( points_to_Dpath(points_mult(dpoints, dbu),o.wg_width) ) )
+
+ return num_errors
+
+
+def check_components(rdb, cell, LayerDevRecN):
+ # function to go through all the cells
+ # check that the cell has at most ONE DevRec shape.
+ return False
+
+
+
+def flag_component_error(box, text, x, y):
+ # global variable "layout_errors" of class "Layout_error" used for storing all the errors.
+ layout_errors.append(Layout_error(text, x, y) )
+ print text
+ if 'wtext' in globals():
+ topcell.shapes(LayerErrorN).insert(box)
+ wtext.insertHtml('%s<br>' %text)
+
+
+def check_connectivity(rdb, optical_components, topcell, LayerErrorN):
+ # Make sure that all pins/waveguides are connected, i.e., dangling pins/waveguides.
+ # Flag disconnected pins
+ # Flag disconnected waveguides
+ # Make sure that waveguides / pins are connected in the correct direction (identify_nets only finds colinear pins/waveguides)
+
+ num_errors=0
+
+ rdb_cell = next(rdb.each_cell())
+
+ rdb_cat_id = rdb.create_category("Connectivity errors")
+
+ rdb_cat_id_discwg = rdb.create_category(rdb_cat_id, "Disconnected waveguide")
+ rdb_cat_id_discwg.description = "Disconnected waveguides"
+
+ rdb_cat_id_discpin = rdb.create_category(rdb_cat_id, "Disconnected pin")
+ rdb_cat_id_discpin.description = "Disconnected pin"
+
+ if 0:
+ for k in range(0,len(optical_components)):
+ if optical_components[k].npins != len(optical_components[k].nets):
+ text = " *** Connectivity error. Mismatch between the number of pins (%s) on the component (%s, %s) at (%s, %s), and the number of nets (%s)." \
+ % ( optical_components[k].npins, optical_components[k].component, optical_components[k].index, \
+ optical_components[k].x, optical_components[k].y, len(optical_components[k].nets) )
+ bbox = layout.cell(optical_components[k].instance).bbox()
+ box = bbox.transformed(pya.Trans(optical_components[k].rotate, optical_components[k].flip, \
+ optical_components[k].x/dbu,optical_components[k].y/dbu))
+# flag_component_error(box, text, optical_components[k].x, optical_components[k].y)
+
+ # go through all the pins in the component, and check if they aren't assigned to a net
+ for m in range(0,optical_components[k].npins):
+ pin = optical_pins[optical_components[k].pins[m]]
+ if pin.net == 0 and pin.pin_type == 1: # disconnected pin on a pin_type = 1 (component)
+ text = " *** Found disconnected pin #%s at (%s, %s)." % (pin.index, pin.x*dbu, pin.y*dbu)
+ box = pya.Box(pin.x-3000, pin.y-3000, pin.x+3000, pin.y+3000)
+# flag_component_error(box, text, pin.x*dbu, pin.y*dbu)
+
+ for pin in optical_pins:
+ if pin.net == -1 and pin.pin_type != 2: # disconnected pin not on a pin_type = 2 (optical IO)
+ text = " *** Found disconnected pin #%s, type %s, at (%s, %s), component #%s {%s}" \
+ % (pin.index, pin.pin_type, pin.x*dbu, pin.y*dbu, \
+ pin.component_n, optical_components[pin.component_n].component)
+ box = pya.Box(pin.x-3000, pin.y-3000, pin.x+3000, pin.y+3000)
+ num_errors += 1
+ flag_component_error(box, text, pin.x*dbu, pin.y*dbu)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_discpin.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( pya.DBox(pin.x*dbu-0.3, pin.y*dbu-0.3, pin.x*dbu+0.3, pin.y*dbu+0.3) ) )
+
+ for w1 in optical_waveguides:
+ print (w1.points)
+ # examine the beginning of the waveguide:
+ if w1.net1 == -1:
+ text = " *** Found disconnected waveguide at (%s, %s), net1" \
+ % (w1.points[0][0]*dbu, w1.points[0][1]*dbu)
+ dpoints = [w1.points[0], w1.points[1]]
+ num_errors += 1
+ flag_waveguide_error( dpoints, text, optical_waveguides[w1.index], topcell)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_discwg.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( points_to_Dpath(points_mult(dpoints, dbu),w1.wg_width) ) )
+ # examine the end of the waveguide:
+ if w1.net2 == -1:
+ text = " *** Found disconnected waveguide at (%s, %s), net2" \
+ % (w1.points[len(w1.points)-1][0]*dbu, w1.points[len(w1.points)-1][1]*dbu)
+ dpoints = [w1.points[len(w1.points)-1], w1.points[len(w1.points)-2]]
+ print (dpoints)
+ num_errors += 1
+ flag_waveguide_error(dpoints, \
+ text, optical_waveguides[w1.index], topcell)
+ rdb_item = rdb.create_item(rdb_cell.rdb_id(),rdb_cat_id_discwg.rdb_id())
+ rdb_item.add_value(pya.RdbItemValue( points_to_Dpath(points_mult(dpoints, dbu),w1.wg_width) ) )
+
+ return num_errors
+
+def list_optical_components(optical_components):
+ # list all Optical_component objects from an array
+ # input array, optical_components
+ # example output:
+ # X_grating_coupler_1 N$7 N$6 grating_coupler library="custom/genericcml" sch_x=-1.42 sch_y=-0.265 sch_r=0 sch_f=false
+
+ for o in optical_components:
+ nets_str = ""
+ for n in o.nets:
+ nets_str += " N$" + str(n)
+ flip = ' sch_f=true' if o.flip else ''
+ if o.rotate > 0:
+ rotate = ' sch_r=%s' % str(o.rotate)
+ else:
+ rotate = ''
+# t = '%s %s %s library="%s" lay_x=%s lay_y=%s sch_x=%s sch_y=%s %s%s' % \
+# ( "X"+o.component+"_"+str(o.index), nets_str, o.component, o.library, str (o.x * 1e-6), o.y * 1e-6, o.x, o.y, rotate, flip)
+ t = ' %s %s %s library="%s" sch_x=%s sch_y=%s %s%s' % \
+ ( "X"+o.component+"_"+str(o.index), nets_str, o.component, o.library, eng_str(o.x * 5e-2), eng_str(o.y * 5e-2), rotate, flip)
+ print (t)
+ wtext.insertHtml('%s<br>' %t)
+
+def list_optical_waveguides(list_optical_waveguides):
+ # list all Optical_waveguides objects from an array
+ # input array, optical_waveguides
+ # example output:
+ # X5 9 10 ebeam_wg_strip_1550 library="Design kits/ebeam_v1.0" wg_length=7.86299e-06 wg_width=5.085e-07 sch_x=-1.42 sch_y=-0.265
+
+ for o in list_optical_waveguides:
+ nets_str = "N$%s N$%s" %(o.net1, o.net2)
+ x,y = xy_mean_mult(o.points, dbu)
+# t = '%s %s %s library="%s" wg_length=%s wg_width=%s lay_x=%s lay_y=%s sch_x=%5.3f sch_y=%5.3f' % \
+# ( "Xwg" + str(o.index), nets_str, o.component, o.library, eng_str(o.length*1e-6), eng_str(o.wg_width*1e-6), \
+# eng_str(x * 1e-6), eng_str(y * 1e-6), x, y)
+ t = ' %s %s %s library="%s" wg_length=%s wg_width=%s sch_x=%s sch_y=%s' % \
+ ( "Xwg" + str(o.index), nets_str, o.component, o.library, \
+ eng_str(o.length*1e-6), eng_str(o.wg_width*1e-6), eng_str(x * 5e-2), eng_str(y * 5e-2))
+ print (t)
+ wtext.insertHtml('%s<br>' %t)
+
+
def waveguide_set_target_length():
# Function to move the edges of a waveguide to obtain a target length
# - Dialog prompts user for a target length, and to click on an edge to select shape and edge to move