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

Extend component #185

Merged
merged 9 commits into from
Mar 22, 2023
70 changes: 67 additions & 3 deletions klayout_dot_config/python/SiEPIC/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ def __init__(self, idx=None, component=None, instance=None, trans=None, library=
self.basic_name = basic_name # component's basic_name (especially for PCells)
self.cellName = cellName # component's Library Cell name
from .utils import get_technology
TECHNOLOGY = get_technology()
self.Dcenter = self.center.to_dtype(TECHNOLOGY['dbu'])
self.TECHNOLOGY = get_technology()
self.Dcenter = self.center.to_dtype(self.TECHNOLOGY['dbu'])

def display(self):
from . import _globals
Expand Down Expand Up @@ -230,12 +230,76 @@ def params_dict(self):
if '[' in string:
q=s.split('=')[1]
else:
string = string.replace('u','e-6').replace('n','e-9')
string = string.replace('u','e-6').replace('n','e-9').replace(';','')
# print (string)
q=float(Decimal(string)*Decimal('1e6')) # in microns
dictb[s.split('=')[0]]=q
return dictb

@staticmethod
def pdic2str(arg: dict): #A Dictionary of SPICE parameters to a string
def _isfloat(arg: str)-> bool:
try:
float(arg)
return True
except ValueError:
return False

str_ = ''
keys = list(arg.keys())
for i in range(0, len(arg)):
value = str(arg[keys[i]])
if _isfloat(value):
value = '%.4f'%(float(value)*1e6)+'u' if float(value)<1e-3 else value
if keys[i].find(' ',0)==-1:
str_ += keys[i] + '=' + value
else:
str_ += '"'+ keys[i] +'"'+ '=' + value
if i < len(arg) - 1: str_ += ' '
return str_

def set_SPICE_params(self, arg, verbose = False):
if isinstance(arg, str):
spice_str = arg.replace('Spice_param:', '', 1)
elif isinstance(arg, dict):
spice_str = self.pdic2str(arg)
else:
return False
newSPICE_text = 'Spice_param:' + spice_str;

cell = self.cell
cell_idx = cell.cell_index()

ly = cell.layout()
LayerDevRecN = ly.layer(self.TECHNOLOGY['DevRec'])
iter_sh = cell.begin_shapes_rec(LayerDevRecN)

while not(iter_sh.at_end()): # Find cell where SPICE params are stored
if iter_sh.shape().is_text():
shape = iter_sh.shape();
text = shape.text
if text.string.find("Spice_param:") > -1:
new_text = pya.Text(newSPICE_text, shape.text_trans,shape.text_size ,-1);
new_text.halign = text.halign
shape.text = new_text
self.params = spice_str
return True
iter_sh.next()

if cell._is_const_object():
cell_inst = cell.layout().cell(cell_idx) # Need to do this to avoid error (See KLayout issue #235)
else:
cell_inst = cell

t = pya.Trans(pya.Trans.R0,pya.Point(0,0)) # Coordinates are with respect to the cell center
new_text = pya.Text(newSPICE_text, t,0.1/ly.dbu ,-1);
cell_inst.shapes(LayerDevRecN).insert(new_text)
self.params = spice_str
return True

def get_SPICE_params(self): #Retturns a SPICE parameter string (without the 'Spice_param:' label)
return (self.params)

def find_pins(self):
return self.cell.find_pins_component(self)

Expand Down
20 changes: 12 additions & 8 deletions klayout_dot_config/python/SiEPIC/extend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1475,11 +1475,11 @@ def spice_netlist_export(self, verbose=False, opt_in_selection_text=[]):
if p.type == _globals.PIN_TYPES.ELECTRICAL:
if idx > 0:
if p.pin_name == c.pins[idx - 1].pin_name: continue # Skip pins that have exactly the same name (assume they are internally connected in the component)
NetName = " " + c.component + '_' + str(c.idx) + '_' + p.pin_name
NetName = " " + c.cell.name + '_' + str(c.idx) + '_' + p.pin_name
electricalIO_pins += NetName
DCsources += "N" + \
str(Vn) + NetName + \
" dcsource amplitude=0 sch_x=%s sch_y=%s\n" % (-2 - Vn / 3., -2 + Vn / 8.)
' "dc source" amplitude=0 sch_x=%s sch_y=%s\n' % (-2 - Vn / 3., -2 + Vn / 8.)
Vn += 1
electricalIO_pins_subckt = electricalIO_pins

Expand All @@ -1491,7 +1491,7 @@ def spice_netlist_export(self, verbose=False, opt_in_selection_text=[]):
if p.type == _globals.PIN_TYPES.ELECTRICAL:
NetName = " N$"
electricalIO_pins_subckt += NetName
DCsources = "N1" + NetName + " dcsource amplitude=0 sch_x=-2 sch_y=0\n"
DCsources = "N1" + NetName + ' "dc source" amplitude=0 sch_x=-2 sch_y=0\n'

# find optical IO pins
opticalIO_pins = ''
Expand Down Expand Up @@ -1533,7 +1533,7 @@ def spice_netlist_export(self, verbose=False, opt_in_selection_text=[]):
if idx > 0:
if p.pin_name == c.pins[idx - 1].pin_name: continue # Skip pins that have exactly the same name (assume they are internally connected in the component)
if p.type == _globals.PIN_TYPES.ELECTRICAL:
nets_str += " " + c.component + '_' + str(c.idx) + '_' + p.pin_name
nets_str += " " + c.cell.name + '_' + str(c.idx) + '_' + p.pin_name
if p.type == _globals.PIN_TYPES.OPTICALIO:
nets_str += " " + str(p.net.idx)
if p.type == _globals.PIN_TYPES.OPTICAL:
Expand All @@ -1542,7 +1542,7 @@ def spice_netlist_export(self, verbose=False, opt_in_selection_text=[]):
# optical nets: must be ordered electrical, optical IO, then optical
for p in c.pins:
if p.type == _globals.PIN_TYPES.ELECTRICAL:
nets_str += " " + c.component + '_' + str(c.idx) + '_' + p.pin_name
nets_str += " " + c.cell.name + '_' + str(c.idx) + '_' + p.pin_name
for p in c.pins:
if p.type == _globals.PIN_TYPES.OPTICALIO:
nets_str += " " + str(p.net.idx)
Expand Down Expand Up @@ -1572,9 +1572,13 @@ def spice_netlist_export(self, verbose=False, opt_in_selection_text=[]):
# Remove "$N" from component's name for cell instance arrays of the same name
if "$" in component1:
component1 = component1[:component1.find("$")]

text_subckt += ' %s %s %s ' % (component1.replace(' ', '_') +
"_" + str(c.idx), nets_str, component1.replace(' ', '_'))

if component1.find(' ')>=0 and component1.find('"')==-1:
text_subckt += ' %s %s "%s" ' % (component1.replace(' ','_') +
"_" + str(c.idx), nets_str, component1)
else:
text_subckt += ' %s %s %s ' % (component1.replace('"', '').replace(' ', '_') +
"_" + str(c.idx), nets_str, component1)
if c.library != None:
text_subckt += 'library="%s" ' % c.library
x, y = c.Dcenter.x, c.Dcenter.y
Expand Down
2 changes: 1 addition & 1 deletion klayout_dot_config/python/SiEPIC/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def get_technology(verbose=False, query_activecellview_technology=False):
# "lv.active_cellview().technology" crashes in KLayout 0.24.10 when loading a GDS file (technology not defined yet?) but works otherwise
if KLAYOUT_VERSION > 24 or query_activecellview_technology or lv.title != '<empty>':
technology_name = lv.active_cellview().technology

return get_technology_by_name(technology_name)


Expand Down
2 changes: 1 addition & 1 deletion klayout_dot_config/python/SiEPIC/utils/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, ra
error_seg2 = True
pt_radius = min(dis1/2, dis2/2, pt_radius)
if error_seg1 or error_seg2:
if not error_layer:
if error_layer == None:
# we have an error, but no Error layer
print('- SiEPIC:layout_waveguide2: missing Error layer')
# and pt_radius < to_itype(radius,dbu):
Expand Down