Files
mxpic_forge/mxpic/components/primitives/active/dev_ps.py
T
2026-06-06 16:43:26 +08:00

481 lines
24 KiB
Python

import nazca as nd
import numpy as np
from ..pic import taper_xs2xs
import nazca.interconnects as IC
class Route(IC.Interconnect):
pass
# from ...routing import Route
from ...electronics import Vias
class Heater_NDoped():
"""
This is the class for N-doped heater as a phase shifter.
Parameters
----------
w_wg : float, optional
Width parameter in microns. Default is 0.45.
slab_width : float, optional
Value for the slab_width parameter. Default is 1.1.
heater_length : int, optional
Value for the heater_length parameter. Default is 100.
heater_width : int, optional
Value for the heater_width parameter. Default is 1.
if_open : bool, optional
Value for the if_open parameter. Default is True.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
"""
def __init__(
self,
w_wg: float=0.45,
slab_width: float=1.1,
heater_length: int=100,
heater_width: int=1,
if_open: bool=True,
show_pins: bool=False
) -> None:
'''
__Summary__: Initilization of N Doped Heater.
Args:
1. w_wg [um] Width of input waveguide
2. slab_width [um] Distance betwee wg edge and N doped region edge
3. heater_length[um] Length of heater
4. heater_width [um] Width of heater
5. if_open [Bool] If add an open region to decrease the thickness of cladding
'''
self.w_wg = w_wg
self.slab_width = slab_width
self.heater_length = heater_length
self.heater_width = heater_width
self.pitch = self.heater_width + self.w_wg + self.slab_width*2
self.if_open = if_open
self.show_pins = show_pins
self.cell = self.generate_gds()
def generate_gds(self):
with nd.Cell(name="Heater_NDoped", instantiate=False) as C:
nd.add_xsection(name="rib_narrow")
nd.add_layer2xsection(xsection="rib_narrow", layer="RIB_COR")
nd.add_layer2xsection(xsection="rib_narrow", layer="RIB_CLD", leftedge=(0.5, self.slab_width), rightedge=(-0.5, -self.slab_width))
nd.add_layer2xsection(xsection="rib_narrow", layer="STRIP_COR", leftedge=(0.5, self.slab_width), rightedge=(-0.5, -self.slab_width))
nd.add_layer2xsection(xsection="rib_narrow", layer="STRIP_CLD", leftedge=(0.5, 2), rightedge=(-0.5, -2))
layer_cld = nd.get_layer("STRIP_CLD")
if layer_cld=="dump" :
nd.text(text="==This device is not compatible with this foundry==",height=5,layer=(1005)).put(3,-20)
print("==Active::dev_ps::Heater_NDoped is not compatible with this tapeout.")
L_taper = 10
taper = taper_xs2xs(
xs_1='rib_narrow',
xs_2='strip',
L_taper=L_taper,
w_1=self.w_wg,
w_2=self.w_wg,
L_port=0
).cell
taper_l1 = taper.put('b0', 0, 0)
bend_radius_stripe = 5
stripe = Route(xs='strip', width=self.w_wg, radius=bend_radius_stripe)
rib = Route(xs='rib_narrow', width=self.w_wg)
## Build waveguide first
rib_strt_up = rib.strt(length=self.heater_length, arrow=False).put(taper_l1.pin['a0'])
taper_r1 = taper.put('a0', rib_strt_up.pin['b0'])
stripe.bend(angle=90, arrow=False).put(taper_r1.pin['b0'])
stripe.bend(angle=-180, arrow=False).put()
stripe.strt(length=self.pitch, arrow=False).put()
bend_out = stripe.bend(angle=-90, arrow=False).put()
stripe.strt_p2p(pin1=bend_out.pin['b0'], pin2=(taper_r1.pin['b0'].x, taper_r1.pin['b0'].y-self.pitch, taper_r1.pin['b0'].a+180), arrow=False).put()
taper_r2 = taper.put('b0')
rib_strt_mid = rib.strt(length=self.heater_length, arrow=False).put(taper_r2.pin['a0'])
taper_l2 = taper.put('a0', rib_strt_mid.pin['b0'])
stripe.strt(length=bend_radius_stripe*2, arrow=False).put(taper_l2.pin['b0'])
stripe.bend(angle=90, arrow=False).put()
stripe.strt(length=self.pitch, arrow=False).put()
stripe.bend(angle=180, arrow=False).put()
stripe.bend(angle=-90, arrow=False).put()
taper_l3 = taper.put('b0')
rib_strt_low = rib.strt(length=self.heater_length, arrow=False).put(taper_l3.pin['a0'])
taper_r3 = taper.put('a0', rib_strt_low.pin['b0'])
# Add input and output waveguide
length_wg = bend_radius_stripe*3+2+self.w_wg/2
wg_input = stripe.strt(length=length_wg, arrow=False).put(taper_l1.pin['b0'])
wg_output =stripe.strt(length=length_wg, arrow=False).put(taper_r3.pin['b0'])
## Add N-doped heater region
heater_strip_cor = nd.strt(length=self.heater_length, width=self.heater_width, layer='STRIP_COR')
heater_Ndoped = nd.strt(length=self.heater_length, width=self.heater_width, layer='NP')
heater_strip_cor.put(rib_strt_up.pin['a0'].x, (rib_strt_up.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
heater_strip_cor.put(rib_strt_up.pin['a0'].x, (rib_strt_low.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
heater_Ndoped.put(rib_strt_up.pin['a0'].x, (rib_strt_up.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
heater_Ndoped.put(rib_strt_up.pin['a0'].x, (rib_strt_low.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
vias_width = 6
vias = Vias(xs='via_s2m', area=[vias_width, self.heater_width-0.2*2], sz=[0.25, 0.25], spacing=[0.35, 0.35], xs_l1='sa', xs_l2='metal').cell
vias_l1 = vias.put(rib_strt_up.pin['a0'].x+0.2+vias_width/2, (rib_strt_up.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
vias_l2 = vias.put(rib_strt_up.pin['a0'].x+0.2+vias_width/2, (rib_strt_low.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
vias_r1 = vias.put(rib_strt_up.pin['b0'].x-0.2-vias_width/2, (rib_strt_up.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
vias_r2 = vias.put(rib_strt_up.pin['b0'].x-0.2-vias_width/2, (rib_strt_low.pin['a0'].y+rib_strt_mid.pin['b0'].y)/2, 0)
metal1 = Route(xs='metal', radius=0)
metal_l=metal1.strt_p2p(pin1=vias_l1.pin['a0'], pin2=vias_l2.pin['b0'], width=vias_width, arrow=False).put()
metal_r=metal1.strt_p2p(pin1=vias_r1.pin['a0'], pin2=vias_r2.pin['b0'], width=vias_width, arrow=False).put()
## Add open region to decrease the thickness of cladding
if self.if_open:
length_open = self.heater_length - 0.4 - vias_width*2 - 6*2
nd.strt(length=length_open, width=20, layer='GC_OPEN').put(
rib_strt_up.pin['a0'].x+0.2+vias_width+6,
(metal_r.pin['a0'].y+metal_r.pin['b0'].y)/2,
0
)
## Add dummy to avoid sharp angle
poly = [
(0, 0),
(0, self.pitch+self.w_wg+4+bend_radius_stripe*2),
(bend_radius_stripe*3+self.w_wg/2+2, self.pitch+self.w_wg+4+bend_radius_stripe*2),
(bend_radius_stripe*3+self.w_wg/2+2, 0)
]
nd.Polygon(points=poly, layer="STRIP_CLD").put(
taper_l1.pin['b0'].x, taper_l1.pin['b0'].y-self.pitch+self.w_wg/2+2, flip=True, flop=True
)
nd.Polygon(points=poly, layer="STRIP_CLD").put(
taper_r1.pin['b0'].x, taper_r2.pin['b0'].y-self.w_wg/2-2
)
## Add pin
nd.Pin(name='a0').put(wg_input.pin['b0'])
nd.Pin(name='a1', width=self.w_wg).put(wg_input.pin['b0'])
nd.Pin(name='b1', width=self.w_wg).put(wg_output.pin['b0'])
nd.Pin(name='ep1', width=abs(metal_l.pin['a0'].y-metal_l.pin['b0'].y)).put(
metal_l.pin['a0'].x, (metal_l.pin['a0'].y+metal_l.pin['b0'].y)/2, 180
)
nd.Pin(name='en1', width=abs(metal_r.pin['a0'].y-metal_r.pin['b0'].y)).put(
metal_r.pin['a0'].x, (metal_r.pin['a0'].y+metal_r.pin['b0'].y)/2, 0
)
if self.show_pins:
nd.put_stub()
return C
def generate_test_gds(self, gc, mmi, mzi_offset=60, ct_pitch=20, gc2gc_length=500, cell_name=None, gc_offset=0):
if cell_name==None:
cell_name = self.cell.cell_name + "_test"
with nd.Cell(name=cell_name, instantiate=False) as C:
stripe = Route(radius=5, width=gc.w_wg, xs='strip')
gc_input = gc.cell.put('g1',0,gc_offset,180)
gc_output = gc.cell.put('g1',gc2gc_length,gc_offset,0)
mmi_input = mmi.cell.put('a1',20,0,0)
mmi_output = mmi.cell.put('a1', gc_output.pin['g1'].x-20,0, 180)
stripe.sbend_p2p(
pin1=gc_input.pin['g1'],
pin2=mmi_input.pin['a1'],
Lstart=5,
arrow=False
).put()
stripe.sbend_p2p(
pin1=gc_output.pin['g1'],
pin2=mmi_output.pin['a1'],
Lstart=5,
arrow=False
).put()
# Connect upper arm
ps = self.cell.put('a1',mmi_input.pin['b1'].x+40,mzi_offset)
stripe.sbend_route_p2p(
pin1=mmi_input.pin['b1'],
pin2=ps.pin['a1'],
arrow=False
).put()
stripe.sbend_route_p2p(
pin1=mmi_output.pin['b2'],
pin2=ps.pin['b1'],
arrow=False
).put()
# Connect lower arm
stripe.strt_p2p(
pin1=mmi_input.pin['b2'],
pin2=mmi_output.pin['b1'],
arrow=False
).put()
## Put CT heater
ps_ct = self.cell.put('a1',ps.pin['a1'].x,ps.pin['a1'].y+ct_pitch,0)
## Put pins
nd.Pin(name="ep1", pin=ps.pin['ep1']).put()
nd.Pin(name="en1", pin=ps.pin['en1']).put()
nd.Pin(name="ep2", pin=ps_ct.pin['ep1']).put()
nd.Pin(name="en2", pin=ps_ct.pin['en1']).put()
return C
class PS_PIN() :
"""
PIN junction for a high-speed phase shift.
Parameters
----------
w_wg : float, optional
Width parameter in microns. Default is 0.45.
w_wg_slab : float, optional
Width parameter in microns. Default is 0.5.
w_slab : float, optional
Width parameter in microns. Default is 1.
l_wg : float, optional
Value for the l_wg parameter. Default is 800.
d2wg_list : list, optional
Value for the d2wg_list parameter. Default is [0.2, 1].
p_layer_list : list, optional
Value for the p_layer_list parameter. Default is ['PW', 'PP'].
n_layer_list : list, optional
Value for the n_layer_list parameter. Default is ['NW', 'NP'].
w_plus_max : float, optional
Width parameter in microns. Default is 5.1.
show_pins : bool, optional
Whether to draw pin markers in the generated layout. Default is False.
"""
def __init__(
self,
w_wg: float=0.45,
w_wg_slab: float=0.5,
w_slab: float=1,
l_wg: float=800,
d2wg_list: list = [0.2, 1],
p_layer_list: list = ['PW', 'PP'],
n_layer_list: list = ['NW', 'NP'],
w_plus_max: float = 5.1,
show_pins: bool=False,
# # Parameters to be abandoned
# d2wg=0.4,
# layer_pld='PLD_2',
# layer_nld='NLD_2'
) -> None:
'''
Initilization of PS_PIN.
Args:
- w_wg [um] Width of the input waveguide.
- w_wg_slab [um] Width of the slab waveguide.
- w_slab [um] Width of the slab region of slab waveguides.
- l_wg [um] Length of the PIN phase shifter.
- d2wg_list [list[um]] Distance to the waveguide edge of corresponding doping regions.
- p_layer_list [list[strt]] Layer names of P doped regions, with same length as 'd2wg_list'.
- n_layer_list [list[strt]] Layer names of N doped regions, with same length as 'd2wg_list'.
- w_plus_max[um] Maximum distance of doping regions to the center.
- show_pins [bool] If show connecting pins, with a1, b1, ep1, en1.
'''
self.w_wg = w_wg
self.w_wg_slab = w_wg_slab
self.w_slab = w_slab
self.l_wg = l_wg
self.d2wg_list = d2wg_list
self.p_layer_list = p_layer_list
self.n_layer_list = n_layer_list
self.w_plus_max = w_plus_max
if len(self.d2wg_list) != len(self.p_layer_list) :
print("==Warning==PIN:: len(d2wg_list) != len(self.p_layer_list). ")
if len(self.d2wg_list) != len(self.n_layer_list) :
print("==Warning==PIN:: len(d2wg_list) != len(self.n_layer_list). ")
self.show_pins = show_pins
self.cell = self.generate_gds()
''' Parameters to be abandoned '''
# self.d2wg = d2wg
# self.layer_pld = layer_pld
# self.layer_nld = layer_nld
def generate_gds(self) :
cell_name = "ps_pin"
for _index_ in range(len(self.d2wg_list)) :
cell_name = cell_name + "_" + self.p_layer_list[_index_] + str(int(self.d2wg_list[_index_]*1000)) + "nm"
self.cell_name = cell_name
with nd.Cell(name=self.cell_name, instantiate=True) as ICell :
''' Add The Waveguide '''
strip = Route(radius=10,width=self.w_wg,xs='strip')
nd.add_xsection(name='slab_pin')
nd.add_layer2xsection(xsection='slab_pin', layer='RIB_COR', leftedge=(0.5,0), rightedge=(-0.5,0), overwrite=True)
nd.add_layer2xsection(xsection='slab_pin', layer='RIB_CLD', leftedge=(0.5,self.w_slab), rightedge=(-0.5,-self.w_slab), overwrite=True)
slab = Route(radius=10,width=self.w_wg_slab,xs='slab_pin')
nd.add_xsection(name='slab2strip_pin')
nd.add_layer2xsection(xsection='slab2strip_pin', layer='RIB_COR', leftedge=(0.5,0), rightedge=(-0.5,0), overwrite=True)
nd.add_layer2xsection(xsection='slab2strip_pin', layer='RIB_CLD', leftedge=(0.5,self.w_slab), rightedge=(-0.5,-self.w_slab), overwrite=True)
nd.add_layer2xsection(xsection='slab2strip_pin', layer='STRIP_COR', leftedge=(0.5,self.w_slab), rightedge=(-0.5,-self.w_slab), overwrite=True)
nd.add_layer2xsection(xsection='slab2strip_pin', layer='STRIP_CLD', leftedge=(0.5,self.w_slab*2), rightedge=(-0.5,-self.w_slab*2), overwrite=True)
taper_strip2slab = taper_xs2xs(xs_1='strip',xs_2='slab2strip_pin',L_taper=10,w_1=self.w_wg,w_2=self.w_wg_slab, L_port=0.2)
taper_slab2strip = taper_xs2xs(xs_1='slab2strip_pin',xs_2='strip',L_taper=10,w_1=self.w_wg_slab, w_2=self.w_wg,L_port=0.2)
taper_input = taper_strip2slab.cell.put('a1',0,0,0)
wg_ps = slab.strt(length=self.l_wg,arrow=False).put(taper_input.pin['b1'])
taper_output = taper_slab2strip.cell.put('a1',wg_ps.pin['b0'])
''' Add doping area near the waveguide '''
l_edge = 1
for _index_ in range(len(self.d2wg_list)) :
d2wg_temp = self.d2wg_list[_index_]
p_layer_temp = self.p_layer_list[_index_]
n_layer_temp = self.n_layer_list[_index_]
doping_polygon = [
(taper_input.pin['b1'].x+l_edge, self.w_wg_slab/2+d2wg_temp),
(taper_output.pin['a1'].x-l_edge, self.w_wg_slab/2+d2wg_temp),
(taper_output.pin['a1'].x-l_edge, self.w_plus_max),
(taper_input.pin['b1'].x+l_edge, self.w_plus_max)
]
nd.Polygon(points=doping_polygon, layer=p_layer_temp).put(0,0)
nd.Polygon(points=doping_polygon, layer=n_layer_temp).put(0,0,flop=True)
''' Add Vias '''
vias = Vias(
xs='via_s2m', area=[self.l_wg-l_edge*2-0.2*2, self.w_plus_max-(self.d2wg_list[-1]+self.w_wg_slab/2)-0.2*2],
sz=[0.25, 0.25], spacing=[0.35, 0.35],
xs_l1="sa", xs_l2="metal", show_pins=False
)
vias_p = vias.cell.put(
taper_input.pin['b1'].x+self.l_wg/2, (self.w_plus_max+self.d2wg_list[-1]+self.w_wg_slab/2)/2
)
vias_n = vias.cell.put(
taper_input.pin['b1'].x+self.l_wg/2, -(self.w_plus_max+self.d2wg_list[-1]+self.w_wg_slab/2)/2
)
''' Add Pins '''
nd.Pin(name='a1',width=self.w_wg).put(taper_input.pin['a1'])
nd.Pin(name='b1',width=self.w_wg).put(taper_output.pin['b1'])
nd.Pin(name="ep1", width=self.w_plus_max-(self.d2wg_list[-1]+self.w_wg_slab/2)-0.2*2).put(vias_p.pin['a0'])
nd.Pin(name="en1", width=self.w_plus_max-(self.d2wg_list[-1]+self.w_wg_slab/2)-0.2*2).put(vias_n.pin['a0'])
# nd.put_stub()
return ICell
def generate_mzi_gds(self, gc, mmi, pad) :
'''
Generating a Mach-Zehnder Interferometer for testing the PIN phase shifter.
'''
with nd.Cell(name=self.cell_name+"_MZI", instantiate=False) as ICell :
mmi_input = mmi.cell.put('a1',0,0,0)
pin2test = self.cell.put('a1', mmi_input.pin['b1'].move(60,100,0))
mmi_bottom = mmi.cell.put('a1', pin2test.pin['b1'].x+10, mmi_input.pin['b2'].y, 0)
mmi_up = mmi.cell.put('a1', pin2test.pin['b1'].move(10,0,0))
mmi_middle = mmi.cell.put(
'a1',
mmi_bottom.pin['b1'].x+mmi.length+25,
mmi_up.pin['b2'].y/2+mmi_bottom.pin['b1'].y/2,
180
)
''' Wg routing '''
strip = Route(radius=10, width=self.w_wg, xs='strip')
strip.strt_p2p(pin1=mmi_input.pin['b2'],pin2=mmi_bottom.pin['a1'],arrow=False).put()
# strip.sbend_p2p(pin1=mmi_input.pin['b1'],pin2=pin2test.pin['a1'],Lstart=1,arrow=False).put()
strip.sbend_p2p(
pin1=mmi_input.pin['b1'],pin2=nd.Pin().put(mmi_input.pin['b1'].x+11,pin2test.pin['a1'].y,180),
radius=5, Lstart=0.5, arrow=False
).put()
strip.sbend_p2p(
pin1=nd.Pin().put(),pin2=nd.Pin().put(mmi_input.pin['b1'].x+22,mmi_input.pin['b1'].y+1,180),
radius=5, Lstart=0.5, arrow=False
).put()
strip.sbend_p2p(
pin1=nd.Pin().put(),pin2=nd.Pin().put(mmi_input.pin['b1'].x+33,pin2test.pin['a1'].y,180),
radius=5, Lstart=0.5, arrow=False
).put()
strip.sbend_p2p(
pin1=nd.Pin().put(),pin2=nd.Pin().put(mmi_input.pin['b1'].x+44,mmi_input.pin['b1'].y+1,180),
radius=5, Lstart=0.5, arrow=False
).put()
strip.sbend_p2p(
pin1=nd.Pin().put(),pin2=nd.Pin().put(mmi_input.pin['b1'].x+55,pin2test.pin['a1'].y,180),
radius=5, Lstart=0.5, arrow=False
).put()
strip.strt_p2p(pin1=nd.Pin().put(),pin2=pin2test.pin['a1'],arrow=False).put()
# strip.sbend(radius=5,offset=-abs(pin2test.pin['a1'].y-mmi_input.pin['b1'].y),arrow=False).put()
strip.strt_p2p(pin1=mmi_up.pin['a1'],pin2=pin2test.pin['b1'],arrow=False).put()
strip.sbend_p2p(pin1=mmi_up.pin['b2'],pin2=mmi_middle.pin['b2'],Lstart=0.5,radius=10,arrow=False).put()
strip.sbend_p2p(pin1=mmi_bottom.pin['b1'],pin2=mmi_middle.pin['b1'],Lstart=2.5,radius=10,arrow=False).put()
''' Add pads '''
pad_ground = pad.cell.put(
mmi_input.pin['b1'].x+40+30+50,mmi_input.pin['b1'].y+5+40-4,0
)
pad_signal = pad.cell.put(
mmi_input.pin['b1'].x+40+30+100+50,mmi_input.pin['b1'].y+5+40-4,0
)
''' Metal Connecting '''
metal = Route(radius=5,width=10,xs='metal')
metal_2 = Route(radius=5,width=10,xs='metal_2')
vias_m2m = Vias(
xs='via_m2m', area=[self.l_wg+0.4, 10], sz=[0.6, 0.6], spacing=[0.6, 0.6],
xs_l1='metal', xs_l2='metal_2', instantiate=True, show_pins=False
)
metal.strt_p2p(
pin1=pad_ground.pin['p1'],
pin2=nd.Pin().put(pad_ground.pin['p1'].x,pin2test.pin['en1'].y),
arrow=False
).put()
vias = vias_m2m.cell.put(
pin2test.pin['ep1'].move(
0,-5+(self.w_plus_max-self.d2wg_list[-1]-self.w_wg_slab/2)/2,0
)
)
metal_2.strt_p2p(
pin1=pad_signal.pin['p1'],
pin2=nd.Pin().put(pad_signal.pin['p1'].x,vias.pin['a0'].y),
arrow=False
).put()
metal.strt(length=self.l_wg+0.4,width=10,arrow=False).put(
pin2test.pin['en1'].move(
-self.l_wg/2-0.2,5-(self.w_plus_max-self.d2wg_list[-1]-self.w_wg_slab/2)/2,0
)
)
''' Put output gratings '''
strip.strt(length=60,arrow=False).put(mmi_input.pin['a1'])
gc.cell.put('g1')
strip.strt(length=60,arrow=False).put(mmi_up.pin['b1'])
gc.cell.put('g1')
strip.strt(length=100,arrow=False).put(mmi_middle.pin['a1'])
gc.cell.put('g1')
strip.strt(length=60,arrow=False).put(mmi_bottom.pin['b2'])
gc.cell.put('g1')
return ICell
# class N_Doped_strt() :
# '''
# Class for a strt N doped region
# '''
# def __init__(self, tapeout, width=2.5, length=100, sa_length=6):
# self.tapeout = tapeout
# self.width = width
# self.length = length
# self.sa_length = sa_length
# self.generate_gds()
# def generate_gds(self):
# with nd.Cell(name="N_Doped_strt", instantiate=False) as C:
# nd.strt(length=self.length, width=self.width, layer="STRIP_COR").put(0,0)
# nd.strt(length=self.length, width=self.width, layer="NP").put(0,0)
# nd.strt(length=self.length, width=self.width, layer="STRIP_COR").put(0,0)
# nd.strt(length=self.length+4, width=self.width+4, layer="STRIP_CLD").put(-2,0)
# sa_ep1 = nd.strt(length=self.sa_length, width=self.width-0.4, xs="sa").put(0.2,0)
# sa_ep2 = nd.strt(length=self.sa_length, width=self.width-0.4, xs="sa").put(self.length-0.2,0,180)
# sa_en1 = nd.strt(length=self.sa_length, width=self.width-0.4, xs="sa").put(self.length/2-self.sa_length/2,0)
# # vias = Vias(
# # xs="via_h2m",
# # area=[self.sa_length, self.width-0.4],
# # sz=[0.6, 0.6],
# # spacing=[0.6, 0.6],
# # xs="ct",
# # area=[self.sa_length, self.width-0.4],
# # sz=[0.25, 0.25],
# # spacing=[0.35, 0.35],
# # xs_l1='sa',
# # xs_l2='metal_1'
# # )
# # vias_ep1 = vias.cell.put(sa_ep1.pin['a0'].move(-self.sa_length/2,0))
# # vias_ep2 = vias.cell.put(sa_ep2.pin['a0'].move(-self.sa_length/2,0))
# # vias_en1 = vias.cell.put(sa_en1.pin['a0'].move(-self.sa_length/2,0))
# # nd.Pin(name="ep1", pin=vias_ep1.pin['b0']).put()
# # nd.Pin(name="ep2", pin=vias_ep2.pin['a0']).put()
# # nd.Pin(name="en1", pin=vias_en1.pin['b0'].move(0,0,90)).put()
# # nd.put_stub(pinname=["ep1", "ep2", "en1"])
# self.cell = C
# return C