2244 lines
96 KiB
Python
2244 lines
96 KiB
Python
from typing import Any, Optional
|
|
import nazca as nd
|
|
import numpy as np
|
|
|
|
from ...basic import __xs_exist__
|
|
|
|
from ...geometry import *
|
|
import nazca.interconnects as IC
|
|
|
|
class Route(IC.Interconnect):
|
|
pass
|
|
# from ...routing import *
|
|
|
|
from .unit import *
|
|
|
|
from ..pic import *
|
|
from ...electronics import Vias
|
|
|
|
from ...basic import __xs_exist__
|
|
|
|
|
|
|
|
class SOCR():
|
|
"""
|
|
This is the class for normal Strong Over Coupled Ring for phase modulation.
|
|
|
|
Parameters
|
|
----------
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
w_cp : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
w_ring : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
r_ring : float, optional
|
|
Radius parameter in microns. Default is 6.
|
|
gap : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
theta_arc : float, optional
|
|
Angle parameter in degrees. Default is 100.
|
|
Ls : float, optional
|
|
Length parameter in microns. Default is 2.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 1.5.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 6.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is True.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
w_wg : float = 0.45,
|
|
w_cp : float =0.45,
|
|
w_ring : float =0.45,
|
|
r_ring : float =6,
|
|
gap : float =0.2,
|
|
theta_arc : float =100,
|
|
Ls : float = 2,
|
|
xs_ring : str = "strip",
|
|
|
|
w_heater : float =1.5,
|
|
xs_heater : str = "heater",
|
|
|
|
w_metal : float = 6,
|
|
xs_metal : str = "metal",
|
|
|
|
via_h2m: Any = None,
|
|
|
|
sharp_patch : bool = True,
|
|
show_pins : bool = True
|
|
) -> None:
|
|
'''
|
|
Initilization of SOCR.
|
|
|
|
Args:
|
|
- w_wg [um] Width of normal waveguide
|
|
- w_cp [um] Width of coupling waveguide
|
|
- w_ring [um] Width of ring resonator
|
|
- r_ring [um] Radius of ring resonator
|
|
- gap [um] Gap of coupling region
|
|
- theta_arc [degree]Angle of coupling region
|
|
- Ls [um]
|
|
'''
|
|
self.res = 0.1
|
|
## Basic parameters
|
|
self.w_wg = w_wg
|
|
self.w_cp = w_cp
|
|
self.w_ring = w_ring
|
|
self.r_ring = r_ring
|
|
self.gap = gap
|
|
self.theta_arc = theta_arc
|
|
self.Ls = Ls
|
|
self.xs_ring = xs_ring
|
|
|
|
self.w_heater = w_heater
|
|
self.xs_heater = xs_heater
|
|
|
|
self.w_metal = w_metal
|
|
self.xs_metal = xs_metal
|
|
|
|
self.via_h2m = via_h2m
|
|
self.xs_via_h2m = self.via_h2m.xs
|
|
self.sz_via_h2m = self.via_h2m.sz[0]
|
|
self.sp_via_h2m = self.via_h2m.spacing[0]
|
|
try:
|
|
nd.get_xsection(self.xs_via_h2m)
|
|
except:
|
|
print("==Passive::rings::SOCR::<xs_via_h2m>::",self.xs_via_h2m," not define in the tapeout.")
|
|
self.xs_via_h2m = None
|
|
|
|
self.sharp_patch = sharp_patch
|
|
self.show_pins = show_pins
|
|
|
|
self.cell_name = "SOCR_Wcp"+str(np.floor(self.w_cp*1000))+"_Wr"+str(np.floor(self.w_ring*1000))+"_G"+str(self.gap)+"_R"+str(self.r_ring)+"_Arc"+str(self.theta_arc)
|
|
self.cell = self.generate_gds()
|
|
|
|
def generate_pic_part(self):
|
|
'''
|
|
Generate gds.
|
|
Return: Cell
|
|
'''
|
|
with nd.Cell(name=self.cell_name+"_pic",instantiate=False) as C:
|
|
## Generate the adiabatic ring
|
|
theta_list = np.linspace(0, 2*np.pi, int(self.r_ring*2*np.pi/self.res)+1)
|
|
self.r_out = self.r_ring + self.w_ring/2
|
|
self.r_in = self.r_ring - self.w_ring/2
|
|
curve_r_out = [(self.r_out*np.cos(theta), self.r_out*np.sin(theta)) for theta in theta_list]
|
|
curve_r_in = [(self.r_in*np.cos(theta), self.r_in*np.sin(theta)) for theta in theta_list]
|
|
curve_r_in.reverse()
|
|
poly_resonator = curve_r_out + curve_r_in
|
|
nd.Polygon(points=poly_resonator, layer=self.xs_ring.upper()+"_COR").put()
|
|
# Add cladding if cladding layer exists
|
|
layer_cld_name = nd.get_layer(self.xs_ring.upper()+"_CLD")
|
|
# if layer_cld_name != "dump":
|
|
# r_cld_out = self.r_out + 2
|
|
# resonator_cld_out = [(r_cld_out*np.cos(theta), r_cld_out*np.sin(theta)) for theta in theta_list]
|
|
# r_cld_in = self.r_in - 2
|
|
# if r_cld_in < 1:
|
|
# resonator_cld_in = []
|
|
# else:
|
|
# resonator_cld_in = [(r_cld_in*np.cos(theta), r_cld_in*np.sin(theta)) for theta in theta_list]
|
|
# resonator_cld_in.reverse()
|
|
# resonator_cld_poly = resonator_cld_out + resonator_cld_in
|
|
# nd.Polygon(points=resonator_cld_poly, layer=self.xs_ring.upper()+"_CLD").put(0, 0)
|
|
for layers,growx,growy,acc in nd.layeriter(xs=self.xs_ring):
|
|
(a1,b1), (a2,b2),c1,c2 = growx
|
|
if b1!=0 and b2!=0 :
|
|
r_cld_out = self.r_out + b1
|
|
resonator_cld_out = [(r_cld_out*np.cos(theta), r_cld_out*np.sin(theta)) for theta in theta_list]
|
|
r_cld_in = self.r_in + b2
|
|
if r_cld_in < 1:
|
|
resonator_cld_in = []
|
|
else:
|
|
resonator_cld_in = [(r_cld_in*np.cos(theta), r_cld_in*np.sin(theta)) for theta in theta_list]
|
|
resonator_cld_in.reverse()
|
|
resonator_cld_poly = resonator_cld_out + resonator_cld_in
|
|
nd.Polygon(points=resonator_cld_poly, layer=layers).put(0, 0)
|
|
## Add input waveguide
|
|
wg = Route(width=self.w_cp, radius=5, xs=self.xs_ring)
|
|
wg.bend(radius=self.r_out+self.gap+self.w_cp/2, angle=self.theta_arc/2, arrow=False).put(0, -(self.r_out+self.gap+self.w_cp/2))
|
|
wg.strt(length=self.Ls, arrow=False).put()
|
|
wg.bend(angle=-self.theta_arc/2, arrow=False).put()
|
|
strt_out = wg.strt(length=1, arrow=False).put()
|
|
wg.taper(width1=self.w_cp, width2=self.w_wg, length=4.5, arrow=False).put()
|
|
wg_out = wg.strt(width=self.w_wg,length=0.5,arrow=False).put()
|
|
|
|
wg.bend(radius=self.r_out+self.gap+self.w_cp/2, angle=-self.theta_arc/2, arrow=False).put(0, -(self.r_out+self.gap+self.w_cp/2), 180)
|
|
wg.strt(length=self.Ls, arrow=False).put()
|
|
wg.bend(angle=self.theta_arc/2, arrow=False).put()
|
|
wg.strt(length=1, arrow=False).put()
|
|
wg.taper(width1=self.w_cp, width2=self.w_wg, length=4.5, arrow=False).put()
|
|
wg_in = wg.strt(width=self.w_wg,length=0.5,arrow=False).put()
|
|
## Add pins
|
|
nd.Pin(name="a1", width=self.w_wg).put(wg_in.pin['b0'])
|
|
nd.Pin(name="b1", width=self.w_wg).put(wg_out.pin['b0'])
|
|
## Add patch
|
|
if self.sharp_patch and (layer_cld_name != "dump"):
|
|
# if hasattr(self.tapeout, "LAYER_STRIP_CLD"):
|
|
# Vertical patch
|
|
x_min = self.r_ring + self.w_ring/2 + 2
|
|
x_max = self.r_ring - self.w_ring/2 - 2
|
|
y_min = 0
|
|
y_max = wg_in.pin['a0'].y + self.w_cp/2 + 2
|
|
rect_poly = [(x_min,y_min),(x_min,y_max),(x_max,y_max),(x_max,y_min)]
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0)
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0,flip=True)
|
|
# Horizontal patch
|
|
x_min = self.r_in - 2
|
|
x_max = strt_out.pin['b0'].x
|
|
y_min = strt_out.pin['b0'].y - self.w_cp/2 - 2
|
|
y_max = strt_out.pin['b0'].y + self.w_cp/2 + 2
|
|
rect_poly = [(x_min,y_min),(x_min,y_max),(x_max,y_max),(x_max,y_min)]
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0)
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0,flip=True)
|
|
if self.show_pins:
|
|
nd.put_stub()
|
|
return C
|
|
|
|
def generate_eic_part(self):
|
|
with nd.Cell(name=self.cell_name+"_eic",instantiate=False) as C:
|
|
# Add heater
|
|
ring_x = 0
|
|
ring_y = 0
|
|
ring_radius = self.r_ring
|
|
ring_width = self.w_heater
|
|
theta_start = -30
|
|
theta_stop = 180+30
|
|
n_points = int((theta_stop-theta_start)*2*np.pi/360 * ring_radius / self.res)
|
|
circle(radius=ring_radius, width=ring_width, theta_start=theta_start, theta_stop=theta_stop, res=self.res,
|
|
# n_points=n_points, ## revised in 2023.03.20
|
|
layer=self.xs_heater.upper()).cell.put(ring_x, ring_y)
|
|
# Add a broad region to connect heater with metal2
|
|
via_region_width = self.w_metal
|
|
r_below_point = [((ring_radius+ring_width/2) * np.cos(theta_start*np.pi/180)+ring_x,
|
|
(ring_radius+ring_width/2) * np.sin(theta_start*np.pi/180)+ring_y)]
|
|
r_up_point = [((ring_radius-ring_width/2) * np.cos(theta_start*np.pi/180)+ring_x,
|
|
(ring_radius-ring_width/2) * np.sin(theta_start*np.pi/180)+ring_y)]
|
|
heater_con_poly = r_up_point + r_below_point + [
|
|
(r_below_point[0][0], r_below_point[0][1]-2.2),
|
|
# (r_up_point[0][0]+via_region_width, r_below_point[0][1]-2.2),
|
|
(r_up_point[0][0], r_below_point[0][1]-2.2)
|
|
]
|
|
nd.Polygon(points=heater_con_poly, layer=self.xs_heater.upper()).put(0, 0)
|
|
nd.Polygon(points=heater_con_poly, layer=self.xs_heater.upper()).put(0, 0, flip=True)
|
|
# Add via
|
|
heater_wide_width = r_up_point[0][0]+via_region_width - r_up_point[0][0]
|
|
heater_wide_x = (r_up_point[0][0]+via_region_width + r_up_point[0][0]) / 2
|
|
heater_wide_y = -heater_wide_width/2 + r_below_point[0][1]-2.2
|
|
vias = Vias(
|
|
xs=self.xs_via_h2m,
|
|
area=[heater_wide_width, heater_wide_width],
|
|
sz=[self.sz_via_h2m, self.sz_via_h2m],
|
|
spacing=[self.sp_via_h2m, self.sp_via_h2m],
|
|
xs_l1=self.xs_heater,
|
|
xs_l2=self.xs_metal
|
|
)
|
|
vias.cell.put(heater_wide_x,heater_wide_y)
|
|
vias.cell.put(-heater_wide_x,heater_wide_y)
|
|
nd.Pin(name='ep1', width=via_region_width).put(-heater_wide_x, heater_wide_y, -90)
|
|
nd.Pin(name='en1', width=via_region_width).put( heater_wide_x, heater_wide_y, -90)
|
|
return C
|
|
|
|
def generate_gds(self):
|
|
self.cell_pic = self.generate_pic_part()
|
|
self.cell_eic = self.generate_eic_part()
|
|
with nd.Cell(name=self.cell_name,instantiate=False) as C:
|
|
pic = self.cell_pic.put(0, 0)
|
|
eic = self.cell_eic.put(0, 0)
|
|
## Add pins
|
|
nd.Pin(name="a1", width=self.w_wg).put(pic.pin['a1'])
|
|
nd.Pin(name="b1", width=self.w_wg).put(pic.pin['b1'])
|
|
nd.Pin(name="ep1", width=eic.pin['ep1'].width).put(eic.pin['ep1'])
|
|
nd.Pin(name="en1", width=eic.pin['en1'].width).put(eic.pin['en1'])
|
|
if self.show_pins:
|
|
nd.put_stub()
|
|
return C
|
|
|
|
def generate_2pi_gds(self, gap=10):
|
|
with nd.Cell(name=self.cell.cell_name+"_2pi", instantiate=False) as C:
|
|
socr_1 = self.cell.put('a1',0,0,0)
|
|
socr_2 = self.cell.put('a1', socr_1.pin['b1'].move(gap,0,0))
|
|
stripe = Route(xs='strip', width=self.w_wg, radius=5)
|
|
metal1 = Route(xs='metal', width=6, radius=0)
|
|
stripe.strt_p2p(
|
|
pin1=socr_1.pin['b1'].move(-0.1,0,0),
|
|
pin2=socr_2.pin['a1'].move(-0.1,0,0),
|
|
arrow=False
|
|
).put()
|
|
metal1.strt_p2p(
|
|
pin1=socr_1.pin['en1'],
|
|
pin2=socr_2.pin['ep1'],
|
|
arrow=False
|
|
).put()
|
|
nd.Pin(name='a1', width=self.w_wg).put(socr_1.pin['a1'])
|
|
nd.Pin(name='b1', width=self.w_wg).put(socr_2.pin['b1'])
|
|
nd.Pin(name='ep1',pin=socr_1.pin['ep1'].move(0,0,-90)).put()
|
|
nd.Pin(name='en1',pin=socr_2.pin['en1'].move(0,0, 90)).put()
|
|
return C
|
|
|
|
def generate_test_mzi_gds(self, gc, mmi, num_socr=1, gc2gc_length=250, mid_offset=40, show_pins=False):
|
|
with nd.Cell(name=self.cell.cell_name+"_test_mzi", instantiate=False) as C:
|
|
gc_input = gc.cell.put('g1', 0, 0, 180)
|
|
gc_output_mid = gc.cell.put('g1', gc2gc_length+mid_offset, 0, 0)
|
|
mmi_input = mmi.cell.put('a1', 20, 0, 0)
|
|
stripe = Route(xs='strip', width=gc.w_wg, radius=5)
|
|
# Connect input gc with first mmi
|
|
stripe.strt_p2p(pin1=gc_input.pin['g1'], pin2=mmi_input.pin['a1'], arrow=False).put()
|
|
# Connect the upper arm
|
|
self.length = self.cell.pin['b1'].x - self.cell.pin['a1'].x
|
|
socr_cell = []
|
|
for _index_ in range(num_socr):
|
|
cell = self.cell.put('a1', mmi_input.pin['b1'].x+30+(self.length+5)*_index_, 40, 0)
|
|
socr_cell.append(cell)
|
|
|
|
# socr_cell = pd.concat(socr_cell,cell)
|
|
|
|
if _index_>=1:
|
|
stripe.strt_p2p(
|
|
pin1=socr_cell[_index_-1].pin['b1'].move(-0.1,0,0),
|
|
pin2=socr_cell[_index_].pin['a1'].move(-0.1,0,0),
|
|
arrow=False
|
|
).put()
|
|
nd.Pin(name="ep"+str(_index_+1),pin=cell.pin['ep1']).put()
|
|
nd.Pin(name="en"+str(_index_+1),pin=cell.pin['en1']).put()
|
|
stripe.sbend_p2p(
|
|
pin1=mmi_input.pin['b1'],
|
|
pin2=socr_cell[0].pin['a1'].move(-0.1,0,0),
|
|
Lstart=1,
|
|
arrow=False).put()
|
|
mmi_output_up = mmi.cell.put('a1', socr_cell[-1].pin['b1'].x+30, socr_cell[-1].pin['b1'].y, 0)
|
|
stripe.strt_p2p(
|
|
pin1=mmi_output_up.pin['a1'],
|
|
pin2=socr_cell[-1].pin['b1'].move(-0.1,0,0),
|
|
arrow=False).put()
|
|
gc_output_up = gc.cell.put('g1', gc2gc_length, mmi_output_up.pin['b1'].y, 0)
|
|
stripe.strt_p2p(
|
|
pin1=mmi_output_up.pin['b1'],
|
|
pin2=gc_output_up.pin['g1'],
|
|
arrow=False).put()
|
|
# Connect the below arm
|
|
mmi_output_below = mmi.cell.put('a1', socr_cell[-1].pin['b1'].x+30, -socr_cell[-1].pin['b1'].y, 0)
|
|
stripe.sbend_p2p(
|
|
pin1=mmi_input.pin['b2'],
|
|
pin2=mmi_output_below.pin['a1'],
|
|
Lstart=1,
|
|
arrow=False).put()
|
|
gc_output_below = gc.cell.put('g1', gc2gc_length, mmi_output_below.pin['b2'].y, 0)
|
|
stripe.strt_p2p(
|
|
pin1=mmi_output_below.pin['b2'],
|
|
pin2=gc_output_below.pin['g1'],
|
|
arrow=False).put()
|
|
# Combine upper and below arm together to do the coherence detection
|
|
mmi_output_mid = mmi.cell.put('a1', mmi_output_below.pin['b1'].x+mmi.length+20, gc_output_mid.pin['g1'].y, 180)
|
|
stripe.strt_p2p(
|
|
pin1=mmi_output_mid.pin['a1'],
|
|
pin2=gc_output_mid.pin['g1'],
|
|
arrow=False).put()
|
|
stripe.sbend_p2p(
|
|
pin1=mmi_output_up.pin['b2'],
|
|
pin2=mmi_output_mid.pin['b2'],
|
|
Lstart=1,
|
|
arrow=False).put()
|
|
stripe.sbend_p2p(
|
|
pin1=mmi_output_below.pin['b1'],
|
|
pin2=mmi_output_mid.pin['b1'],
|
|
Lstart=1,
|
|
arrow=False).put()
|
|
if show_pins : nd.put_stub()
|
|
return C
|
|
|
|
def generate_test_gds(self, gc, num_socr=1, gc2gc_length=250, cell_name=None):
|
|
if cell_name==None:
|
|
cell_name = self.cell.cell_name+"_test_N"+str(num_socr)
|
|
with nd.Cell(name=cell_name, instantiate=False) as C:
|
|
gc_input = gc.cell.put('g1',0,0,180)
|
|
gc_output = gc.cell.put('g1',gc2gc_length, 0, 0)
|
|
stripe = Route(xs='strip', width=gc.w_wg, radius=5)
|
|
# Add test structure
|
|
self.length = self.cell.pin['b1'].x - self.cell.pin['a1'].x
|
|
socr_cell = []
|
|
for _index_ in range(num_socr):
|
|
cell = self.cell.put('a1', gc_input.pin['g1'].x+10+(self.length+5)*_index_, 0, 0)
|
|
socr_cell.append(cell)
|
|
# socr_cell = pd.concat(socr_cell,[cell])
|
|
|
|
|
|
if _index_>=1:
|
|
stripe.strt_p2p(
|
|
pin1=socr_cell[_index_-1].pin['b1'].move(-0.1,0,0),
|
|
pin2=socr_cell[_index_].pin['a1'].move(-0.1,0,0),
|
|
arrow=False).put()
|
|
if num_socr>=1:
|
|
stripe.strt_p2p(
|
|
pin1=gc_input.pin['g1'],
|
|
pin2=socr_cell[0].pin['a1'].move(-0.1,0,0),
|
|
arrow=False).put()
|
|
stripe.strt_p2p(
|
|
pin1=gc_output.pin['g1'],
|
|
pin2=socr_cell[-1].pin['b1'].move(-0.1,0,0),
|
|
arrow=False).put()
|
|
else:
|
|
stripe.strt_p2p(
|
|
pin1=gc_input.pin['g1'],
|
|
pin2=gc_output.pin['g1'],
|
|
arrow=False
|
|
).put()
|
|
return C
|
|
|
|
class SOCR_Cband(SOCR):
|
|
"""
|
|
This is the class for already designed SOCR with multimode waveguide to suppres the phase noise.
|
|
|
|
Parameters
|
|
----------
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is True.
|
|
"""
|
|
def __init__(self, w_wg : float = 0.45, via_h2m: Any = None, show_pins : bool = True) -> None:
|
|
super().__init__(
|
|
w_wg=w_wg,
|
|
w_cp=0.45, w_ring=0.8, r_ring=5.6, gap=0.18, theta_arc=150, Ls=1, w_heater=1.5,
|
|
via_h2m=via_h2m,
|
|
show_pins=show_pins
|
|
)
|
|
|
|
class SOCR_Adiabatic(SOCR):
|
|
"""
|
|
This is the class for adiabatic Strong Over Coupled Ring(SOCR) for phase modulation.
|
|
|
|
Parameters
|
|
----------
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
w_cp : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
w_in : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
w_out : float, optional
|
|
Width parameter in microns. Default is 2.
|
|
r_out : float, optional
|
|
Radius parameter in microns. Default is 6.
|
|
gap : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
theta_arc : float, optional
|
|
Angle parameter in degrees. Default is 100.
|
|
Ls : float, optional
|
|
Length parameter in microns. Default is 2.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 1.5.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 6.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is True.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
w_wg : float = 0.45,
|
|
w_cp : float = 0.45,
|
|
w_in : float = 0.45,
|
|
w_out : float = 2,
|
|
r_out : float = 6,
|
|
gap : float = 0.2,
|
|
theta_arc : float = 100,
|
|
Ls : float = 2,
|
|
xs_ring : str = "strip",
|
|
|
|
w_heater : float = 1.5,
|
|
xs_heater : str = "heater",
|
|
|
|
w_metal : float = 6,
|
|
xs_metal : str = "metal",
|
|
|
|
via_h2m: Any = None,
|
|
# sz_via_h2m : float = 0.25,
|
|
# sp_via_h2m : float = 0.4,
|
|
# xs_via_h2m : str = "via_h2m",
|
|
|
|
sharp_patch : bool = True,
|
|
show_pins : bool = True
|
|
) -> None:
|
|
'''
|
|
Initilization of SOCR.
|
|
|
|
Args:
|
|
- w_wg [um] Width of normal waveguide
|
|
- w_cp [um] Width of coupling waveguide
|
|
- w_in [um] Width of narrow waveugide
|
|
- w_out [um] Width of wider waveguide
|
|
- r_out [um] Outer radius
|
|
- gap [um] Gap of coupling region
|
|
- theta_arc [degree]Angle of coupling region
|
|
- Ls [um]
|
|
'''
|
|
self.res = 0.1
|
|
## Basic parameters
|
|
self.w_wg = w_wg
|
|
self.w_cp = w_cp
|
|
self.w_in = w_in
|
|
self.w_out = w_out
|
|
self.r_out = r_out
|
|
self.gap = gap
|
|
self.theta_arc = theta_arc
|
|
self.Ls = Ls
|
|
self.xs_ring = xs_ring
|
|
|
|
self.w_heater = w_heater
|
|
self.xs_heater = xs_heater
|
|
|
|
self.w_metal = w_metal
|
|
self.xs_metal = xs_metal
|
|
|
|
self.via_h2m = via_h2m
|
|
self.xs_via_h2m = self.via_h2m.xs
|
|
self.sz_via_h2m = self.via_h2m.sz[0]
|
|
self.sp_via_h2m = self.via_h2m.spacing[0]
|
|
try :
|
|
nd.get_xsection(self.xs_via_h2m)
|
|
except:
|
|
print("==Passive::rings::SOCR_Adiabatic::<xs_via_h2m>::",self.xs_via_h2m," not define in the tapeout.")
|
|
self.xs_via_h2m = None
|
|
|
|
self.sharp_patch = sharp_patch
|
|
self.show_pins = show_pins
|
|
## More parametes
|
|
self.r_in = self.r_out - (self.w_in+self.w_out)/2
|
|
self.delta = (self.w_out - self.w_in)/2
|
|
## Generate gds
|
|
self.cell_name = "SOCR_Adiabatic_Wcp%d_Win%d_Wout%.2f_G%.2f_R%d_Arc%d" %(
|
|
self.w_cp*1000, self.w_in*1000, self.w_out, self.gap, self.r_out, self.theta_arc
|
|
)
|
|
self.cell = self.generate_gds()
|
|
|
|
def generate_pic_part(self):
|
|
'''
|
|
Generate gds.
|
|
Return: Cell
|
|
'''
|
|
with nd.Cell(name=self.cell_name+"_pic",instantiate=False) as C:
|
|
## Generate the adiabatic ring
|
|
theta_list = np.linspace(0, 2*np.pi, int(self.r_out*2*np.pi/self.res)+1)
|
|
resonator_out = [(self.r_out*np.cos(theta), self.r_out*np.sin(theta)) for theta in theta_list]
|
|
resonator_in = [(self.r_in*np.cos(theta), -self.delta+self.r_in*np.sin(theta)) for theta in theta_list]
|
|
resonator_in.reverse()
|
|
poly_resonator = resonator_out + resonator_in
|
|
nd.Polygon(points=poly_resonator, layer=self.xs_ring.upper()+"_COR").put(0, 0)
|
|
# Add cladding if cladding layer exists
|
|
layer_cld_name = nd.get_layer(self.xs_ring.upper()+"_CLD")
|
|
# if layer_cld_name != "dump":
|
|
# r_cld_out = self.r_out + 2
|
|
# resonator_cld_out = [(r_cld_out*np.cos(theta), r_cld_out*np.sin(theta)) for theta in theta_list]
|
|
# r_cld_in = self.r_in - 2
|
|
# if r_cld_in < 1:
|
|
# resonator_cld_in = []
|
|
# else:
|
|
# resonator_cld_in = [(r_cld_in*np.cos(theta), -self.delta+r_cld_in*np.sin(theta)) for theta in theta_list]
|
|
# resonator_cld_in.reverse()
|
|
# resonator_cld_poly = resonator_cld_out + resonator_cld_in
|
|
# nd.Polygon(points=resonator_cld_poly, layer=self.xs_ring.upper()+"_CLD").put(0, 0)
|
|
for layers,growx,growy,acc in nd.layeriter(xs=self.xs_ring):
|
|
(a1,b1), (a2,b2),c1,c2 = growx
|
|
if b1!=0 and b2!=0 :
|
|
r_cld_out = self.r_out + b1
|
|
resonator_cld_out = [(r_cld_out*np.cos(theta), r_cld_out*np.sin(theta)) for theta in theta_list]
|
|
r_cld_in = self.r_in + b2
|
|
if r_cld_in < 1:
|
|
resonator_cld_in = []
|
|
else:
|
|
resonator_cld_in = [(r_cld_in*np.cos(theta), -self.delta+r_cld_in*np.sin(theta)) for theta in theta_list]
|
|
resonator_cld_in.reverse()
|
|
resonator_cld_poly = resonator_cld_out + resonator_cld_in
|
|
nd.Polygon(points=resonator_cld_poly, layer=layers).put(0, 0)
|
|
## Add input waveguide
|
|
wg = Route(width=self.w_cp, radius=5, xs=self.xs_ring)
|
|
wg.bend(radius=self.r_out+self.gap+self.w_cp/2, angle=self.theta_arc/2, arrow=False).put(0, -(self.r_out+self.gap+self.w_cp/2))
|
|
wg.strt(length=self.Ls, arrow=False).put()
|
|
# wg.strt(length=1, arrow=False).put()
|
|
wg.bend(angle=-self.theta_arc/2, arrow=False).put()
|
|
strt_out = wg.strt(length=1, arrow=False).put()
|
|
wg.taper(width1=self.w_cp, width2=self.w_wg, length=5, arrow=False).put()
|
|
wg_out = wg.strt(width=self.w_wg,length=0.5,arrow=False).put()
|
|
|
|
wg.bend(radius=self.r_out+self.gap+self.w_cp/2, angle=-self.theta_arc/2, arrow=False).put(0, -(self.r_out+self.gap+self.w_cp/2), 180)
|
|
wg.strt(length=self.Ls, arrow=False).put()
|
|
wg.bend(angle=self.theta_arc/2, arrow=False).put()
|
|
wg.strt(length=1, arrow=False).put()
|
|
wg.taper(width1=self.w_cp, width2=self.w_wg, length=4.5, arrow=False).put()
|
|
wg_in = wg.strt(width=self.w_wg,length=0.5,arrow=False).put()
|
|
## Add patch
|
|
if layer_cld_name != "dump":
|
|
# Vertical patch
|
|
x_min = r_cld_in
|
|
x_max = r_cld_out
|
|
y_min = 0
|
|
y_max = wg_in.pin['a0'].y + self.w_cp/2 + 2
|
|
rect_poly = [(x_min,y_min),(x_min,y_max),(x_max,y_max),(x_max,y_min)]
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0)
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0,flip=True)
|
|
# Horizontal patch
|
|
x_min = strt_out.pin['b0'].x
|
|
x_max = r_cld_in
|
|
y_min = strt_out.pin['b0'].y - self.w_cp/2 - 2
|
|
y_max = strt_out.pin['b0'].y + self.w_cp/2 + 2
|
|
rect_poly = [(x_min,y_min),(x_min,y_max),(x_max,y_max),(x_max,y_min)]
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0)
|
|
nd.Polygon(points=rect_poly, layer=layer_cld_name).put(0,0,flip=True)
|
|
## Add pins
|
|
nd.Pin(name="a1", width=self.w_wg).put(wg_in.pin['b0'])
|
|
nd.Pin(name="b1", width=self.w_wg).put(wg_out.pin['b0'])
|
|
if self.show_pins:
|
|
nd.put_stub()
|
|
self.cell = C
|
|
return C
|
|
|
|
def generate_eic_part(self):
|
|
with nd.Cell(name=self.cell_name+"_eic",instantiate=False) as C:
|
|
# Add heater
|
|
ring_x = 0
|
|
ring_y = -self.delta/2
|
|
ring_radius = (self.r_in*2+self.w_in/2+self.w_out/2)/2
|
|
ring_width = self.w_heater
|
|
theta_start = -30
|
|
theta_stop = 180+30
|
|
# n_points = int((theta_stop-theta_start)*2*np.pi/360 * ring_radius / self.res)
|
|
circle(radius=ring_radius, width=ring_width, theta_start=theta_start, theta_stop=theta_stop, res=self.res,
|
|
# n_points=n_points,
|
|
layer=self.xs_heater.upper()).cell.put(ring_x, ring_y)
|
|
# Add a broad region to connect heater with metal2
|
|
via_region_width = self.w_metal
|
|
r_below_point = [((ring_radius+ring_width/2) * np.cos(theta_start*np.pi/180)+ring_x,
|
|
(ring_radius+ring_width/2) * np.sin(theta_start*np.pi/180)+ring_y)]
|
|
r_up_point = [((ring_radius-ring_width/2) * np.cos(theta_start*np.pi/180)+ring_x,
|
|
(ring_radius-ring_width/2) * np.sin(theta_start*np.pi/180)+ring_y)]
|
|
heater_con_poly = r_up_point + r_below_point + [
|
|
(r_below_point[0][0], r_below_point[0][1]-2.2),
|
|
# (r_up_point[0][0]+via_region_width, r_below_point[0][1]-2.2),
|
|
(r_up_point[0][0], r_below_point[0][1]-2.2)
|
|
]
|
|
nd.Polygon(points=heater_con_poly, layer=self.xs_heater.upper()).put(0, 0)
|
|
nd.Polygon(points=heater_con_poly, layer=self.xs_heater.upper()).put(0, 0, flip=True)
|
|
# Add via
|
|
heater_wide_x = r_up_point[0][0] + via_region_width/2
|
|
heater_wide_y = -via_region_width/2 + r_below_point[0][1]-2.2
|
|
vias = Vias(
|
|
xs=self.xs_via_h2m,
|
|
area=[via_region_width, via_region_width],
|
|
sz=[self.sz_via_h2m, self.sz_via_h2m],
|
|
spacing=[self.sp_via_h2m, self.sp_via_h2m],
|
|
xs_l1=self.xs_heater,
|
|
xs_l2=self.xs_metal
|
|
)
|
|
vias.cell.put(heater_wide_x,heater_wide_y)
|
|
vias.cell.put(-heater_wide_x,heater_wide_y)
|
|
nd.Pin(name='ep1', width=via_region_width).put(-heater_wide_x, heater_wide_y, -90)
|
|
nd.Pin(name='en1', width=via_region_width).put(heater_wide_x, heater_wide_y, -90)
|
|
return C
|
|
|
|
def generate_gds(self):
|
|
return super().generate_gds()
|
|
|
|
class SOCR_Adiabatic_Cband(SOCR_Adiabatic):
|
|
"""
|
|
This is already designed SOCR at C-band.
|
|
|
|
Parameters
|
|
----------
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is True.
|
|
"""
|
|
|
|
def __init__(self, w_wg : float=0.45, via_h2m: Any = None, show_pins : bool = True) -> None:
|
|
super().__init__(
|
|
w_wg=w_wg,
|
|
w_cp=0.45, w_in=0.51, w_out=2, r_out=9, gap=0.2, theta_arc=120, Ls=1,
|
|
via_h2m=via_h2m,
|
|
show_pins=show_pins
|
|
)
|
|
|
|
class MRR_AED(AED_ring):
|
|
"""
|
|
MRR AED primitive component.
|
|
|
|
This component builds the MRR AED layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : Optional[str], optional
|
|
Unique identifier for the device cell. Default is None.
|
|
ORx : float, optional
|
|
Value for the ORx parameter. Default is 10.
|
|
ORy : float, optional
|
|
Value for the ORy parameter. Default is 10.
|
|
IRx : float, optional
|
|
Value for the IRx parameter. Default is 10 - 0.45.
|
|
IRy : float, optional
|
|
Value for the IRy parameter. Default is 10 - 0.5.
|
|
gap1 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
gap2 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w1_bus : float, optional
|
|
Value for the w1_bus parameter. Default is 0.45.
|
|
w2_bus : float, optional
|
|
Value for the w2_bus parameter. Default is 0.45.
|
|
R1_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
R2_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
A1_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
A2_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
offset_X : float, optional
|
|
Value for the offset_X parameter. Default is 0.
|
|
offset_Y : float, optional
|
|
Value for the offset_Y parameter. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R1_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
R1_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A1_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
A2_att : float, optional
|
|
Angle parameter in degrees. Default is 20.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
L_tilt : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
Euler_trasition : bool, optional
|
|
Value for the Euler_trasition parameter. Default is False.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is None.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is None.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
ht_notch_dual : bool, optional
|
|
Value for the ht_notch_dual parameter. Default is True.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self,
|
|
name: Optional[str] =None,
|
|
ORx: float=10,
|
|
ORy: float=10,
|
|
IRx: float=10-0.45,
|
|
IRy: float=10-0.5,
|
|
gap1: float=0.2,
|
|
gap2: float=0.2,
|
|
w1_bus: float=0.45,
|
|
w2_bus: float=0.45,
|
|
R1_cp: Any=None,
|
|
R2_cp: Any=None,
|
|
A1_cp: int=0,
|
|
A2_cp: int=0,
|
|
offset_X: float=0,
|
|
offset_Y: float=0,
|
|
w_wg: float=0.45,
|
|
R1_att: float = 20,
|
|
R2_att: float = 20,
|
|
R2_att_min: float = 10,
|
|
R1_att_min: float = 10,
|
|
A1_att: float = 30,
|
|
A2_att: float = 20,
|
|
Ltp_bus: int=10,
|
|
dL_p2p: Optional[float] = None,
|
|
L_tilt: int=10,
|
|
xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
Euler_trasition: bool=False,
|
|
|
|
show_pins: bool=False,
|
|
|
|
xs_heater : str = None,
|
|
w_heater : float = 0,
|
|
|
|
xs_metal : str = None,
|
|
w_metal : float = 0,
|
|
|
|
via_h2m: Any = None, ## input the class of the via
|
|
|
|
isl: Any = None, ## thermal isolation paramters
|
|
|
|
A_ht : float = 270,
|
|
ht_notch_dual: bool = True,
|
|
epin_dX: int = 0,
|
|
epin_dY: int = 0,
|
|
res: float = 0.05,
|
|
res_eic: float = 0.5,
|
|
ht_rot: bool = False,
|
|
) -> None:
|
|
|
|
|
|
super().__init__(name=None,
|
|
ORx=ORx,ORy=ORy,IRx=IRx,IRy=IRy,
|
|
gap1=gap1,gap2=gap2,w1_bus=w1_bus,w2_bus=w2_bus,
|
|
R1_cp=R1_cp,R2_cp=R2_cp,
|
|
A1_cp=A1_cp,A2_cp=A2_cp,
|
|
A1_att=A1_att,A2_att=A2_att,
|
|
R1_att=R1_att,R2_att=R2_att,
|
|
R1_att_min=R1_att_min,R2_att_min=R2_att_min,
|
|
offset_X=offset_X,offset_Y=offset_Y,
|
|
w_wg=w_wg,L_tilt=L_tilt,Ltp_bus=Ltp_bus,xs=xs_ring,
|
|
sharp_patch=sharp_patch,
|
|
cell_xs_transition = cell_xs_transition,
|
|
Euler_trasition=Euler_trasition,
|
|
res=res,show_pins=show_pins,dL_p2p=dL_p2p)
|
|
|
|
self.name = name
|
|
if (self.name==None):
|
|
self.instantiate = False
|
|
else :
|
|
self.instantiate = True
|
|
|
|
|
|
self.w_heater = w_heater
|
|
self.w_metal = w_metal
|
|
self.Rx = (ORx+IRx)/2
|
|
self.Ry = (ORy+IRy)/2
|
|
self.cell_eic=None
|
|
self.res_eic = res_eic
|
|
|
|
self.xs_heater = xs_heater
|
|
self.xs_metal = xs_metal
|
|
self.A_ht = A_ht
|
|
self.epin_dX = epin_dX
|
|
self.epin_dY = epin_dY
|
|
|
|
self.isl = isl
|
|
self.via_h2m = via_h2m
|
|
|
|
self.cell_pic = self.cell
|
|
|
|
self.ht_notch_dual = ht_notch_dual
|
|
## building electro part
|
|
xs_heater = __xs_exist__(xs=xs_heater,para_name="xs_heater",func_name="mxpic::passive::MRR_AED")
|
|
xs_metal = __xs_exist__(xs=xs_metal,para_name="xs_metal",func_name="mxpic::passive::MRR_AED")
|
|
|
|
|
|
if (w_heater>0 and xs_heater!=None and xs_metal!=None):
|
|
self.cell_eic = self.generate_eic_gds(show_pins=show_pins)
|
|
else :
|
|
self.cell_eic = None
|
|
|
|
|
|
if (self.cell_eic!=None and self.cell_pic!=None):
|
|
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
|
|
|
|
""" 2023.09.20 REVISED for 180 rotation of placing heaters """
|
|
if (ht_rot == False):
|
|
C_eic = self.cell_eic.put(0,0,0)
|
|
else:
|
|
C_eic = self.cell_eic.put(0,0,ht_rot)
|
|
|
|
C_pic = self.cell_pic.put(0,0,0)
|
|
|
|
## transporting pins
|
|
for str,Pin in C_eic.ic_pins():
|
|
nd.Pin(name=str,pin=Pin).put()
|
|
for str,Pin in C_pic.ic_pins():
|
|
nd.Pin(name=str,pin=Pin).put()
|
|
|
|
self.cell = C
|
|
|
|
elif (self.cell_eic==None and self.cell_pic!=None):
|
|
self.cell = self.cell_pic
|
|
|
|
|
|
def generate_eic_gds(self,
|
|
show_pins=False):
|
|
|
|
with nd.Cell(instantiate=False) as C:
|
|
|
|
w_pad = self.w_metal
|
|
|
|
## calculating the heater angle
|
|
if (self.w2_bus>0 and self.ht_notch_dual):
|
|
|
|
A_L = [-self.A_ht/4,self.A_ht/4]
|
|
else :
|
|
A_L = [90-self.A_ht/2,90]
|
|
|
|
|
|
|
|
""" Placing main heaters """
|
|
w_heater = self.w_heater
|
|
|
|
Elipse_dual(xs=self.xs_heater,ORy=self.Ry+w_heater/2,ORx=self.Rx+w_heater/2,IRx=self.Rx-w_heater/2,IRy=self.Ry-w_heater/2,
|
|
theta_start=A_L[0],theta_stop=A_L[1],
|
|
offset_X=self.offset_X,offset_Y=self.offset_Y,sharp_patch=False,res=self.res_eic,
|
|
).cell.put(0,0,0)
|
|
|
|
Elipse_dual(xs=self.xs_heater,ORy=self.Ry+w_heater/2,ORx=self.Rx+w_heater/2,IRx=self.Rx-w_heater/2,IRy=self.Ry-w_heater/2,
|
|
theta_start=180-A_L[1],theta_stop=180-A_L[0],
|
|
offset_X=self.offset_X,offset_Y=self.offset_Y,sharp_patch=False,res=self.res_eic,
|
|
).cell.put(0,0,0)
|
|
|
|
|
|
x_pad = self.Rx*np.cos(A_L[0]/180*np.pi)
|
|
y_pad = self.Ry*np.sin(A_L[0]/180*np.pi)
|
|
|
|
|
|
if (self.via_h2m==None):
|
|
vias = Vias(xs=None,area=[w_pad,w_pad],sz=0,spacing=0,xs_l1=self.xs_heater,xs_l2=self.xs_metal).cell ## only putting metal blocks
|
|
|
|
else:
|
|
if (hasattr(self.via_h2m,"cell")):
|
|
vias = self.via_h2m.cell
|
|
else :
|
|
vias = Vias(xs=self.via_h2m.xs,area=[w_pad,w_pad],sz=self.via_h2m.sz,spacing=self.via_h2m.spacing,xs_l1=self.xs_heater,xs_l2=self.xs_metal).cell ## placing vias
|
|
|
|
|
|
|
|
if (self.w2_bus >0 and self.ht_notch_dual):
|
|
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(-x_pad,-y_pad-w_heater/2,90)
|
|
att = nd.strt(xs=self.xs_heater,length=self.epin_dY,width=w_heater).put(-x_pad,-y_pad,90)
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(att.pin['b0'].x+w_heater/2,att.pin['b0'].y,180)
|
|
nd.strt(xs=self.xs_heater,length=self.epin_dX,width=w_heater).put(att.pin['b0'].x,att.pin['b0'].y,180)
|
|
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(x_pad,-y_pad-w_heater/2,90)
|
|
att = nd.strt(xs=self.xs_heater,length=self.epin_dY,width=w_heater).put(x_pad,-y_pad,90)
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(att.pin['b0'].x-w_heater/2,att.pin['b0'].y,0)
|
|
nd.strt(xs=self.xs_heater,length=self.epin_dX,width=w_heater).put(att.pin['b0'].x,att.pin['b0'].y,0)
|
|
|
|
V1 = vias.put(-x_pad-self.epin_dX,-y_pad+self.epin_dY,90)
|
|
V2 = vias.put( x_pad+self.epin_dX,-y_pad+self.epin_dY,90,flip=1)
|
|
|
|
dLVia = abs(V1.pin['b0'].x - V2.pin['b0'].x)+V1.pin['b0'].width/2+ V2.pin['b0'].width/2
|
|
nd.strt(length=dLVia,width=self.w_metal,xs=self.xs_metal).put(V1.pin['b0'].move(0, V1.pin['b0'].width/2,-90))
|
|
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(-x_pad,y_pad-w_heater/2,90)
|
|
att = nd.strt(xs=self.xs_heater,length=self.epin_dY,width=w_heater).put(-x_pad,y_pad,-90)
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(att.pin['b0'].x+w_heater/2,att.pin['b0'].y,180)
|
|
nd.strt(xs=self.xs_heater,length=self.epin_dX,width=w_heater).put(att.pin['b0'].x,att.pin['b0'].y,180)
|
|
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(x_pad,y_pad-w_heater/2,90)
|
|
att = nd.strt(xs=self.xs_heater,length=self.epin_dY,width=w_heater).put(x_pad,y_pad,-90)
|
|
nd.strt(xs=self.xs_heater,length=w_heater,width=w_heater).put(att.pin['b0'].x-w_heater/2,att.pin['b0'].y,0)
|
|
nd.strt(xs=self.xs_heater,length=self.epin_dX,width=w_heater).put(att.pin['b0'].x,att.pin['b0'].y,0)
|
|
|
|
if (self.epin_dX>0):
|
|
VIAL = vias.put(-x_pad-self.epin_dX,y_pad-self.epin_dY,180,flip=1)
|
|
VIAR = vias.put( x_pad+self.epin_dX,y_pad-self.epin_dY,0)
|
|
else :
|
|
|
|
VIAL = vias.put(-x_pad-self.epin_dX,y_pad-self.epin_dY,-90,flip=1)
|
|
VIAR = vias.put( x_pad+self.epin_dX,y_pad-self.epin_dY,-90)
|
|
|
|
nd.Pin(name='ep1',width=w_pad,pin=VIAL.pin['b0']).put()
|
|
nd.Pin(name='en1',width=w_pad,pin=VIAR.pin['b0']).put()
|
|
|
|
if (self.isl!=None):
|
|
if (self.w2_bus>0):
|
|
L_isl = np.abs(self.cell_pic.pin['a1'].y - self.cell_pic.pin['a2'].y) - self.isl.sp_isl_wg*2 - self.w_wg
|
|
|
|
else:
|
|
L_isl = np.abs(self.ORy - self.cell_pic.pin['a1'].y) - self.isl.sp_isl_wg - self.w_wg/2
|
|
|
|
y_isl = self.cell_pic.pin['a1'].y + self.isl.sp_isl_wg + self.w_wg/2
|
|
|
|
if (L_isl>self.isl.width):
|
|
x_isl = self.ORx+self.isl.sp_isl_metal+self.isl.width/2
|
|
ISL(xs=self.isl.xs,width=self.isl.width,length=L_isl,spacing=self.isl.spacing,Lmax=self.isl.Lmax).cell.put(-x_isl,y_isl,90)
|
|
ISL(xs=self.isl.xs,width=self.isl.width,length=L_isl,spacing=self.isl.spacing,Lmax=self.isl.Lmax).cell.put( x_isl,y_isl,90)
|
|
|
|
if (show_pins):
|
|
nd.put_stub()
|
|
|
|
return C
|
|
|
|
class MRR_STD_Ring(MRR_AED) :
|
|
|
|
"""
|
|
MRR STD Ring primitive component.
|
|
|
|
This component builds the MRR STD Ring layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : Optional[str], optional
|
|
Unique identifier for the device cell. Default is None.
|
|
r_ring : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
w_ring : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
gap1 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
gap2 : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w1_bus : float, optional
|
|
Value for the w1_bus parameter. Default is 0.45.
|
|
w2_bus : float, optional
|
|
Value for the w2_bus parameter. Default is 0.
|
|
R1_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
R2_cp : Any, optional
|
|
Radius parameter in microns. Default is None.
|
|
A1_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
A2_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
offset_X : float, optional
|
|
Value for the offset_X parameter. Default is 0.
|
|
offset_Y : float, optional
|
|
Value for the offset_Y parameter. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R1_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R2_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
R1_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A1_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
A2_att : float, optional
|
|
Angle parameter in degrees. Default is 20.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
L_tilt : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
Euler_trasition : bool, optional
|
|
Value for the Euler_trasition parameter. Default is False.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
ht_notch_dual : bool, optional
|
|
Value for the ht_notch_dual parameter. Default is False.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self,
|
|
name: Optional[str]=None,
|
|
r_ring: float=10,
|
|
w_ring: float=0.45,
|
|
gap1: float=0.2,
|
|
gap2: float=0.2,
|
|
w1_bus: float=0.45,
|
|
w2_bus: float=0,
|
|
R1_cp: Any=None,
|
|
R2_cp: Any=None,
|
|
A1_cp: int=0,
|
|
A2_cp: int=0,
|
|
offset_X: float=0,
|
|
offset_Y: float=0,
|
|
w_wg: float=0.45,
|
|
R1_att: float = 20,
|
|
R2_att: float = 20,
|
|
R2_att_min: float = 10,
|
|
R1_att_min: float = 10,
|
|
A1_att: float = 30,
|
|
A2_att: float = 20,
|
|
Ltp_bus: int = 10,
|
|
dL_p2p: Optional[float]=None,
|
|
L_tilt: int=10,
|
|
xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
Euler_trasition: bool=False,
|
|
show_pins: bool=False, xs_heater: str = 'heater',
|
|
w_heater: float = 0, xs_metal: str = 'metal',
|
|
w_metal: float = 0,
|
|
via_h2m: Any = None,
|
|
isl: Any = None,
|
|
A_ht: float = 270, ht_notch_dual: bool = False, epin_dX: int=0, epin_dY: int=0,
|
|
res: float = 0.05,
|
|
res_eic: float = 0.5,
|
|
ht_rot: bool=False) -> None:
|
|
"""_summary_
|
|
|
|
Args:
|
|
name (_type_, optional): Name of the device. Defaults to None.
|
|
r_ring (int, optional): Central radius of the ring . Defaults to 10.
|
|
w_ring (float, optional): Width of the ring. Defaults to 0.45.
|
|
gap1 (float, optional): Gap distnace of the lower bus waveguide and the ring. Defaults to 0.2.
|
|
gap2 (float, optional): Gap distnace of the upper bus waveguide and the ring. Defaults to 0.2.
|
|
w1_bus (float, optional): Width of the lower bus waveguide. Defaults to 0.45.
|
|
w2_bus (int, optional): Width of the upper bus waveguide. Defaults to 0.
|
|
R1_cp (_type_, optional): Radius of the bus 1, used in asymmetric coupling. Defaults to None.
|
|
R2_cp (_type_, optional): Radius of the bus 1, used in asymmetric coupling. Defaults to None.
|
|
A1_cp (int, optional): Coupling angle for lower bus. Defaults to 0.
|
|
A2_cp (int, optional): Coupling angle for upper bus. Defaults to 0.
|
|
offset_X (int, optional): Inner and outer circle offset in X. Defaults to 0.
|
|
offset_Y (int, optional): Inner and outer circle offset in Y. Defaults to 0.
|
|
w_wg (float, optional): Width of the input and output waveguide. Defaults to 0.45.
|
|
R1_att (float, optional): Attached bend radius of the IO port, lower waveguide. Defaults to 20.
|
|
R2_att (float, optional): Attached bend radius of the IO port, lower waveguide. Defaults to 20.
|
|
R2_att_min (float, optional): Attached minimum bend radius of the IO port, lower waveguide. Defaults to 10.
|
|
R1_att_min (float, optional): _description_. Defaults to 10.
|
|
A1_att (float, optional): _description_. Defaults to 30.
|
|
A2_att (float, optional): _description_. Defaults to 20.
|
|
Ltp_bus (int, optional): _description_. Defaults to 10.
|
|
dL_p2p (_type_, optional): _description_. Defaults to None.
|
|
L_tilt (int, optional): _description_. Defaults to 10.
|
|
xs_ring (str, optional): _description_. Defaults to 'strip'.
|
|
sharp_patch (bool, optional): _description_. Defaults to True.
|
|
Euler_trasition (bool, optional): _description_. Defaults to False.
|
|
show_pins (bool, optional): _description_. Defaults to False.
|
|
xs_heater (str, optional): _description_. Defaults to 'heater'.
|
|
w_heater (float, optional): _description_. Defaults to 0.
|
|
xs_metal (str, optional): _description_. Defaults to 'metal'.
|
|
w_metal (float, optional): _description_. Defaults to 0.
|
|
via_h2m (_type_, optional): _description_. Defaults to None.
|
|
isl (_type_, optional): _description_. Defaults to None.
|
|
A_ht (float, optional): _description_. Defaults to 270.
|
|
ht_notch_dual (bool, optional): _description_. Defaults to True.
|
|
epin_dX (int, optional): _description_. Defaults to 0.
|
|
epin_dY (int, optional): _description_. Defaults to 0.
|
|
res (float, optional): _description_. Defaults to 0.05.
|
|
res_eic (float, optional): _description_. Defaults to 0.5.
|
|
"""
|
|
|
|
ORx = r_ring + w_ring/2
|
|
ORy = r_ring + w_ring/2
|
|
IRx = r_ring - w_ring/2
|
|
IRy = r_ring - w_ring/2
|
|
|
|
self.r_ring = r_ring
|
|
self.w_ring = w_ring
|
|
|
|
super().__init__(name,ORx, ORy, IRx, IRy, gap1, gap2,
|
|
w1_bus, w2_bus, R1_cp, R2_cp, A1_cp, A2_cp,
|
|
offset_X, offset_Y, w_wg,
|
|
R1_att, R2_att, R2_att_min, R1_att_min,
|
|
A1_att, A2_att, Ltp_bus, dL_p2p,
|
|
L_tilt, xs_ring, sharp_patch, cell_xs_transition,
|
|
Euler_trasition,
|
|
show_pins,
|
|
xs_heater=xs_heater,
|
|
w_heater=w_heater,
|
|
xs_metal=xs_metal,
|
|
w_metal=w_metal,
|
|
via_h2m=via_h2m,
|
|
isl=isl,
|
|
A_ht=A_ht, ht_notch_dual=ht_notch_dual, epin_dX=epin_dX, epin_dY=epin_dY,
|
|
res=res,res_eic=res_eic,ht_rot=ht_rot)
|
|
|
|
""" Simplified classed for Standard ring """
|
|
class MRR_STD_Allpass(MRR_STD_Ring):
|
|
"""
|
|
MRR STD Allpass primitive component.
|
|
|
|
This component builds the MRR STD Allpass layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Unique identifier for the device cell.
|
|
r_ring : float
|
|
Radius parameter in microns.
|
|
w_ring : float
|
|
Width parameter in microns.
|
|
gap : float
|
|
Spacing or gap parameter in microns.
|
|
w_bus : float
|
|
Width parameter in microns.
|
|
A_cp : Any
|
|
Angle parameter in degrees.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
L_tilt : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self, name: str,
|
|
r_ring: float,
|
|
w_ring: float,
|
|
gap: float,
|
|
w_bus: float,
|
|
A_cp: Any,
|
|
w_wg: float=0.45,
|
|
R_att: float = 20,
|
|
Ltp_bus: int=10,
|
|
dL_p2p: Optional[float]=None,
|
|
L_tilt: int=10,
|
|
xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
show_pins: bool=False,
|
|
xs_heater: str = 'heater',
|
|
w_heater: float = 0,
|
|
xs_metal: str = 'metal',
|
|
w_metal: float = 0,
|
|
via_h2m: Any =None,
|
|
isl: Any =None,
|
|
A_ht: float = 270,
|
|
epin_dX: int=0,
|
|
epin_dY: int=0,
|
|
res: float=0.05,
|
|
res_eic: float=0.5,ht_rot: bool=False) -> None:
|
|
"""_summary_
|
|
|
|
Args:
|
|
name (_type_): _description_
|
|
r_ring (int, optional): Central radius of the ring . Defaults to 10.
|
|
w_ring (float, optional): Width of the ring. Defaults to 0.45.
|
|
gap (float, optional): Gap distnace of the bus waveguide and the ring. Defaults to 0.2.
|
|
w_bus (float, optional): Width of the bus waveguide. Defaults to 0.45.
|
|
A_cp (_type_): Angle of coupling, can be 0.
|
|
w_wg (float, optional): Width of the IO port. Defaults to 0.45.
|
|
R_att (float, optional): Radius of the anti-direction bend after bend coupling. Defaults to 20.
|
|
Ltp_bus (int, optional): Length of taper for transision from w_bus to w_wg. Defaults to 10.
|
|
dL_p2p (_type_, optional): _description_. Defaults to None.
|
|
L_tilt (int, optional): Length of the tilt transision from bend coupling to anti-direction bend. Defaults to 10.
|
|
xs_ring (str, optional): xsection of ring. Defaults to 'strip'.
|
|
sharp_patch (bool, optional): Flag to add sharp angle patch. Defaults to True.
|
|
show_pins (bool, optional): Flag of displaying pins. Defaults to False.
|
|
xs_heater (str, optional): Xsection of heaters. Defaults to 'heater'.
|
|
w_heater (float, optional): Width of the main heater. Defaults to 0.
|
|
xs_metal (str, optional): Xsection of metal. Defaults to 'metal'.
|
|
w_metal (float, optional): Width of the output metal width. Defaults to 0.
|
|
via_h2m (_type_, optional): Class of via from heater to metal. Defaults to None.
|
|
isl (_type_, optional): Class of isolation trench. Defaults to None.
|
|
A_ht (float, optional): Angle of heater. Defaults to 270.
|
|
epin_dX (int, optional): Heater epitaxy in X for connection. Defaults to 0.
|
|
epin_dY (int, optional): Heater epitaxy in Y for connection. Defaults to 0.
|
|
res (float, optional): Waveguide resolution. Defaults to 0.05.
|
|
res_eic (float, optional): Electrical resolution. Defaults to 0.5.
|
|
"""
|
|
self.r_ring = r_ring
|
|
self.w_ring = w_ring
|
|
super().__init__(name=name,
|
|
r_ring=r_ring, w_ring=w_ring,
|
|
gap1=gap,
|
|
gap2=0, ## coupler 2 not used
|
|
w1_bus=w_bus,
|
|
w2_bus=0, ## coupler 2 not used
|
|
R1_cp=None,
|
|
R2_cp=None,
|
|
A1_cp=A_cp,
|
|
A2_cp=0,
|
|
offset_X=0,
|
|
offset_Y=0, w_wg=w_wg,
|
|
R1_att=R_att,
|
|
R2_att=R_att,
|
|
R2_att_min=R_att,
|
|
R1_att_min=R_att,
|
|
A1_att=10,
|
|
A2_att=10,
|
|
Ltp_bus=Ltp_bus,
|
|
dL_p2p=dL_p2p,
|
|
L_tilt=L_tilt,
|
|
xs_ring=xs_ring,
|
|
sharp_patch=sharp_patch,
|
|
cell_xs_transition=cell_xs_transition,
|
|
Euler_trasition=False,
|
|
show_pins=show_pins,
|
|
xs_heater=xs_heater,
|
|
w_heater=w_heater,
|
|
xs_metal=xs_metal,
|
|
w_metal=w_metal,
|
|
via_h2m = via_h2m,
|
|
isl = isl,
|
|
A_ht=A_ht,
|
|
ht_notch_dual=False,
|
|
epin_dX=epin_dX,
|
|
epin_dY=epin_dY,
|
|
res=res,
|
|
res_eic=res_eic,
|
|
ht_rot=ht_rot)
|
|
|
|
class MRR_STD_Adddrop(MRR_STD_Ring):
|
|
"""
|
|
MRR STD Adddrop primitive component.
|
|
|
|
This component builds the MRR STD Adddrop layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Unique identifier for the device cell.
|
|
r_ring : float
|
|
Radius parameter in microns.
|
|
w_ring : float
|
|
Width parameter in microns.
|
|
gap : float
|
|
Spacing or gap parameter in microns.
|
|
w_bus : float
|
|
Width parameter in microns.
|
|
A_cp : Any
|
|
Angle parameter in degrees.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
L_tilt : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self, name: str,
|
|
r_ring: float,
|
|
w_ring: float,
|
|
gap: float,
|
|
w_bus: float,
|
|
A_cp: Any,
|
|
w_wg: float=0.45,
|
|
R_att: float = 20,
|
|
Ltp_bus: int=10,
|
|
dL_p2p: Optional[float]=None,
|
|
L_tilt: int=10,
|
|
xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
show_pins: bool=False,
|
|
xs_heater: str = 'heater',
|
|
w_heater: float = 0,
|
|
xs_metal: str = 'metal',
|
|
w_metal: float = 0,
|
|
via_h2m: Any = None,
|
|
isl: Any = None,
|
|
A_ht: float = 270,
|
|
epin_dX: int=0,
|
|
epin_dY: int=0,
|
|
res: float = 0.05,
|
|
res_eic: float = 0.5,
|
|
ht_rot: bool=False) -> None:
|
|
|
|
self.r_ring = r_ring
|
|
self.w_ring = w_ring
|
|
super().__init__(name=name,
|
|
r_ring=r_ring, w_ring=w_ring,
|
|
gap1=gap,
|
|
gap2=gap, ## coupler 2 not used
|
|
w1_bus=w_bus,
|
|
w2_bus=w_bus, ## coupler 2 not used
|
|
R1_cp=None,
|
|
R2_cp=None,
|
|
A1_cp=A_cp,
|
|
A2_cp=A_cp,
|
|
offset_X=0,
|
|
offset_Y=0, w_wg=w_wg,
|
|
R1_att=R_att,
|
|
R2_att=R_att,
|
|
R2_att_min=R_att,
|
|
R1_att_min=R_att,
|
|
A1_att=10,
|
|
A2_att=10,
|
|
Ltp_bus=Ltp_bus,
|
|
dL_p2p=dL_p2p,
|
|
L_tilt=L_tilt,
|
|
xs_ring=xs_ring,
|
|
sharp_patch=sharp_patch,
|
|
cell_xs_transition=cell_xs_transition,
|
|
Euler_trasition=False,
|
|
show_pins=show_pins,
|
|
xs_heater=xs_heater,
|
|
w_heater=w_heater,
|
|
xs_metal=xs_metal,
|
|
w_metal=w_metal,
|
|
via_h2m = via_h2m,
|
|
isl = isl,
|
|
|
|
A_ht=A_ht,
|
|
ht_notch_dual=False,
|
|
epin_dX=epin_dX,
|
|
epin_dY=epin_dY,
|
|
res=res,
|
|
res_eic=res_eic,
|
|
ht_rot=ht_rot)
|
|
|
|
""" Multimode ring simplified """
|
|
class MRR_MM_Allpass(MRR_STD_Ring):
|
|
"""
|
|
MRR MM Allpass primitive component.
|
|
|
|
This component builds the MRR MM Allpass layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : Optional[str], optional
|
|
Unique identifier for the device cell. Default is None.
|
|
r_ring : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
w_ring : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
gap : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w_bus : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
A_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self, name: Optional[str]=None,
|
|
r_ring: float=10,
|
|
w_ring: float=0.45,
|
|
gap: float=0.2,
|
|
w_bus: float=0.45,
|
|
A_cp: int=0,
|
|
w_wg: float=0.45,
|
|
R_att: float = 20,
|
|
R_att_min: float = 10,
|
|
A_att: float = 30,
|
|
Ltp_bus: int=10,
|
|
dL_p2p: Optional[float]=None,
|
|
xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
show_pins: bool=False,
|
|
xs_heater: str = 'heater',
|
|
w_heater: float = 0,
|
|
xs_metal: str = 'metal',
|
|
w_metal: float = 0,
|
|
via_h2m: Any=None,
|
|
isl: Any=None,
|
|
A_ht: float = 270,
|
|
epin_dX: int=0,
|
|
epin_dY: int=0,
|
|
res: float = 0.05,
|
|
res_eic: float = 0.5,
|
|
ht_rot: bool=False) -> None:
|
|
"""_summary_
|
|
|
|
Args:
|
|
|
|
R_att (float, optional): The attached radius for the anti-attaching. Defaults to 20.
|
|
R_att_min (float, optional): The minimum radius for the angti-attaching, due to euler transision. Defaults to 10.
|
|
A_att (float, optional): The angle of the Euler transision. Defaults to 30.
|
|
|
|
"""
|
|
self.r_ring = r_ring
|
|
self.w_ring = w_ring
|
|
super().__init__(name,
|
|
r_ring=r_ring,
|
|
w_ring=w_ring,
|
|
gap1=gap,
|
|
gap2=0,
|
|
w1_bus=w_bus,
|
|
w2_bus=0,
|
|
R1_cp=None,
|
|
R2_cp=None,
|
|
A1_cp=A_cp,
|
|
A2_cp=0,
|
|
offset_X=0,
|
|
offset_Y=0,
|
|
w_wg=w_wg,
|
|
R1_att=R_att,
|
|
R2_att=R_att,
|
|
R2_att_min=R_att_min,
|
|
R1_att_min=R_att_min,
|
|
A1_att=A_att, A2_att=A_att,
|
|
Ltp_bus=Ltp_bus,
|
|
dL_p2p=dL_p2p,
|
|
L_tilt=0,
|
|
xs_ring=xs_ring,
|
|
sharp_patch=sharp_patch,
|
|
cell_xs_transition = cell_xs_transition, Euler_trasition=True,
|
|
show_pins=show_pins,
|
|
xs_heater=xs_heater,
|
|
w_heater=w_heater,
|
|
xs_metal=xs_metal,
|
|
w_metal=w_metal,
|
|
via_h2m=via_h2m,
|
|
isl=isl,
|
|
A_ht=A_ht,
|
|
ht_notch_dual=False,
|
|
epin_dX=epin_dX,
|
|
epin_dY=epin_dY,res=res,
|
|
res_eic=res_eic,
|
|
ht_rot=ht_rot)
|
|
|
|
class MRR_MM_Adddrop(MRR_STD_Ring):
|
|
"""
|
|
MRR MM Adddrop primitive component.
|
|
|
|
This component builds the MRR MM Adddrop layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : Optional[str], optional
|
|
Unique identifier for the device cell. Default is None.
|
|
r_ring : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
w_ring : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
gap : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w_bus : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
A_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self, name: Optional[str]=None,
|
|
r_ring: float=10,
|
|
w_ring: float=0.45,
|
|
gap: float=0.2,
|
|
w_bus: float=0.45,
|
|
A_cp: int=0,
|
|
w_wg: float=0.45,
|
|
R_att: float = 20,
|
|
R_att_min: float = 10,
|
|
A_att: float = 30,
|
|
Ltp_bus: int=10,
|
|
dL_p2p: Optional[float]=None,
|
|
xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
show_pins: bool=False,
|
|
xs_heater: str = 'heater',
|
|
w_heater: float = 0,
|
|
xs_metal: str = 'metal',
|
|
w_metal: float = 0,
|
|
via_h2m: Any=None,
|
|
isl: Any=None,
|
|
A_ht: float = 270,
|
|
epin_dX: int=0,
|
|
epin_dY: int=0,
|
|
res: float = 0.05,
|
|
res_eic: float = 0.5,
|
|
ht_rot: bool=False) -> None:
|
|
|
|
self.r_ring = r_ring
|
|
self.w_ring = w_ring
|
|
|
|
super().__init__(name,
|
|
r_ring=r_ring,
|
|
w_ring=w_ring,
|
|
gap1=gap,
|
|
gap2=gap,
|
|
w1_bus=w_bus,
|
|
w2_bus=w_bus,
|
|
R1_cp=None,
|
|
R2_cp=None,
|
|
A1_cp=A_cp,
|
|
A2_cp=A_cp,
|
|
offset_X=0,
|
|
offset_Y=0,
|
|
w_wg=w_wg,
|
|
R1_att=R_att,
|
|
R2_att=R_att,
|
|
R2_att_min=R_att_min,
|
|
R1_att_min=R_att_min,
|
|
A1_att=A_att, A2_att=A_att,
|
|
Ltp_bus=Ltp_bus,
|
|
dL_p2p=dL_p2p,
|
|
L_tilt=0,
|
|
xs_ring=xs_ring,
|
|
sharp_patch=sharp_patch,
|
|
cell_xs_transition = cell_xs_transition,
|
|
Euler_trasition=True,
|
|
show_pins=show_pins,
|
|
xs_heater=xs_heater,
|
|
w_heater=w_heater,
|
|
xs_metal=xs_metal,
|
|
w_metal=w_metal,
|
|
via_h2m=via_h2m,
|
|
isl=isl,
|
|
A_ht=A_ht,
|
|
ht_notch_dual=True,
|
|
epin_dX=epin_dX,
|
|
epin_dY=epin_dY,
|
|
res=res,
|
|
res_eic=res_eic,
|
|
ht_rot=ht_rot)
|
|
|
|
""" Dual width controled ring with Euler shape coupler """
|
|
class MRR_DW_Adddrop(MRR_AED):
|
|
"""
|
|
MRR DW Adddrop primitive component.
|
|
|
|
This component builds the MRR DW Adddrop layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Unique identifier for the device cell.
|
|
r_ring : float
|
|
Radius parameter in microns.
|
|
w0_ring : float
|
|
Value for the w0_ring parameter.
|
|
w1_ring : float
|
|
Value for the w1_ring parameter.
|
|
gap : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w_bus : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
A_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self, name: str,
|
|
r_ring: float,
|
|
w0_ring: float,
|
|
w1_ring: float,
|
|
|
|
gap: float=0.2,
|
|
w_bus: float=0.45,
|
|
A_cp: int=0,
|
|
w_wg: float=0.45,
|
|
R_att: float = 20,
|
|
R_att_min: float = 10,
|
|
A_att: float = 30,
|
|
Ltp_bus: int=10, dL_p2p: Optional[float]=None, xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
show_pins: bool=False,
|
|
xs_heater: str = "heater",
|
|
w_heater: float = 0,
|
|
xs_metal: str = "metal",
|
|
w_metal: float = 0,
|
|
via_h2m: Any=None,
|
|
isl: Any=None,
|
|
A_ht: float = 270,
|
|
epin_dX: int=0,
|
|
epin_dY: int=0,
|
|
res: float=0.05,
|
|
res_eic: float=0.5,
|
|
ht_rot: bool=False) -> None:
|
|
|
|
ORx = r_ring + w1_ring/2
|
|
ORy = r_ring + w0_ring/2
|
|
IRx = r_ring - w1_ring/2
|
|
IRy = r_ring - w0_ring/2
|
|
|
|
self.r_ring = r_ring
|
|
self.w0_ring = w0_ring
|
|
self.w1_ring = w1_ring
|
|
|
|
super().__init__(name, ORx=ORx, ORy=ORy, IRx=IRx, IRy=IRy,
|
|
gap1=gap, gap2=gap, w1_bus=w_bus, w2_bus=w_bus, R1_cp=None, R2_cp=None, A1_cp=A_cp, A2_cp=A_cp,
|
|
offset_X=0, offset_Y=0,
|
|
w_wg=w_wg,
|
|
R1_att=R_att, R2_att=R_att, R2_att_min=R_att_min, R1_att_min=R_att_min,
|
|
A1_att=A_att, A2_att=A_att,
|
|
Ltp_bus=Ltp_bus,
|
|
dL_p2p=dL_p2p,
|
|
L_tilt=0,
|
|
xs_ring=xs_ring,
|
|
sharp_patch=sharp_patch,
|
|
cell_xs_transition = cell_xs_transition,
|
|
Euler_trasition=True,
|
|
show_pins=show_pins,
|
|
xs_heater=xs_heater,
|
|
w_heater=w_heater,
|
|
xs_metal=xs_metal,
|
|
w_metal=w_metal,
|
|
via_h2m=via_h2m,
|
|
isl=isl,
|
|
A_ht=A_ht,
|
|
ht_notch_dual=False,
|
|
epin_dX=epin_dX, epin_dY=epin_dY, res=res, res_eic=res_eic,ht_rot=ht_rot)
|
|
|
|
class MRR_DW_Allpass(MRR_AED):
|
|
"""
|
|
MRR DW Allpass primitive component.
|
|
|
|
This component builds the MRR DW Allpass layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : str
|
|
Unique identifier for the device cell.
|
|
r_ring : float
|
|
Radius parameter in microns.
|
|
w0_ring : float
|
|
Value for the w0_ring parameter.
|
|
w1_ring : float
|
|
Value for the w1_ring parameter.
|
|
gap : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
w_bus : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
A_cp : int, optional
|
|
Angle parameter in degrees. Default is 0.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
R_att : float, optional
|
|
Radius parameter in microns. Default is 20.
|
|
R_att_min : float, optional
|
|
Radius parameter in microns. Default is 10.
|
|
A_att : float, optional
|
|
Angle parameter in degrees. Default is 30.
|
|
Ltp_bus : int, optional
|
|
Length parameter in microns. Default is 10.
|
|
dL_p2p : Optional[float], optional
|
|
Value for the dL_p2p parameter. Default is None.
|
|
xs_ring : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
cell_xs_transition : Any, optional
|
|
Cell or component dependency used by this device. Default is None.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 0.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
A_ht : float, optional
|
|
Angle parameter in degrees. Default is 270.
|
|
epin_dX : int, optional
|
|
Value for the epin_dX parameter. Default is 0.
|
|
epin_dY : int, optional
|
|
Value for the epin_dY parameter. Default is 0.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.05.
|
|
res_eic : float, optional
|
|
Value for the res_eic parameter. Default is 0.5.
|
|
ht_rot : bool, optional
|
|
Value for the ht_rot parameter. Default is False.
|
|
"""
|
|
def __init__(self, name: str,
|
|
r_ring: float,
|
|
w0_ring: float,
|
|
w1_ring: float,
|
|
|
|
gap: float=0.2,
|
|
w_bus: float=0.45,
|
|
A_cp: int=0,
|
|
w_wg: float=0.45,
|
|
R_att: float = 20,
|
|
R_att_min: float = 10,
|
|
A_att: float = 30,
|
|
Ltp_bus: int=10, dL_p2p: Optional[float]=None, xs_ring: str='strip',
|
|
sharp_patch: bool=True,
|
|
cell_xs_transition: Any=None,
|
|
show_pins: bool=False,
|
|
xs_heater: str = "heater",
|
|
w_heater: float = 0,
|
|
xs_metal: str = "metal",
|
|
w_metal: float = 0,
|
|
via_h2m: Any=None,
|
|
isl: Any=None,
|
|
A_ht: float = 270,
|
|
epin_dX: int=0,
|
|
epin_dY: int=0,
|
|
res: float=0.05,
|
|
res_eic: float=0.5,
|
|
ht_rot: bool=False) -> None:
|
|
|
|
ORx = r_ring + w1_ring/2
|
|
ORy = r_ring + w0_ring/2
|
|
IRx = r_ring - w1_ring/2
|
|
IRy = r_ring - w0_ring/2
|
|
|
|
self.r_ring = r_ring
|
|
self.w0_ring = w0_ring
|
|
self.w1_ring = w1_ring
|
|
|
|
super().__init__(name, ORx=ORx, ORy=ORy, IRx=IRx, IRy=IRy,
|
|
gap1=gap, gap2=0, w1_bus=w_bus, w2_bus=0, R1_cp=None, R2_cp=None, A1_cp=A_cp, A2_cp=A_cp,
|
|
offset_X=0, offset_Y=0,
|
|
w_wg=w_wg,
|
|
R1_att=R_att, R2_att=R_att, R2_att_min=R_att_min, R1_att_min=R_att_min,
|
|
A1_att=A_att, A2_att=A_att,
|
|
Ltp_bus=Ltp_bus,
|
|
dL_p2p=dL_p2p,
|
|
L_tilt=0,
|
|
xs_ring=xs_ring,
|
|
sharp_patch=sharp_patch,
|
|
cell_xs_transition = cell_xs_transition,
|
|
Euler_trasition=True,
|
|
show_pins=show_pins,
|
|
xs_heater=xs_heater,
|
|
w_heater=w_heater,
|
|
xs_metal=xs_metal,
|
|
w_metal=w_metal,
|
|
via_h2m=via_h2m,
|
|
isl=isl,
|
|
A_ht=A_ht,
|
|
ht_notch_dual=False,
|
|
epin_dX=epin_dX, epin_dY=epin_dY, res=res, res_eic=res_eic,ht_rot=ht_rot)
|
|
|
|
|
|
""" NEW CLASS: 2023.03.21"""
|
|
class STD_ring_AMZI_adddrop:
|
|
"""
|
|
STD ring AMZI adddrop primitive component.
|
|
|
|
This component builds the STD ring AMZI adddrop layout cell.
|
|
|
|
Parameters
|
|
----------
|
|
name : Optional[str], optional
|
|
Unique identifier for the device cell. Default is None.
|
|
r_ring : float, optional
|
|
Radius parameter in microns. Default is 30.
|
|
w_ring : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
w_wg : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
xs_wg : str, optional
|
|
Layer or cross-section name used by the device. Default is 'strip'.
|
|
w_bus : float, optional
|
|
Width parameter in microns. Default is 0.45.
|
|
gap : float, optional
|
|
Spacing or gap parameter in microns. Default is 0.2.
|
|
dAc : float, optional
|
|
Value for the dAc parameter. Default is 10.
|
|
L_tilt : int, optional
|
|
Length parameter in microns. Default is 1.
|
|
dL_arm : float, optional
|
|
Value for the dL_arm parameter. Default is 10.
|
|
w_heater : float, optional
|
|
Width parameter in microns. Default is 2.5.
|
|
xs_heater : str, optional
|
|
Layer or cross-section name used by the device. Default is 'heater'.
|
|
w_metal : float, optional
|
|
Width parameter in microns. Default is 6.
|
|
xs_metal : str, optional
|
|
Layer or cross-section name used by the device. Default is 'metal'.
|
|
via_h2m : Any, optional
|
|
Via definition used between heater and metal layers. Default is None.
|
|
isl : Any, optional
|
|
Isolation-trench definition used by the electrical layout. Default is None.
|
|
res : float, optional
|
|
Value for the res parameter. Default is 0.1.
|
|
R_bend : int, optional
|
|
Radius parameter in microns. Default is 10.
|
|
L_tp : int, optional
|
|
Length parameter in microns. Default is 5.
|
|
show_pins : bool, optional
|
|
Whether to draw pin markers in the generated layout. Default is False.
|
|
sharp_patch : bool, optional
|
|
Whether to add geometry patches for sharp corners or cladding continuity. Default is True.
|
|
"""
|
|
def __init__(self,
|
|
name: Optional[str]=None,
|
|
r_ring: float = 30,
|
|
w_ring: float = 0.45,
|
|
w_wg: float = 0.45,
|
|
xs_wg: str='strip',
|
|
w_bus: float=0.45,
|
|
gap: float=0.2,
|
|
dAc: float=10,
|
|
L_tilt: int=1,
|
|
dL_arm: float=10,
|
|
w_heater: float=2.5,
|
|
xs_heater: str='heater',
|
|
w_metal: float=6,
|
|
xs_metal: str='metal',
|
|
|
|
via_h2m: Any = None,
|
|
isl: Any = None,
|
|
|
|
res: float = 0.1,
|
|
R_bend: int=10,
|
|
L_tp: int = 5,
|
|
show_pins: bool=False,
|
|
sharp_patch: bool=True,
|
|
) -> None:
|
|
self.name=name
|
|
if (name==None):
|
|
self.instantiate = False
|
|
else :
|
|
self.instantiate = True
|
|
self.r_ring = r_ring
|
|
self.w_ring = w_ring
|
|
self.w_wg = w_wg
|
|
self.xs_wg = xs_wg
|
|
self.w_bus = w_bus
|
|
self.gap = gap
|
|
self.dAc = dAc
|
|
self.L_tilt = L_tilt
|
|
self.dL_arm = dL_arm
|
|
self.w_heater = w_heater
|
|
self.xs_heater = xs_heater
|
|
self.w_metal = w_metal
|
|
self.xs_metal = xs_metal
|
|
|
|
self.via_h2m = via_h2m
|
|
self.isl = isl
|
|
|
|
self.res = res
|
|
self.R_bend=R_bend
|
|
self.L_tp = L_tp
|
|
|
|
self.cell = self.generate_gds(sharp_patch=sharp_patch,show_pins=show_pins)
|
|
|
|
def generate_gds(self,show_pins,sharp_patch):
|
|
with nd.Cell(name=self.name,instantiate=self.instantiate) as C:
|
|
|
|
R_cp=self.r_ring+self.gap+self.w_bus/2+self.w_ring/2
|
|
|
|
circle(radius=self.r_ring,width=self.w_ring,theta_start=0,theta_stop=360,res=self.res,xs=self.xs_wg,sharp_patch=sharp_patch).cell.put(0,0,0)
|
|
wg_cp = ring_bus_wg(xs=self.xs_wg,R_cp=R_cp,
|
|
w_bus=self.w_bus,bend_DC=True,w_wg=self.w_wg,
|
|
dAc=self.dAc,
|
|
euler_anti_bend=False,
|
|
euler_transistion=False,
|
|
dL_trans=self.L_tilt,res=self.res,
|
|
R_max_anti=self.R_bend,R_min_anti=self.R_bend,
|
|
A_anti=self.dAc/2+45,wg_Ltp=self.L_tp,dL_p2p=None,sharp_patch=sharp_patch)
|
|
|
|
cp_U = wg_cp.cell.put(0,R_cp,0,flip=1)
|
|
cp_D = wg_cp.cell.put(0,-R_cp,0)
|
|
cp_L = wg_cp.cell.put(-R_cp,0,-90)
|
|
cp_R = wg_cp.cell.put( R_cp,0,-90,flip=1)
|
|
|
|
pic_strip = Route(radius=self.R_bend,width=self.w_wg,xs=self.xs_wg)
|
|
|
|
|
|
nd.Pin(name='a2',pin=cp_D.pin['a1']).put()
|
|
nd.Pin(name='a1',pin=cp_L.pin['b1']).put()
|
|
nd.Pin(name='b2',pin=cp_R.pin['a1']).put()
|
|
nd.Pin(name='b1',pin=cp_U.pin['b1']).put()
|
|
|
|
x_BOX = abs(cp_D.pin['a1'].x - cp_R.pin['a1'].x)*np.sqrt(2)
|
|
y_BOX = abs(cp_D.pin['a1'].y - cp_R.pin['a1'].y)*np.sqrt(2)
|
|
|
|
if (sharp_patch):
|
|
nd.strt(layer="STRIP_CLD",length=x_BOX/2,width=y_BOX).put(0,0,45)
|
|
nd.strt(layer="STRIP_CLD",length=x_BOX/2,width=y_BOX).put(0,0,225)
|
|
|
|
""" Generating of EIC parts """
|
|
if (self.via_h2m==None):
|
|
via = Vias(xs=None,area=self.w_metal,sz=0,spacing=0,xs_l1=self.xs_heater,xs_l2=self.xs_metal).cell ## only putting metal blocks
|
|
|
|
else:
|
|
if (hasattr(self.via_h2m,"cell")):
|
|
via = self.via_h2m.cell
|
|
else :
|
|
via = Vias(xs=self.via_h2m.xs,area=self.w_metal,sz=self.via_h2m.sz,spacing=self.via_h2m.spacing,xs_l1=self.xs_heater,xs_l2=self.xs_metal).cell ## placing vias
|
|
|
|
eic_dL = 0.5
|
|
HT_UR = circle(radius=self.r_ring,width=self.w_heater,xs=self.xs_heater,theta_stop=90,res=eic_dL).cell.put(0,0,0)
|
|
HT_DL = circle(radius=self.r_ring,width=self.w_heater,xs=self.xs_heater,theta_stop=90,res=eic_dL).cell.put(0,0,180)
|
|
|
|
# via = Vias(xs=self.xs_via_h2m,xs_l1=self.xs_metal,xs_l2=self.xs_heater,sz=self.sz_via_h2m,spacing=self.sp_via_h2m,area=self.w_metal).cell
|
|
|
|
V1_UR = via.put(HT_UR.pin['a1'].x,HT_UR.pin['a1'].y,45)
|
|
V2_UR = via.put(HT_UR.pin['b1'].x,HT_UR.pin['b1'].y,45)
|
|
|
|
V1_DL = via.put(HT_DL.pin['a1'].x,HT_DL.pin['a1'].y,45)
|
|
V2_DL = via.put(HT_DL.pin['b1'].x,HT_DL.pin['b1'].y,45)
|
|
|
|
eic_m = Route(radius=self.w_metal/2,width=self.w_metal,xs=self.xs_metal,PCB=True)
|
|
|
|
eic_m.sbend_p2p(pin1=V2_UR.pin['a0'],pin2=V2_DL.pin['a0'].move(0,0,180),Lstart=abs(V2_UR.pin['a0'].y-V2_DL.pin['a0'].y)/np.sqrt(2)/2 - self.w_metal/2).put()
|
|
|
|
nd.Pin(name='en1',pin=V1_UR.pin['b0']).put()
|
|
nd.Pin(name='ep1',pin=V1_DL.pin['a0']).put()
|
|
|
|
""" Generating the heaters for MZI part """
|
|
uoffst = np.sqrt(abs(cp_U.pin['a1'].x - cp_L.pin['a1'].x)**2 + abs(cp_U.pin['a1'].y - cp_L.pin['a1'].y)**2)
|
|
HT = waveguide(w_heater=self.w_heater,xs_heater=self.xs_heater,
|
|
via_h2m=self.via_h2m,
|
|
isl = self.isl,
|
|
|
|
shape='ubend',
|
|
w_metal=self.w_metal,xs_metal=self.xs_metal,
|
|
R_bend=self.R_bend,
|
|
ubend_offset=uoffst,
|
|
L_wg=self.dL_arm+uoffst+(np.pi-2)*self.R_bend,
|
|
|
|
L_heater=uoffst+(np.pi-2)*self.R_bend+self.dL_arm/2)
|
|
HT_U = HT.cell.put('a1',cp_L.pin['a1'])
|
|
HT_D = HT.cell.put('a1',cp_R.pin['b1'])
|
|
|
|
nd.Pin(name='ep2',pin=HT_U.pin['ep1'].move(0,0,90)).put()
|
|
nd.Pin(name='en2',pin=HT_U.pin['en1'].move(0,0,-90)).put()
|
|
|
|
nd.Pin(name='en3',pin=HT_D.pin['ep1'].move(0,0,90)).put()
|
|
nd.Pin(name='ep3',pin=HT_D.pin['en1'].move(0,0,-90)).put()
|
|
|
|
|
|
if (show_pins):
|
|
nd.put_stub()
|
|
return C
|