Files

1569 lines
70 KiB
Python

from typing import Any, Optional
from operator import add
import nazca as nd
import numpy as np
from ...electronics.eic_units import Vias_arc
from ..pic.taper import taper_xs2xs
from ...geometry import *
import nazca.interconnects as IC
class Route(IC.Interconnect):
pass
# from ...routing import *
from ..pic import *
from ...electronics import Vias
from ..passive.rings import MRR_STD_Ring,MRR_AED
from ...basic import __list_convert__,__array_convert__
""" This is used within the situation that double side is the same, and concentric coupling """
""" Refreshed 2023.09.14 """
class AED_Ring_PIN(MRR_AED): ## Finished in 2022.11.23
"""
AED Ring PIN primitive component.
This component builds the AED Ring PIN 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 9.
IRx : float, optional
Value for the IRx parameter. Default is 10 - 0.65.
IRy : float, optional
Value for the IRy parameter. Default is 9 - 0.4.
gap : float, optional
Spacing or gap parameter in microns. Default is 0.2.
dual_BUS : bool, optional
Value for the dual_BUS parameter. Default is False.
w_bus : float, optional
Width parameter in microns. Default is 0.45.
R_cp : Any, optional
Radius parameter in microns. Default is None.
A_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.
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.
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.
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 8.
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_ht_dX : int, optional
Value for the epin_ht_dX parameter. Default is 10.
epin_ht_dY : int, optional
Value for the epin_ht_dY parameter. Default is 3.
via_i2m : Any, optional
Via definition used between implant and metal layers. Default is None.
xs_metal_imp : str, optional
Layer or cross-section name used by the device. Default is 'metal'.
xs_p : str, optional
Layer or cross-section name used by the device. Default is 'p'.
xs_n : str, optional
Layer or cross-section name used by the device. Default is 'n'.
xs_cont_wg : Optional[str], optional
Layer or cross-section name used by the device. Default is None.
w_p : float, optional
Width parameter in microns. Default is 3.0.
gap_p_i : float, optional
Spacing or gap parameter in microns. Default is 1.
gap_n_i : float, optional
Spacing or gap parameter in microns. Default is 1.
w_n : float, optional
Width parameter in microns. Default is 3.0.
offset_i : float, optional
Value for the offset_i parameter. Default is 0.
A_imp_in : int, optional
Angle parameter in degrees. Default is 180.
A_imp_out : int, optional
Angle parameter in degrees. Default is 180.
sp_cont : float, optional
Spacing or gap parameter in microns. Default is 0.2.
w_ovlp : float, optional
Width parameter in microns. Default is 0.1.
bus_dopping : bool, optional
Value for the bus_dopping parameter. Default is True.
p_in_n_out : bool, optional
Value for the p_in_n_out parameter. Default is False.
cell_xs_transition : Any, optional
Cell or component dependency used by this device. Default is None.
"""
def __init__(self,
name: Optional[str]=None,
ORx: float=10,
ORy: float=9,
IRx: float=10 - 0.65,
IRy: float=9 - 0.40,
gap: float=0.2,
dual_BUS: bool=False,
w_bus: float=0.45,
R_cp: Any=None,
A_cp: int=0,
offset_X: float=0, offset_Y: float=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,
L_tilt: int=10,
xs_ring: str='strip', sharp_patch: bool=True,
Euler_trasition: bool=False,
show_pins: bool=False,
xs_heater: str = 'heater', w_heater: float = 0,
xs_metal: str = 'metal', w_metal: float = 8,
via_h2m: Any = None,
isl: Any = None,
A_ht: float = 270,
ht_notch_dual: bool = True,
epin_ht_dX: int = 10,
epin_ht_dY: int = 3,
via_i2m: Any = None,
xs_metal_imp: str = 'metal', ## metal connect to implemetation
xs_p: str = 'p',
xs_n: str = 'n',
xs_cont_wg: Optional[str] = None,
w_p: float = 3.0,
gap_p_i: float = 1,
gap_n_i: float = 1,
w_n: float = 3.0,
offset_i: float = 0,
A_imp_in: int = 180,
A_imp_out: int = 180,
## REVISED in 2023.09.20, contact doping merged into xs_p and xs_n
# xs_pcont = 'pp',
# xs_ncont = 'np',
# w_pcont = 3.0,
# w_ncont = 3.0,
sp_cont: float = 0.2,
w_ovlp: float = 0.1, ## overlapping area for doping
bus_dopping: bool = True,
p_in_n_out: bool=False, ## default , p-outside n-inside
cell_xs_transition: Any = None,
) -> None:
self.name = name
if (name == None):
self.instantiate = False
else :
self.instantiate = True
gap1 = gap
gap2 = 0
w1_bus = w_bus
w2_bus = 0
R1_cp = R_cp
R2_cp = 0
A1_cp = A_cp
A2_cp = 0
R1_att = R_att
R2_att = 0
R1_att_min = R_att_min
R2_att_min = 0
A1_att = A_att
A2_att = 0
if (dual_BUS==True):
gap2=gap
w2_bus=w_bus
R2_cp=R_cp
A2_cp=A_cp
R2_att=R_att
R2_att_min=R_att_min
A2_att=A_att
self.epin_ht_dY = epin_ht_dY
self.xs_metal_imp = xs_metal_imp
if (via_i2m!=None):
self.via_i2m = via_i2m
else :
raise Exception("ERROR : In <mxpic::active::AED_Ring_PIN>, <via_i2m> cannot be none")
self.xs_cont_wg = xs_cont_wg
self.dL_p2p = dL_p2p
self.xs_p = __list_convert__(xs_p,'xs_p','mxpic::active::rings')
self.xs_n = __list_convert__(xs_n,'xs_n','mxpic::active::rings')
self.w_p = __array_convert__(w_p,'w_p','mxpic::active::rings')
self.w_n = __array_convert__(w_n,'w_n','mxpic::active::rings')
if (p_in_n_out): ## P in N out
self.A_imp_in = __array_convert__(A_imp_in,'A_imp_in','mxpic::active::rings',num=len(self.xs_p))
self.A_imp_out = __array_convert__(A_imp_out,'A_imp_out','mxpic::active::rings',num=len(self.xs_n))
else : ## P out N in
self.A_imp_in = __array_convert__(A_imp_in,'A_imp_in','mxpic::active::rings',num=len(self.xs_n))
self.A_imp_out = __array_convert__(A_imp_out,'A_imp_out','mxpic::active::rings',num=len(self.xs_p))
if (len(self.w_p) != len(self.xs_p)) :
raise Exception("ERROR: in <mxpic::active::rings>, <xs_p> and <w_p> not same dimension")
if (len(self.w_n) != len(self.xs_n)) :
raise Exception("ERROR: in <mxpic::active::rings>, <xs_n> and <w_n> not same dimension")
if (len(self.A_imp_out) != len(self.xs_n)) :
raise Exception("ERROR: in <mxpic::active::rings>, <A_imp_out> and <xs_n> not same dimension")
if (len(self.A_imp_in) != len(self.xs_n)) :
raise Exception("ERROR: in <mxpic::active::rings>, <A_imp_in> and <xs_n> not same dimension")
self.gap_p_i = gap_p_i
self.gap_n_i = gap_n_i
# self.xs_pcont = xs_pcont
# self.xs_ncont = xs_ncont
# self.w_pcont = w_pcont
# self.w_ncont = w_ncont
self.sp_cont = sp_cont
self.w_ovlp = w_ovlp
self.bus_dopping = bus_dopping
self.offset_i = offset_i
self.p_in_n_out = p_in_n_out
super().__init__(name=name,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,
offset_X=offset_X, offset_Y=offset_Y, w_wg=w_wg,
R1_att=R1_att, R2_att=R2_att, R2_att_min=R2_att_min, R1_att_min=R1_att_min, A1_att=A1_att, A2_att=A2_att,
Ltp_bus=Ltp_bus, dL_p2p=dL_p2p,
L_tilt=L_tilt, xs_ring=xs_ring, sharp_patch=sharp_patch,
Euler_trasition=Euler_trasition,
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=ht_notch_dual, epin_dX=epin_ht_dX, epin_dY=epin_ht_dY,
cell_xs_transition=cell_xs_transition)
if (name is not None):
name_full = self.name + "_cell"
else:
name_full = None
self.cell_imp = self.generate_imp_gds()
self.cell_passive = self.cell
if (self.cell_imp!=None):
with nd.Cell(name=name_full,instantiate=self.instantiate) as C:
C_all = self.cell.put()
C_imp = self.cell_imp.put(0,0,0)
C_imp.raise_pins()
C_all.raise_pins()
if (show_pins):
nd.put_stub()
self.cell = C
def generate_imp_gds(self):
with nd.Cell(instantiate=False) as C:
""" Considering the reverse of the PN of inner and outer """
wx = self.ORx - self.IRx
wy = self.ORy - self.IRy
eic_dL = 1
""" P out N in // p_in_n_out = False // default """
if (self.p_in_n_out==False):
ORx_out = self.ORx+self.gap_p_i+np.cumsum(self.w_p)
IRx_out = self.ORx+self.gap_p_i+np.cumsum(self.w_p) - self.w_p
ORy_out = self.ORy+self.gap_p_i+np.cumsum(self.w_p)
IRy_out = self.ORy+self.gap_p_i+np.cumsum(self.w_p) - self.w_p
ORx_in = self.IRx-self.gap_n_i-np.cumsum(self.w_n) + self.w_n
IRx_in = self.IRx-self.gap_n_i-np.cumsum(self.w_n)
ORy_in = self.IRy-self.gap_n_i-np.cumsum(self.w_n) + self.w_n
IRy_in = self.IRy-self.gap_n_i-np.cumsum(self.w_n)
xs_out = self.xs_p
xs_in = self.xs_n
xs_cont_out = self.xs_p[-1]
xs_cont_in = self.xs_n[-1]
w_cont_out = self.w_p[-1]
w_cont_in = self.w_n[-1]
# print("P out N in")
else :
""" P in N out // p_in_n_out = True // default """
ORx_out = self.ORx+self.gap_n_i+np.cumsum(self.w_n)
IRx_out = self.ORx+self.gap_n_i+np.cumsum(self.w_n) - self.w_n
ORy_out = self.ORy+self.gap_n_i+np.cumsum(self.w_n)
IRy_out = self.ORy+self.gap_n_i+np.cumsum(self.w_n) - self.w_n
ORx_in = self.IRx-self.gap_p_i-np.cumsum(self.w_p) + self.w_p
IRx_in = self.IRx-self.gap_p_i-np.cumsum(self.w_p)
ORy_in = self.IRy-self.gap_p_i-np.cumsum(self.w_p) + self.w_p
IRy_in = self.IRy-self.gap_p_i-np.cumsum(self.w_p)
xs_out = self.xs_n
xs_in = self.xs_p
xs_cont_out = self.xs_n[-1]
xs_cont_in = self.xs_p[-1]
w_cont_out = self.w_n[-1]
w_cont_in = self.w_p[1]
""" Calculation of the angle of the ring """
if (self.w2_bus>0):
A_in = np.c_[-self.A_imp_in/4,self.A_imp_in/4]
A_out = np.c_[-self.A_imp_out/4,self.A_imp_out/4]
else :
A_in = np.c_[90-self.A_imp_in/2,90*np.ones(np.shape(self.A_imp_in))]
A_out = np.c_[90-self.A_imp_out/2,90*np.ones(np.shape(self.A_imp_in))]
for idx in range(0,len(ORx_out)):
if (idx!=0):
ovlp = self.w_ovlp
else :
ovlp = 0
IMP_LO = Elipse_dual(ORx=ORx_out[idx]+ovlp/2,ORy=ORy_out[idx]+ovlp/2,IRx=IRx_out[idx]-ovlp/2,IRy=IRy_out[idx]-ovlp/2,
xs=xs_out[idx],theta_start=180-A_out[idx,1],theta_stop=180-A_out[idx,0],res=eic_dL,
).cell.put(0,0,0)
IMP_LI = Elipse_dual(ORx=ORx_in[idx]+ovlp/2,ORy=ORy_in[idx]+ovlp/2,IRx=IRx_in[idx]-ovlp/2,IRy=IRy_in[idx]-ovlp/2,res=eic_dL,
xs=xs_in[idx],theta_start=180-A_in[idx,1],theta_stop=180-A_in[idx,0],
).cell.put(0,self.offset_Y,0)
IMP_RO = Elipse_dual(ORx=ORx_out[idx]+ovlp/2,ORy=ORy_out[idx]+ovlp/2,IRx=IRx_out[idx]-ovlp/2,IRy=IRy_out[idx]-ovlp/2,res=eic_dL,
xs=xs_out[idx],theta_start=A_out[idx,0],theta_stop=A_out[idx,1],
).cell.put(0,0,0)
IMP_RI = Elipse_dual(ORx=ORx_in[idx]+ovlp/2,ORy=ORy_in[idx]+ovlp/2,IRx=IRx_in[idx]-ovlp/2,IRy=IRy_in[idx]-ovlp/2,res=eic_dL,
xs=xs_in[idx],theta_start=A_in[idx,0],theta_stop=A_in[idx,1],
).cell.put(0,self.offset_Y,0)
R_cont_out = max(np.r_[ORx_out[-1],ORy_out[-1]])-w_cont_out/2
R_cont_in = min(np.r_[IRx_in,IRy_in])+w_cont_in/2
""" Vias for ouside connenction """
ovlp = self.w_ovlp
## complemented with elipse and spacing
""" To ensure the upper part is connected """
if (self.w2_bus == 0):
A_comp_out = [ np.arctan(ORy_out[-1]/ORx_out[-1]*np.tan(A_out[-1,0]/180*pi))/pi*180 + self.sp_cont/R_cont_out/pi*180,
np.arctan(ORy_out[-1]/ORx_out[-1]*np.tan(A_out[-1,1]/180*pi))/pi*180]
else :
A_comp_out = [ np.arctan(ORy_out[-1]/ORx_out[-1]*np.tan(A_out[-1,0]/180*pi))/pi*180 + self.sp_cont/R_cont_out/pi*180,
np.arctan(ORy_out[-1]/ORx_out[-1]*np.tan(A_out[-1,1]/180*pi))/pi*180 - self.sp_cont/R_cont_out/pi*180]
if (abs(A_in[0,0]) == 90):
""" To ensure the inner ring is connected """
A_comp_in = [ np.arctan(IRy_in[-1]/IRx_in[-1]*np.tan(A_in[0,0]/180*pi))/pi*180,
np.arctan(IRy_in[-1]/IRx_in[-1]*np.tan(A_in[0,1]/180*pi))/pi*180]
else :
A_comp_in = [ np.arctan(IRy_in[-1]/IRx_in[-1]*np.tan(A_in[0,0]/180*pi))/pi*180 + self.sp_cont/R_cont_in/pi*180,
np.arctan(IRy_in[-1]/IRx_in[-1]*np.tan(A_in[0,1]/180*pi))/pi*180 - self.sp_cont/R_cont_in/pi*180]
eic_mt = Route(radius=(w_cont_out/2-self.sp_cont)+ovlp/2,PCB=True,width=w_cont_out-self.sp_cont*2+ovlp,xs=self.xs_metal_imp)
VIA_LO = Vias_arc(R=R_cont_out,w=w_cont_out-self.sp_cont*2+ovlp,
xs=self.via_i2m.xs,
spacing=self.via_i2m.spacing,
sz=self.via_i2m.sz,
xs_l1=self.via_i2m.xs_l1,
xs_l2=self.via_i2m.xs_l2,
via_cell=self.via_i2m.via,
sp_via_xs=self.via_i2m.sp_via_xs,
theta_start=180-A_comp_out[1],res=eic_dL,
theta_stop=180-A_comp_out[0],).cell.put(0,0,0)
VIA_LI = Vias_arc(R=R_cont_in,w=w_cont_in-self.sp_cont*2+ovlp,
xs=self.via_i2m.xs,
spacing=self.via_i2m.spacing,
sz=self.via_i2m.sz,
xs_l1=self.via_i2m.xs_l1,
xs_l2=self.via_i2m.xs_l2,
via_cell=self.via_i2m.via,
sp_via_xs=self.via_i2m.sp_via_xs,
theta_start=180-A_comp_in[1],theta_stop=180-A_comp_in[0]).cell.put(0,self.offset_Y,0)
VIA_RO = Vias_arc(R=R_cont_out,w=w_cont_out-self.sp_cont*2+ovlp,
xs=self.via_i2m.xs,
spacing=self.via_i2m.spacing,
sz=self.via_i2m.sz,
xs_l1=self.via_i2m.xs_l1,
xs_l2=self.via_i2m.xs_l2,
via_cell=self.via_i2m.via,
sp_via_xs=self.via_i2m.sp_via_xs,
theta_start=A_comp_out[0],theta_stop=A_comp_out[1]).cell.put(0,0,0)
VIA_RI = Vias_arc(R=R_cont_in,w=w_cont_in-self.sp_cont*2+ovlp,
xs=self.via_i2m.xs,
spacing=self.via_i2m.spacing,
sz=self.via_i2m.sz,
xs_l1=self.via_i2m.xs_l1,xs_l2=self.via_i2m.xs_l2,
via_cell=self.via_i2m.via,
sp_via_xs=self.via_i2m.sp_via_xs,
theta_start=A_comp_in[0],theta_stop=A_comp_in[1]).cell.put(0,self.offset_Y,0)
nd.Pin(name='ep2').put(0,self.offset_Y,-90)
# metal connection
if (A_in[-1,1]<90):
circle(radius=R_cont_in,width=w_cont_in,xs=self.xs_metal_imp,
theta_start=A_comp_in[1],theta_stop=180-A_comp_in[1],res=eic_dL,
# n_points=64
).cell.put(0,self.offset_Y,0)
# if (A_out[1]<90):
# circle(radius=R_cont_out,width=w_cont_out,xs=self.xs_metal_imp,
# theta_start=A_out[1],theta_stop=180-A_out[1],n_points=64).cell.put(0,0,0)
## adding the central metal
if (R_cont_in<self.w_metal*2):
circle(radius=R_cont_in/2,width=R_cont_in,xs=self.xs_metal_imp,
theta_start=0,theta_stop=360,res=eic_dL,
# n_points=128
).cell.put(0,self.offset_Y,0)
else :
nd.strt(width=self.w_metal,length=R_cont_in*2,xs=self.xs_metal_imp).put(-R_cont_in,self.offset_Y,0)
# print(R_cont_in,w_cont_in,self.sp_cont)
# print((R_cont_in+w_cont_in/2-self.sp_cont)*(R_cont_in+w_cont_in/2-self.sp_cont))
# print((R_cont_in-w_cont_in/2+self.sp_cont)*(R_cont_in-w_cont_in/2+self.sp_cont))
# print((R_cont_in+w_cont_in/2-self.sp_cont)*(R_cont_in+w_cont_in/2-self.sp_cont) - (R_cont_in-w_cont_in/2+self.sp_cont)*(R_cont_in-w_cont_in/2+self.sp_cont))
# w1_mt = 2*np.sqrt((R_cont_in+w_cont_in/2-self.sp_cont)*(R_cont_in+w_cont_in/2-self.sp_cont) - (R_cont_in-w_cont_in/2+self.sp_cont)*(R_cont_in-w_cont_in/2+self.sp_cont))
# nd.taper(width1=w1_mt,
# width2=self.w_metal,
# length=w_cont_in+self.w_metal,xs=self.xs_metal_imp).put(-R_cont_in+w_cont_in/2-self.sp_cont,self.offset_Y,0)
# nd.taper(width1=w1_mt,
# width2=self.w_metal,
# length=w_cont_in+self.w_metal,xs=self.xs_metal_imp).put(R_cont_in-w_cont_in/2+self.sp_cont,self.offset_Y,180)
if (self.xs_cont_wg != None):
CONT_LO = Elipse_dual(ORx=R_cont_out+w_cont_out/2+ovlp/2,ORy=R_cont_out+w_cont_out/2+ovlp/2,
IRx=R_cont_out-w_cont_out/2-ovlp/2,IRy=R_cont_out-w_cont_out/2-ovlp/2,
xs=self.xs_cont_wg,theta_start=180-A_out[-1,1],theta_stop=180-A_out[-1,0],res=eic_dL,
sharp_patch=False,
# n_points=64
).cell.put(0,0,0)
CONT_LI = Elipse_dual(ORx=R_cont_in+ovlp/2+w_cont_in/2,ORy=R_cont_in+ovlp/2+w_cont_in/2,
IRx=R_cont_in-ovlp/2-w_cont_in/2,IRy=R_cont_in-ovlp/2-w_cont_in/2,
xs=self.xs_cont_wg,theta_start=180-A_in[-1,1],theta_stop=180-A_in[-1,0],res=eic_dL,
# n_points=64
sharp_patch=False,
).cell.put(0,self.offset_Y,0)
CONT_RO = Elipse_dual(ORx=R_cont_out+w_cont_out/2+ovlp/2,ORy=R_cont_out+w_cont_out/2+ovlp/2,
IRx=R_cont_out-w_cont_out/2-ovlp/2,IRy=R_cont_out-w_cont_out/2-ovlp/2,
xs=self.xs_cont_wg,theta_start=A_out[-1,0],theta_stop=A_out[-1,1],res=eic_dL,
# n_points=64
sharp_patch=False,
).cell.put(0,0,0)
CONT_RI = Elipse_dual(ORx=R_cont_in+ovlp/2+w_cont_in/2,ORy=R_cont_in+ovlp/2+w_cont_in/2,
IRx=R_cont_in-ovlp/2-w_cont_in/2,IRy=R_cont_in-ovlp/2-w_cont_in/2,
xs=self.xs_cont_wg,theta_start=A_in[-1,0],theta_stop=A_in[-1,1],res=eic_dL,
# n_points=64
sharp_patch=False,
).cell.put(0,self.offset_Y,0)
if (self.bus_dopping):
""" Implantation for bus waveguide """
y_cp = -(self.ORy+self.gap1+self.w1_bus/2)
for idx in range(0,len(ORx_out)):
w_imp_bus = ORy_out[idx]-IRy_out[idx]
if (idx==0):
Y = y_cp-self.w1_bus/2-(IRy_out[idx]-self.ORy)-w_imp_bus/2
else :
Y = Y-w_imp_bus/2
BUS_IMP = ring_bus_wg(xs=xs_out[idx], R_cp=self.R1_cp,
w_bus=w_imp_bus+ovlp,bend_DC=True, w_wg=w_imp_bus+ovlp, dAc=self.A1_cp,
w_trans=w_imp_bus+ovlp,
euler_anti_bend=self.Euler_trasition,euler_transistion=self.Euler_trasition,
R_max_trans=self.R1_att,dA_trans=self.A1_att,dL_trans=self.L_tilt,
R_max_anti=self.R1_att,R_min_anti=self.R1_att_min,
sharp_patch=False,show_pins=False,
wg_Ltp=self.Ltp_bus,res=eic_dL,
dL_p2p=self.dL_p2p)
INSTR = BUS_IMP.cell.put(0,Y)
Y = Y-w_imp_bus/2
Y = Y+w_cont_out/2
if (self.xs_cont_wg != None):
BUS_CONT = ring_bus_wg(xs=self.xs_cont_wg, R_cp=self.R1_cp,
w_bus=w_cont_out+ovlp,bend_DC=True, w_wg=w_cont_out+ovlp, dAc=self.A1_cp,
w_trans=w_cont_out+ovlp,
euler_anti_bend=self.Euler_trasition,euler_transistion=self.Euler_trasition,
R_max_trans=self.R1_att,dA_trans=self.A1_att,dL_trans=self.L_tilt,
R_max_anti=self.R1_att,R_min_anti=self.R1_att_min,
sharp_patch=False,show_pins=False,res=eic_dL,
wg_Ltp=self.Ltp_bus,
dL_p2p=self.dL_p2p).cell.put(0,Y)
BUS_VIA_L = Vias(xs=self.via_i2m.xs,area=[self.w_metal,BUS_IMP.w_wg-self.sp_cont*2],
xs_l1=self.via_i2m.xs_l1,
xs_l2=self.via_i2m.xs_l2,
sz=self.via_i2m.sz,
spacing=self.via_i2m.spacing,
sp_via_xs=self.via_i2m.sp_via_xs,
instantiate=self.via_i2m.instantiate,
## revised in 2026.06.07 by Qin Yue
# legacy: ).cell.put(INSTR.pin['a1'].x+self.w_metal/2+self.sp_cont,INSTR.pin['a1'].y,180)
).cell.put(INSTR.pin['opt_a1'].x+self.w_metal/2+self.sp_cont,INSTR.pin['opt_a1'].y,180)
BUS_VIA_R = Vias(xs=self.via_i2m.xs,area=[self.w_metal,BUS_IMP.w_wg-self.sp_cont*2],
xs_l1=self.via_i2m.xs_l1,
xs_l2=self.via_i2m.xs_l2,
sz=self.via_i2m.sz,
spacing=self.via_i2m.spacing,
sp_via_xs=self.via_i2m.sp_via_xs,
instantiate=self.via_i2m.instantiate,
## revised in 2026.06.07 by Qin Yue
# legacy: ).cell.put(INSTR.pin['b1'].x-self.w_metal/2-self.sp_cont,INSTR.pin['b1'].y)
).cell.put(INSTR.pin['opt_b1'].x-self.w_metal/2-self.sp_cont,INSTR.pin['opt_b1'].y)
## revised in 2026.06.07 by Qin Yue
# legacy: if (abs(BUS_VIA_L.pin['a0'].x) > abs(VIA_LO.pin['b1'].x)):
## revised in 2026.06.07 by Qin Yue
# legacy: if (abs(BUS_VIA_L.pin['a0'].x) > abs(VIA_LO.pin['opt_b1'].x)):
if (abs(BUS_VIA_L.pin['a0'].x) > abs(VIA_LO.pin['ele_b1'].x)):
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_LO.pin['b1'],angle=360-VIA_LO.pin['b1'].a,arrow=False).put(flip=0)
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_LO.pin['opt_b1'],angle=360-VIA_LO.pin['opt_b1'].a,arrow=False).put(flip=0)
temp = eic_mt.bend(pin=VIA_LO.pin['ele_b1'],angle=360-VIA_LO.pin['ele_b1'].a,arrow=False).put(flip=0)
eic_mt.ubend_p2p(pin2=BUS_VIA_L.pin['a0'],arrow=False).put()
else :
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin1=VIA_LO.pin['b1'],pin2=BUS_VIA_L.pin['a0'].move(0,0,90),arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin1=VIA_LO.pin['opt_b1'],pin2=BUS_VIA_L.pin['a0'].move(0,0,90),arrow=False).put()
eic_mt.strt_bend_strt_p2p(pin1=VIA_LO.pin['ele_b1'],pin2=BUS_VIA_L.pin['a0'].move(0,0,90),arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: if (abs(BUS_VIA_R.pin['a0'].x) > abs(VIA_RO.pin['a1'].x)):
## revised in 2026.06.07 by Qin Yue
# legacy: if (abs(BUS_VIA_R.pin['a0'].x) > abs(VIA_RO.pin['opt_a1'].x)):
if (abs(BUS_VIA_R.pin['a0'].x) > abs(VIA_RO.pin['ele_a1'].x)):
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_RO.pin['a1'],angle=VIA_RO.pin['a1'].a-180,arrow=False).put(flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_RO.pin['opt_a1'],angle=VIA_RO.pin['opt_a1'].a-180,arrow=False).put(flip=1)
temp = eic_mt.bend(pin=VIA_RO.pin['ele_a1'],angle=VIA_RO.pin['ele_a1'].a-180,arrow=False).put(flip=1)
eic_mt.ubend_p2p(pin2=BUS_VIA_R.pin['a0'],arrow=False).put()
else :
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin1=VIA_RO.pin['a1'],pin2=BUS_VIA_R.pin['a0'].move(0,0,-90),arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin1=VIA_RO.pin['opt_a1'],pin2=BUS_VIA_R.pin['a0'].move(0,0,-90),arrow=False).put()
eic_mt.strt_bend_strt_p2p(pin1=VIA_RO.pin['ele_a1'],pin2=BUS_VIA_R.pin['a0'].move(0,0,-90),arrow=False).put()
nd.Pin(name='en3',width=BUS_IMP.wg_Ltp-self.sp_cont*2).put(BUS_VIA_L.pin['a0'].x,BUS_VIA_L.pin['a0'].y,-90)
nd.Pin(name='en4',width=BUS_IMP.wg_Ltp-self.sp_cont*2).put(BUS_VIA_R.pin['a0'].x,BUS_VIA_R.pin['a0'].y,-90)
if (self.w2_bus>0):
y_cp = (self.ORy+self.gap2+self.w2_bus/2)
for idx in range(0,len(ORx_out)):
w_imp_bus = ORy_out[idx]-IRy_out[idx]
if (idx==0):
Y = y_cp+self.w2_bus/2+(IRy_out[idx]-self.ORy)+w_imp_bus/2
else :
Y = Y+w_imp_bus/2
BUS_IMP = ring_bus_wg(xs=xs_out[idx], R_cp=self.R2_cp,
w_bus=w_imp_bus+ovlp,bend_DC=True, w_wg=w_imp_bus+ovlp, dAc=self.A2_cp,
w_trans=w_imp_bus+ovlp,
euler_anti_bend=self.Euler_trasition,euler_transistion=self.Euler_trasition,
R_max_trans=self.R2_att,dA_trans=self.A2_att,dL_trans=self.L_tilt,
R_max_anti=self.R2_att,R_min_anti=self.R2_att_min,
sharp_patch=False,show_pins=False,
wg_Ltp=self.Ltp_bus,
dL_p2p=self.dL_p2p)
INSTR = BUS_IMP.cell.put(0,Y,flip=1)
Y = Y+w_imp_bus/2
Y = Y-w_cont_out/2
if (self.xs_cont_wg != None):
BUS_CONT = ring_bus_wg(xs=self.xs_cont_wg, R_cp=self.R1_cp,
w_bus=w_cont_out+ovlp,bend_DC=True, w_wg=w_cont_out+ovlp, dAc=self.A1_cp,
w_trans=w_cont_out+ovlp,
euler_anti_bend=self.Euler_trasition,euler_transistion=self.Euler_trasition,
R_max_trans=self.R1_att,dA_trans=self.A1_att,dL_trans=self.L_tilt,
R_max_anti=self.R1_att,R_min_anti=self.R1_att_min,
sharp_patch=False,show_pins=False,res=eic_dL,
wg_Ltp=self.Ltp_bus,
dL_p2p=self.dL_p2p).cell.put(0,Y,flip=1)
BUS_VIA_L = Vias(xs=self.via_i2m.xs,area=[self.w_metal,BUS_IMP.w_wg-self.sp_cont*2],
xs_l1=self.via_i2m.xs_l1,
xs_l2=self.via_i2m.xs_l2,
sz=self.via_i2m.sz,spacing=self.via_i2m.spacing,
sp_via_xs=self.via_i2m.sp_via_xs,
## revised in 2026.06.07 by Qin Yue
# legacy: ).cell.put(INSTR.pin['a1'].x+self.w_metal/2+self.sp_cont,INSTR.pin['a1'].y,180)
).cell.put(INSTR.pin['opt_a1'].x+self.w_metal/2+self.sp_cont,INSTR.pin['opt_a1'].y,180)
BUS_VIA_R = Vias(xs=self.via_i2m.xs,area=[self.w_metal,BUS_IMP.w_wg-self.sp_cont*2],
xs_l1=self.via_i2m.xs_l1,
xs_l2=self.via_i2m.xs_l2,
sp_via_xs=self.via_i2m.sp_via_xs,
## revised in 2026.06.07 by Qin Yue
# legacy: sz=self.via_i2m.sz,spacing=self.via_i2m.spacing).cell.put(INSTR.pin['b1'].x-self.w_metal/2-self.sp_cont,INSTR.pin['b1'].y)
sz=self.via_i2m.sz,spacing=self.via_i2m.spacing).cell.put(INSTR.pin['opt_b1'].x-self.w_metal/2-self.sp_cont,INSTR.pin['opt_b1'].y)
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.bend(pin=VIA_LO.pin['a1'],angle=VIA_LO.pin['a1'].a-90,arrow=False).put(flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.bend(pin=VIA_LO.pin['opt_a1'],angle=VIA_LO.pin['opt_a1'].a-90,arrow=False).put(flip=1)
eic_mt.bend(pin=VIA_LO.pin['ele_a1'],angle=VIA_LO.pin['ele_a1'].a-90,arrow=False).put(flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin2=BUS_VIA_L.pin['a1'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin2=BUS_VIA_L.pin['opt_a1'],arrow=False).put()
eic_mt.strt_bend_strt_p2p(pin2=BUS_VIA_L.pin['ele_a1'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.bend(pin=VIA_RO.pin['b1'],angle=90-VIA_RO.pin['b1'].a).put(flip=0)
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.bend(pin=VIA_RO.pin['opt_b1'],angle=90-VIA_RO.pin['opt_b1'].a).put(flip=0)
eic_mt.bend(pin=VIA_RO.pin['ele_b1'],angle=90-VIA_RO.pin['ele_b1'].a).put(flip=0)
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin2=BUS_VIA_R.pin['a1'],arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: eic_mt.strt_bend_strt_p2p(pin2=BUS_VIA_R.pin['opt_a1'],arrow=False).put()
eic_mt.strt_bend_strt_p2p(pin2=BUS_VIA_R.pin['ele_a1'],arrow=False).put()
else :
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_LO.pin['b1'],angle=VIA_LO.pin['b1'].a-270,arrow=False).put(flip=1)
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_LO.pin['opt_b1'],angle=VIA_LO.pin['opt_b1'].a-270,arrow=False).put(flip=1)
temp = eic_mt.bend(pin=VIA_LO.pin['ele_b1'],angle=VIA_LO.pin['ele_b1'].a-270,arrow=False).put(flip=1)
nd.Pin(name='en3',width=w_cont_out-self.sp_cont*2+ovlp,pin=temp.pin['b0']).put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_RO.pin['a1'],angle=270-VIA_RO.pin['a1'].a,arrow=False).put()
## revised in 2026.06.07 by Qin Yue
# legacy: temp = eic_mt.bend(pin=VIA_RO.pin['opt_a1'],angle=270-VIA_RO.pin['opt_a1'].a,arrow=False).put()
temp = eic_mt.bend(pin=VIA_RO.pin['ele_a1'],angle=270-VIA_RO.pin['ele_a1'].a,arrow=False).put()
nd.Pin(name='en4',width=w_cont_out-self.sp_cont*2+ovlp,pin=temp.pin['b0']).put()
return C
## Sub-classes for standard ring resonators
class STD_Ring_PIN(AED_Ring_PIN):
"""
STD Ring PIN primitive component.
This component builds the STD Ring PIN layout cell.
Parameters
----------
name : str
Unique identifier for the device cell.
r_ring : float, optional
Radius parameter in microns. Default is 10.
w_ring : float, optional
Width parameter in microns. Default is 0.55.
gap : float, optional
Spacing or gap parameter in microns. Default is 0.2.
dual_BUS : bool, optional
Value for the dual_BUS parameter. Default is True.
w_bus : float, optional
Width parameter in microns. Default is 0.45.
R_cp : Any, optional
Radius parameter in microns. Default is None.
A_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.
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.
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.
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 8.
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_ht_dX : int, optional
Value for the epin_ht_dX parameter. Default is 10.
epin_ht_dY : int, optional
Value for the epin_ht_dY parameter. Default is 3.
xs_metal_imp : str, optional
Layer or cross-section name used by the device. Default is 'metal'.
via_i2m : Any, optional
Via definition used between implant and metal layers. Default is None.
xs_p : str, optional
Layer or cross-section name used by the device. Default is 'p'.
xs_n : str, optional
Layer or cross-section name used by the device. Default is 'n'.
xs_cont_wg : Optional[str], optional
Layer or cross-section name used by the device. Default is None.
w_p : float, optional
Width parameter in microns. Default is 3.
gap_p_i : float, optional
Spacing or gap parameter in microns. Default is 1.
gap_n_i : float, optional
Spacing or gap parameter in microns. Default is 1.
w_n : float, optional
Width parameter in microns. Default is 3.
offset_i : float, optional
Value for the offset_i parameter. Default is 0.
A_imp_in : int, optional
Angle parameter in degrees. Default is 180.
A_imp_out : int, optional
Angle parameter in degrees. Default is 180.
xs_pcont : str, optional
Layer or cross-section name used by the device. Default is 'pp'.
xs_ncont : str, optional
Layer or cross-section name used by the device. Default is 'np'.
w_pcont : float, optional
Width parameter in microns. Default is 3.
w_ncont : float, optional
Width parameter in microns. Default is 3.
sp_cont : float, optional
Spacing or gap parameter in microns. Default is 0.2.
w_ovlp : float, optional
Width parameter in microns. Default is 0.2.
bus_dopping : bool, optional
Value for the bus_dopping parameter. Default is True.
p_in_n_out : bool, optional
Value for the p_in_n_out parameter. Default is False.
"""
def __init__(self,
name: str,
r_ring: float=10,
w_ring: float=0.55,
gap: float=0.2, dual_BUS: bool=True,
w_bus: float=0.45,
R_cp: Any=None,
A_cp: int=0,
offset_X: float=0,
offset_Y: float=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,
L_tilt: int=10, xs_ring: str='strip',
sharp_patch: bool=True,
Euler_trasition: bool=False,
show_pins: bool=False,
xs_heater: str = 'heater',
w_heater: float = 0,
xs_metal: str = 'metal',
w_metal: float = 8,
via_h2m: Any = None,
isl: Any = None,
A_ht: float = 270, ht_notch_dual: bool = True, epin_ht_dX: int=10, epin_ht_dY: int=3,
xs_metal_imp: str='metal',
via_i2m: Any = None,
xs_p: str='p', xs_n: str='n', xs_cont_wg: Optional[str]=None, w_p: float=3,
gap_p_i: float=1, gap_n_i: float=1, w_n: float=3,offset_i: float=0, A_imp_in: int=180, A_imp_out: int=180, xs_pcont: str='pp', xs_ncont: str='np',
w_pcont: float=3, w_ncont: float=3, sp_cont: float=0.2,
w_ovlp: float = 0.2, ## overlapping area for doping
bus_dopping: bool = True,
p_in_n_out: bool=False) -> None:
ORx = r_ring + w_ring/2
ORy = ORx
IRx = r_ring - w_ring/2
IRy = IRx
super().__init__(
name = name,
ORx=ORx,
ORy=ORy,
IRx=IRx,
IRy=IRy,
gap=gap,
dual_BUS=dual_BUS,
w_bus=w_bus,
R_cp=R_cp,
A_cp=A_cp,
offset_X=offset_X, offset_Y=offset_Y,
w_wg=w_wg,
R_att = R_att, R_att_min = R_att_min,
A_att = A_att,
Ltp_bus=Ltp_bus,
dL_p2p=dL_p2p,
L_tilt=L_tilt,
xs_ring=xs_ring, sharp_patch=sharp_patch,
Euler_trasition=Euler_trasition,
# n_points=n_points,
show_pins=show_pins,
xs_heater = xs_heater, w_heater = w_heater,
xs_metal = xs_metal, w_metal = w_metal,
# xs_via_h2m = xs_via_h2m,
# sz_via_h2m = sz_via_h2m, sp_via_h2m = sp_via_h2m,
# xs_isl = xs_isl, w_isl = w_isl, sp_isl = sp_isl,
via_h2m=via_h2m,
isl=isl,
A_ht = A_ht,
ht_notch_dual = ht_notch_dual,
epin_ht_dX = epin_ht_dX,
epin_ht_dY = epin_ht_dY,
# sz_via_i2m = sz_via_i2m,
# sp_via_i2m = sp_via_i2m,
via_i2m= via_i2m,
xs_metal_imp = xs_metal_imp, ## metal connect to implemetation
# xs_via_i2m = xs_via_i2m, ## via to implemetation
xs_p = xs_p,
xs_n = xs_n,
xs_cont_wg = xs_cont_wg,
w_p = w_p,
gap_p_i = gap_p_i,
gap_n_i = gap_n_i,
w_n = w_n,
offset_i = offset_i,
A_imp_in = A_imp_in,
A_imp_out = A_imp_out,
sp_cont = sp_cont,
w_ovlp = w_ovlp, ## overlapping area for doping
bus_dopping = bus_dopping,
p_in_n_out=p_in_n_out, ## default , p-outside n-inside
)
## Sub-classed for allpass rings with Euler shape coupling
class PIN_MRR_MM_Allpass(AED_Ring_PIN):
"""
PIN MRR MM Allpass primitive component.
This component builds the PIN 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.55.
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.
R_cp : Any, optional
Radius parameter in microns. Default is None.
A_cp : int, optional
Angle parameter in degrees. Default is 0.
R_att : int, optional
Radius parameter in microns. Default is 10.
R_att_min : int, optional
Radius parameter in microns. Default is 10.
A_att : int, optional
Angle parameter in degrees. Default is 10.
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.
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.
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 8.
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_ht_dX : int, optional
Value for the epin_ht_dX parameter. Default is 10.
epin_ht_dY : int, optional
Value for the epin_ht_dY parameter. Default is 3.
xs_metal_imp : str, optional
Layer or cross-section name used by the device. Default is 'metal'.
via_i2m : Any, optional
Via definition used between implant and metal layers. Default is None.
xs_p : str, optional
Layer or cross-section name used by the device. Default is 'p'.
xs_n : str, optional
Layer or cross-section name used by the device. Default is 'n'.
xs_cont_wg : Optional[str], optional
Layer or cross-section name used by the device. Default is None.
w_p : float, optional
Width parameter in microns. Default is 3.
w_n : float, optional
Width parameter in microns. Default is 3.
w_i : float, optional
Width parameter in microns. Default is 1.
offset_i : float, optional
Value for the offset_i parameter. Default is 0.
A_imp_in : int, optional
Angle parameter in degrees. Default is 180.
A_imp_out : int, optional
Angle parameter in degrees. Default is 180.
sp_cont : float, optional
Spacing or gap parameter in microns. Default is 0.2.
w_ovlp : float, optional
Width parameter in microns. Default is 0.2.
bus_dopping : bool, optional
Value for the bus_dopping parameter. Default is True.
cell_xs_transition : Any, optional
Cell or component dependency used by this device. Default is None.
p_in_n_out : bool, optional
Value for the p_in_n_out parameter. Default is False.
"""
def __init__(self,
name: Optional[str] = None,
r_ring: float=10,
w_ring: float=0.55,
gap: float=0.2,
w_bus: float=0.45,
R_cp: Any=None,
A_cp: int=0,
R_att: int = 10, R_att_min: int = 10,
A_att: int = 10,
offset_X: float=0,
offset_Y: float=0,
w_wg: float=0.45,
Ltp_bus: int=10,
dL_p2p: Optional[float] = None,
xs_ring: str='strip',
sharp_patch: bool=True,
show_pins: bool=False,
xs_heater: str = 'heater',
w_heater: float = 0,
xs_metal: str = 'metal',
w_metal: float = 8,
via_h2m: Any = None,
isl: Any = None,
A_ht: float = 270, ht_notch_dual: bool = True, epin_ht_dX: int=10, epin_ht_dY: int=3,
xs_metal_imp: str='metal',
via_i2m: Any = None,
xs_p: str='p', xs_n: str='n', xs_cont_wg: Optional[str]=None, w_p: float=3,
w_n: float=3, w_i: float=1,
offset_i: float=0, A_imp_in: int=180, A_imp_out: int=180,
# xs_pcont='pp', xs_ncont='np',
# w_pcont=3, w_ncont=3,
sp_cont: float=0.2,
w_ovlp: float = 0.2, ## overlapping area for doping
bus_dopping: bool = True,
cell_xs_transition: Any = None,
p_in_n_out: bool=False,
) -> None:
ORx = r_ring + w_ring/2
ORy = ORx
IRx = r_ring - w_ring/2
IRy = IRx
super().__init__(
name=name,
ORx=ORx,
ORy=ORy,
IRx=IRx,
IRy=IRy,
gap=gap,
dual_BUS=False,
w_bus=w_bus,
R_cp=R_cp,
A_cp=A_cp,
offset_X=offset_X, offset_Y=offset_Y,
w_wg=w_wg,
R_att = R_att, R_att_min = R_att_min,
A_att = A_att,
Ltp_bus=Ltp_bus,
dL_p2p=dL_p2p,
L_tilt=0,
xs_ring=xs_ring, sharp_patch=sharp_patch,
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 = ht_notch_dual,
epin_ht_dX = epin_ht_dX,
epin_ht_dY = epin_ht_dY,
via_i2m= via_i2m,
xs_metal_imp = xs_metal_imp, ## metal connect to implemetation
xs_p = xs_p,
xs_n = xs_n,
xs_cont_wg = xs_cont_wg,
w_p = w_p,
gap_p_i = w_i/2-w_ring/2,
gap_n_i = w_i/2-w_ring/2,
w_n = w_n,
offset_i = offset_i,
A_imp_in = A_imp_in,
A_imp_out = A_imp_out,
# xs_pcont = xs_pcont,
# xs_ncont = xs_ncont,
# w_pcont = w_pcont,
# w_ncont = w_ncont,
sp_cont = sp_cont,
w_ovlp = w_ovlp, ## overlapping area for doping
bus_dopping = bus_dopping,
p_in_n_out=p_in_n_out, ## default , p-outside n-inside
cell_xs_transition=cell_xs_transition,
)
## Sub-classed for allpass rings with Euler shape coupling
class PIN_MRR_MM_Adddrop(AED_Ring_PIN):
"""
PIN MRR MM Adddrop primitive component.
This component builds the PIN 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.55.
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.
R_cp : Any, optional
Radius parameter in microns. Default is None.
A_cp : int, optional
Angle parameter in degrees. Default is 0.
R_att : int, optional
Radius parameter in microns. Default is 10.
R_att_min : int, optional
Radius parameter in microns. Default is 10.
A_att : int, optional
Angle parameter in degrees. Default is 10.
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.
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.
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 8.
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_ht_dX : int, optional
Value for the epin_ht_dX parameter. Default is 10.
epin_ht_dY : int, optional
Value for the epin_ht_dY parameter. Default is 3.
xs_metal_imp : str, optional
Layer or cross-section name used by the device. Default is 'metal'.
via_i2m : Any, optional
Via definition used between implant and metal layers. Default is None.
xs_p : str, optional
Layer or cross-section name used by the device. Default is 'p'.
xs_n : str, optional
Layer or cross-section name used by the device. Default is 'n'.
xs_cont_wg : Optional[str], optional
Layer or cross-section name used by the device. Default is None.
w_p : float, optional
Width parameter in microns. Default is 3.
w_n : float, optional
Width parameter in microns. Default is 3.
w_i : float, optional
Width parameter in microns. Default is 1.
offset_i : float, optional
Value for the offset_i parameter. Default is 0.
A_imp_in : int, optional
Angle parameter in degrees. Default is 180.
A_imp_out : int, optional
Angle parameter in degrees. Default is 180.
sp_cont : float, optional
Spacing or gap parameter in microns. Default is 0.2.
w_ovlp : float, optional
Width parameter in microns. Default is 0.2.
bus_dopping : bool, optional
Value for the bus_dopping parameter. Default is True.
cell_xs_transition : Any, optional
Cell or component dependency used by this device. Default is None.
p_in_n_out : bool, optional
Value for the p_in_n_out parameter. Default is False.
"""
def __init__(self,
name: Optional[str] = None,
r_ring: float=10,
w_ring: float=0.55,
gap: float=0.2,
w_bus: float=0.45,
R_cp: Any=None,
A_cp: int=0,
R_att: int = 10, R_att_min: int = 10,
A_att: int = 10,
offset_X: float=0,
offset_Y: float=0,
w_wg: float=0.45,
Ltp_bus: int=10,
dL_p2p: Optional[float] = None,
xs_ring: str='strip',
sharp_patch: bool=True,
show_pins: bool=False,
xs_heater: str = 'heater',
w_heater: float = 0,
xs_metal: str = 'metal',
w_metal: float = 8,
via_h2m: Any = None,
isl: Any = None,
A_ht: float = 270, ht_notch_dual: bool = True, epin_ht_dX: int=10, epin_ht_dY: int=3,
xs_metal_imp: str='metal',
via_i2m: Any = None,
xs_p: str='p', xs_n: str='n', xs_cont_wg: Optional[str]=None, w_p: float=3,
w_n: float=3, w_i: float=1,
offset_i: float=0, A_imp_in: int=180, A_imp_out: int=180,
# xs_pcont='pp', xs_ncont='np',
# w_pcont=3, w_ncont=3,
sp_cont: float=0.2,
w_ovlp: float = 0.2, ## overlapping area for doping
bus_dopping: bool = True,
cell_xs_transition: Any = None,
p_in_n_out: bool=False,
) -> None:
ORx = r_ring + w_ring/2
ORy = ORx
IRx = r_ring - w_ring/2
IRy = IRx
super().__init__(
name=name,
ORx=ORx,
ORy=ORy,
IRx=IRx,
IRy=IRy,
gap=gap,
dual_BUS=True,
w_bus=w_bus,
R_cp=R_cp,
A_cp=A_cp,
offset_X=offset_X, offset_Y=offset_Y,
w_wg=w_wg,
R_att = R_att, R_att_min = R_att_min,
A_att = A_att,
Ltp_bus=Ltp_bus,
dL_p2p=dL_p2p,
L_tilt=0,
xs_ring=xs_ring, sharp_patch=sharp_patch,
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 = ht_notch_dual,
epin_ht_dX = epin_ht_dX,
epin_ht_dY = epin_ht_dY,
via_i2m= via_i2m,
xs_metal_imp = xs_metal_imp, ## metal connect to implemetation
xs_p = xs_p,
xs_n = xs_n,
xs_cont_wg = xs_cont_wg,
w_p = w_p,
gap_p_i = w_i/2-w_ring/2,
gap_n_i = w_i/2-w_ring/2,
w_n = w_n,
offset_i = offset_i,
A_imp_in = A_imp_in,
A_imp_out = A_imp_out,
# xs_pcont = xs_pcont,
# xs_ncont = xs_ncont,
# w_pcont = w_pcont,
# w_ncont = w_ncont,
sp_cont = sp_cont,
w_ovlp = w_ovlp, ## overlapping area for doping
bus_dopping = bus_dopping,
p_in_n_out=p_in_n_out, ## default , p-outside n-inside
cell_xs_transition=cell_xs_transition,
)
## Sub-classed for allpass rings with standard coupling
class PIN_MRR_STD_Allpass(AED_Ring_PIN):
"""
PIN MRR STD Allpass primitive component.
This component builds the PIN MRR STD 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.55.
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.
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.
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 8.
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_ht_dX : int, optional
Value for the epin_ht_dX parameter. Default is 10.
epin_ht_dY : int, optional
Value for the epin_ht_dY parameter. Default is 3.
xs_metal_imp : str, optional
Layer or cross-section name used by the device. Default is 'metal'.
via_i2m : Any, optional
Via definition used between implant and metal layers. Default is None.
xs_p : str, optional
Layer or cross-section name used by the device. Default is 'p'.
xs_n : str, optional
Layer or cross-section name used by the device. Default is 'n'.
xs_cont_wg : Optional[str], optional
Layer or cross-section name used by the device. Default is None.
w_p : float, optional
Width parameter in microns. Default is 3.
w_n : float, optional
Width parameter in microns. Default is 3.
w_i : float, optional
Width parameter in microns. Default is 1.
offset_i : float, optional
Value for the offset_i parameter. Default is 0.
A_imp_in : int, optional
Angle parameter in degrees. Default is 180.
A_imp_out : int, optional
Angle parameter in degrees. Default is 180.
sp_cont : float, optional
Spacing or gap parameter in microns. Default is 0.2.
w_ovlp : float, optional
Width parameter in microns. Default is 0.2.
bus_dopping : bool, optional
Value for the bus_dopping parameter. Default is True.
cell_xs_transition : Any, optional
Cell or component dependency used by this device. Default is None.
p_in_n_out : bool, optional
Value for the p_in_n_out parameter. Default is False.
"""
def __init__(self,
name: Optional[str]=None,
r_ring: float=10,
w_ring: float=0.55,
gap: float=0.2,
w_bus: float=0.45,
A_cp: int=0,
w_wg: float=0.45,
Ltp_bus: int=10,
dL_p2p: Optional[float] = None,
L_tilt: int=10,
xs_ring: str='strip',
sharp_patch: bool=True,
show_pins: bool=False,
xs_heater: str = 'heater',
w_heater: float = 0,
xs_metal: str = 'metal',
w_metal: float = 8,
via_h2m: Any = None,
isl: Any = None,
A_ht: float = 270, ht_notch_dual: bool = True, epin_ht_dX: int=10, epin_ht_dY: int=3,
xs_metal_imp: str='metal',
via_i2m: Any = None,
xs_p: str='p', xs_n: str='n', xs_cont_wg: Optional[str]=None, w_p: float=3,
w_n: float=3, w_i: float=1, offset_i: float=0, A_imp_in: int=180, A_imp_out: int=180,
# xs_pcont='pp', xs_ncont='np',
# w_pcont=3, w_ncont=3,
sp_cont: float=0.2,
w_ovlp: float = 0.2, ## overlapping area for doping
bus_dopping: bool = True,
cell_xs_transition: Any = None,
p_in_n_out: bool=False,
) -> None:
ORx = r_ring + w_ring/2
ORy = ORx
IRx = r_ring - w_ring/2
IRy = IRx
super().__init__(
name= name,
ORx=ORx,
ORy=ORy,
IRx=IRx,
IRy=IRy,
gap=gap,
dual_BUS=False,
w_bus=w_bus,
R_cp=None,
A_cp=A_cp,
offset_X=0, offset_Y=0,
w_wg=w_wg,
R_att = 0, R_att_min = 0,
A_att = 0,
Ltp_bus=Ltp_bus,
dL_p2p=dL_p2p,
L_tilt=L_tilt,
xs_ring=xs_ring, sharp_patch=sharp_patch,
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 = ht_notch_dual,
epin_ht_dX = epin_ht_dX,
epin_ht_dY = epin_ht_dY,
via_i2m= via_i2m,
xs_metal_imp = xs_metal_imp, ## metal connect to implemetation
xs_p = xs_p,
xs_n = xs_n,
xs_cont_wg = xs_cont_wg,
w_p = w_p,
gap_p_i = w_i/2-w_ring/2,
gap_n_i = w_i/2-w_ring/2,
w_n = w_n,
offset_i = offset_i,
A_imp_in = A_imp_in,
A_imp_out = A_imp_out,
# xs_pcont = xs_pcont,
# xs_ncont = xs_ncont,
# w_pcont = w_pcont,
# w_ncont = w_ncont,
sp_cont = sp_cont,
w_ovlp = w_ovlp, ## overlapping area for doping
bus_dopping = bus_dopping,
p_in_n_out=p_in_n_out, ## default , p-outside n-inside
cell_xs_transition=cell_xs_transition,
)