from typing import Any, Optional import nazca as nd import numpy as np from ...geometry import * from ....technologies import * from ...electronics import Vias from ...electronics import ISL import nazca.interconnects as IC from ...basic import __xs_exist__,__cell_arg__ from ..pic import taper_xs2xs from ...routing import Route # class Route(IC.Interconnect): # pass class waveguide: """ waveguide primitive component. This component builds the waveguide layout cell. Parameters ---------- w_heater : float, optional Width parameter in microns. Default is 2.5. L_wg : int, optional Length parameter in microns. Default is 150. L_heater : int, optional Length parameter in microns. Default is 150. w_metal : float, optional Width parameter in microns. Default is 10. xs_heater : str, optional Layer or cross-section name used by the device. Default is 'heater'. xs_metal : str, optional Layer or cross-section name used by the device. Default is 'metal'. xs_wg : str, optional Layer or cross-section name used by the device. Default is 'strip'. w_wg : float, optional Width parameter in microns. Default is 0.45. w_port : Optional[float], optional Width parameter in microns. Default is None. Ltp : Any, optional Length parameter in microns. Default is None. 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. euler_bend : bool, optional Value for the euler_bend parameter. Default is False. Rmin : int, optional Radius parameter in microns. Default is 5. thin_attach : bool, optional Value for the thin_attach parameter. Default is False. UPPER_ISL : bool, optional Value for the UPPER_ISL parameter. Default is True. LOWER_ISL : bool, optional Length parameter in microns. Default is True. shape : str, optional Value for the shape parameter. Default is 'strip'. R_bend : int, optional Radius parameter in microns. Default is 10. ubend_offset : int, optional Value for the ubend_offset parameter. Default is 20. show_pins : bool, optional Whether to draw pin markers in the generated layout. Default is False. """ def __init__(self, w_heater: float=2.5, L_wg: int=150, L_heater: int=150, w_metal: float=10, xs_heater: str='heater', xs_metal: str='metal', xs_wg: str = 'strip', w_wg: float = 0.45, w_port: Optional[float] = None, Ltp: Any = None, via_h2m: Any = None, isl: Any = None, euler_bend: bool = False, Rmin: int = 5, thin_attach: bool = False, UPPER_ISL: bool = True, LOWER_ISL: bool = True, shape: str = 'strip', R_bend: int=10, ubend_offset: int=20, show_pins: bool=False) -> None: """ Revised in 2022.12.30, to simplify the function logic """ if (w_heater>0 and xs_heater!=None and xs_metal!=None): xs_heater = __xs_exist__(xs=xs_heater,para_name="xs_heater",func_name="mxpic::passive::waveguide") xs_metal = __xs_exist__(xs=xs_metal,para_name="xs_metal",func_name="mxpic::passive::waveguide") if (w_port==None): w_port = w_wg if (Ltp==None): Ltp=0 """ Generating the basic via_h2m """ if (via_h2m==None): vias = Vias(xs=None,area=w_metal,sz=0,spacing=0,xs_l1=xs_heater,xs_l2=xs_metal) ## only putting metal blocks else: if (hasattr(via_h2m,"cell")): vias = via_h2m else : vias = Vias(xs=via_h2m.xs,area=w_metal,sz=via_h2m.sz,spacing=via_h2m.spacing,xs_l1=xs_heater,xs_l2=xs_metal) ## placing vias if (L_heater==None): L_heater = L_wg ### Adding the straight waveguide if (shape=='strip'): with nd.Cell(instantiate=False) as C: nd.taper(length=Ltp,width1=w_port,width2=w_wg,xs=xs_wg).put(-L_wg/2,0,0) nd.strt(length=L_wg-2*Ltp,width=w_wg,xs=xs_wg).put() nd.taper(length=Ltp,width2=w_port,width1=w_wg,xs=xs_wg).put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',width=w_wg).put(-L_wg/2,0,180) nd.Pin(name='opt_a1',width=w_wg,type="optical:").put(-L_wg/2,0,180) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',width=w_wg).put( L_wg/2,0,0) nd.Pin(name='opt_b1',width=w_wg,type="optical:").put( L_wg/2,0,0) L_heater = np.min([L_wg,L_heater]) ### placing heaters if (w_heater>0 and xs_heater!=None and xs_metal!=None): nd.strt(length=L_heater,width=w_heater,xs=xs_heater).put(-L_heater/2,0,0) if (thin_attach==False): # VIAL = vias.cell.put(-L_heater/2+w_metal/2,0,180,flip=1) # VIAR = vias.cell.put( L_heater/2-w_metal/2,0,0) VIAL = vias.cell.put(-L_heater/2,0,180,flip=1) VIAR = vias.cell.put( L_heater/2,0,0) else : # VIAL = vias.cell.put(-L_heater/2+w_metal/2,0,180,flip=1) # VIAR = vias.cell.put( L_heater/2-w_metal/2,0,0) VIAL = vias.cell.put(-L_heater/2,0,180,flip=1) VIAR = vias.cell.put( L_heater/2,0,0) nd.Pin(name='ep1',width=w_metal,pin=VIAL.pin['b0']).put() nd.Pin(name='en1',width=w_metal,pin=VIAR.pin['b0']).put() if (isl!=None): if (UPPER_ISL): ISL(length=L_heater, ## variables xs=isl.xs,width=isl.width,spacing=isl.spacing,Lmax=isl.Lmax ## default parameters ).cell.put(-L_heater/2,-w_metal/2-isl.width/2-isl.sp_isl_metal,0) if (LOWER_ISL): ISL(length=L_heater, ## variables xs=isl.xs,width=isl.width,spacing=isl.spacing,Lmax=isl.Lmax ## default parameters ).cell.put(-L_heater/2,w_metal/2+isl.width/2+isl.sp_isl_metal,0) ### Adding the bend shape waveguide elif (shape == 'ubend'): with nd.Cell(instantiate=False) as C: if (euler_bend): bd = Clothoid(R=[R_bend,Rmin,R_bend],w=[w_wg,w_wg],A=[0,90,180],xs=xs_wg,n_points=64) ubend_offset = bd.sz[1] R_ht = bd.sz[1]/2 L_wg_mid = 0 L_wg_side = (L_wg-L_wg_mid)/2-R_bend wg_in = nd.strt(length=L_wg_side,width=w_wg,xs=xs_wg).put(-ubend_offset/2,0,90) bd.cell.put(flip=1) wg_out = nd.strt(length=L_wg_side,width=w_wg,xs=xs_wg).put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',width=w_wg,pin=wg_in.pin['a0']).put() nd.Pin(name='opt_a1',width=w_wg,pin=wg_in.pin['a0'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',width=w_wg,pin=wg_out.pin['b0']).put() nd.Pin(name='opt_b1',width=w_wg,pin=wg_out.pin['b0'],type="optical:").put() else: R_ht = R_bend L_wg_mid = ubend_offset-R_bend*2 L_wg_side = (L_wg-L_wg_mid-R_bend*np.pi)/2 wg_in = nd.strt(length=L_wg_side,width=w_wg,xs=xs_wg).put(-ubend_offset/2,0,90) nd.bend(radius=R_bend,width=w_wg,xs=xs_wg).put(flip=1) nd.strt(length=L_wg_mid,width=w_wg,xs=xs_wg).put() nd.bend(radius=R_bend,width=w_wg,xs=xs_wg).put(flip=1) wg_out = nd.strt(length=L_wg_side,width=w_wg,xs=xs_wg).put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',width=w_wg,pin=wg_in.pin['a0']).put() nd.Pin(name='opt_a1',width=w_wg,pin=wg_in.pin['a0'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',width=w_wg,pin=wg_out.pin['b0']).put() nd.Pin(name='opt_b1',width=w_wg,pin=wg_out.pin['b0'],type="optical:").put() L_heater = np.max([L_wg_mid+R_bend+w_metal*2,L_heater]) L_heater = np.min([L_wg,L_heater]) if (w_heater>0): L_ht_side = (L_heater-L_wg_mid)/2-R_bend ht_in = nd.strt(length=L_ht_side,width=w_heater,xs=xs_heater).put(-ubend_offset/2,L_wg_side-L_ht_side,90) nd.bend(radius=R_ht,width=w_heater,xs=xs_heater).put(flip=1) nd.strt(length=(ubend_offset-R_ht*2),width=w_heater,xs=xs_heater).put() nd.bend(radius=R_ht,width=w_heater,xs=xs_heater).put(flip=1) ht_out = nd.strt(length=L_ht_side,width=w_heater,xs=xs_heater).put() # nd.strt(length=w_metal,width=w_metal,xs=xs_metal).put(-ubend_offset/2,L_wg_side-L_ht_side,90) # nd.strt(length=w_metal,width=w_metal,xs=xs_heater).put(-ubend_offset/2,L_wg_side-L_ht_side,90) # nd.strt(length=w_metal,width=w_metal,xs=xs_metal).put( ubend_offset/2,L_wg_side-L_ht_side,90) # nd.strt(length=w_metal,width=w_metal,xs=xs_heater).put( ubend_offset/2,L_wg_side-L_ht_side,90) # print(xs_via,sz_via_h2m,sp_via_h2m) VIAL = vias.cell.put(ubend_offset/2,L_wg_side-L_ht_side+w_metal/2,-90) VIAR = vias.cell.put(-ubend_offset/2,L_wg_side-L_ht_side+w_metal/2,-90,flip=1) nd.Pin(name='ep1',width=w_metal,pin=VIAL.pin['b0']).put() nd.Pin(name='en1',width=w_metal,pin=VIAR.pin['b0']).put() """ Placing Isolation trench with the parameter pack """ if (isl!=None): ## placing outer L_side = L_ht_side + R_bend + w_heater/2 + isl.sp_isl_xs*2 - w_metal ISL(xs=isl.xs,width=isl.w_idth,length=L_side).cell.put(-ubend_offset/2-w_metal/2-isl.sp_isl_xs,L_wg_side-L_ht_side+w_metal+isl.sp_isl_xs,90) ISL(xs=isl.xs,width=isl.w_idth,length=L_side).cell.put( ubend_offset/2+w_metal/2+isl.sp_isl_xs,L_wg_side-L_ht_side+w_metal+isl.sp_isl_xs,90) L_upper = isl.w_idth+2*(ubend_offset/2+w_metal/2+isl.sp_isl_xs) Y_upper = L_wg_side-L_ht_side+w_metal+isl.sp_isl_xs+L_side-isl.w_idth/2 ISL(xs=isl.xs,width=isl.w_idth,length=L_upper).cell.put( -L_upper/2,Y_upper,0) if ((ubend_offset/2-w_metal/2-isl.sp_isl_xs)*2-isl.w_idth>5): L_side = L_ht_side ISL(xs=isl.xs,width=isl.w_idth,length=L_side).cell.put(-ubend_offset/2+w_metal/2+(isl.sp_isl_xs),L_wg_side-L_ht_side,90) ISL(xs=isl.xs,width=isl.w_idth,length=L_side).cell.put( ubend_offset/2-w_metal/2-(isl.sp_isl_xs),L_wg_side-L_ht_side,90) if (show_pins): nd.put_stub(pinsize=2) self.cell = C self.L = L_heater+w_metal*2 """ NEW CLASS:: 2023.03.21, two stage phase shifters, to replace PS_3wg """ class PS_2st: """ PS 2st primitive component. This component builds the PS 2st layout cell. Parameters ---------- xs_wg : str, optional Layer or cross-section name used by the device. Default is 'strip'. w_wg : float, optional Width parameter in microns. Default is 0.5. w1 : float, optional Width parameter in microns. Default is 0.7. w2 : float, optional Width parameter in microns. Default is 0.9. L1 : int, optional Length parameter in microns. Default is 10. L2 : int, optional Length parameter in microns. Default is 55. L_wg : int, optional Length parameter in microns. Default is 0. L_tp : int, optional Length parameter in microns. Default is 1. L12 : Any, optional Length parameter in microns. Default is None. L_ht : Any, optional Length parameter in microns. Default is None. xs_heater : str, optional Layer or cross-section name used by the device. Default is 'heater'. xs_metal : str, optional Layer or cross-section name used by the device. Default is 'metal'. w_heater : float, optional Width parameter in microns. Default is 2.5. 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. UPPER_ISL : bool, optional Value for the UPPER_ISL parameter. Default is True. LOWER_ISL : bool, optional Length parameter in microns. Default is True. R_bend : int, optional Radius parameter in microns. Default is 10. show_pins : bool, optional Whether to draw pin markers in the generated layout. Default is False. """ def __init__(self, xs_wg: str = 'strip', w_wg: float = 0.5, w1: float = 0.7, w2: float = 0.9, L1: int = 10, L2: int = 55, L_wg: int = 0, L_tp: int = 1, L12: Any = None, L_ht: Any = None, xs_heater: str='heater', xs_metal: str='metal', w_heater: float=2.5, w_metal: float = 8, via_h2m: Any = None, isl: Any = None, UPPER_ISL: bool = True, LOWER_ISL: bool = True, R_bend: int=10, show_pins: bool=False) -> None: self.xs_wg = xs_wg self.w_wg = w_wg self.w1 = w1 self.w2 = w2 self.L1 = L1 self.L2 = L2 self.L_wg = L_wg self.L_tp = L_tp self.L_ht = L_ht self.xs_heater = xs_heater self.xs_metal = xs_metal self.w_heater = w_heater self.w_metal = w_metal self.via_h2m = via_h2m self.isl = isl self.R_bend = R_bend self.show_pins = show_pins self.R_bend = R_bend if (L12==None): L12 = L_tp self.L12 = L12 self.cell = self.generate_gds() def generate_gds(self): with nd.Cell(instantiate=False) as C: """ Generating the basic via_h2m """ if (self.via_h2m==None): vias = Vias(xs=None,area=self.w_metal,sz=0,spacing=0,xs_l1=self.xs_heater,xs_l2=self.xs_metal) ## only putting metal blocks else: if (hasattr(self.via_h2m,"cell")): vias = self.via_h2m else : vias = 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) ## placing vias pic_strip = Route(radius=self.R_bend,width=self.w_wg,xs=self.xs_wg) start = nd.strt(length=self.L_wg,width=self.w_wg,xs=self.xs_wg).put(0,0,90) nd.taper(length=self.L_tp,width1=self.w_wg,width2=self.w1,xs=self.xs_wg).put() nd.strt(length=self.L1,width=self.w1,xs=self.xs_wg).put() nd.taper(length=self.L12,width1=self.w1,width2=self.w2,xs=self.xs_wg).put() nd.strt(length=self.L2,width=self.w2,xs=self.xs_wg).put() nd.taper(length=self.L_tp,width1=self.w2,width2=self.w_wg,xs=self.xs_wg).put() nd.strt(length=self.L_wg,width=self.w_wg,xs=self.xs_wg).put() pic_strip.bend_route(angle=180).put(flip=1) nd.strt(length=self.L_wg,width=self.w_wg,xs=self.xs_wg).put() nd.taper(length=self.L_tp,width1=self.w_wg,width2=self.w2,xs=self.xs_wg).put() nd.strt(length=self.L2,width=self.w2,xs=self.xs_wg).put() nd.taper(length=self.L12,width1=self.w2,width2=self.w1,xs=self.xs_wg).put() nd.strt(length=self.L1,width=self.w1,xs=self.xs_wg).put() nd.taper(length=self.L_tp,width1=self.w1,width2=self.w_wg,xs=self.xs_wg).put() end = nd.strt(length=self.L_wg,width=self.w_wg,xs=self.xs_wg).put() L_arm = self.L_wg + self.L_tp + self.L1 + self.L12 + self.L2 + self.L_tp + self.L_wg if (self.L_ht==None): self.L_ht = (L_arm + self.R_bend*np.pi/2)*2 if (self.w_heater>0) : # L_wg_side = (L_wg-L_wg_mid)/2-R_bend # VIA = Vias(xs=self.via_h2m.xs,sz=self.via_h2m.sz,spacing=self.via_h2m.spacing,sp_via_xs=self.via_h2m.sp_via_xs, # xs_l1=self.xs_heater,xs_l2=self.xs_metal, # area=self.w_metal) Ly_ht = (self.L_ht - self.R_bend*np.pi)/2 nd.strt(length=Ly_ht,width=self.w_heater,xs=self.xs_heater).put(0,L_arm-Ly_ht,90) nd.bend(radius=self.R_bend,angle=180,xs=self.xs_heater,width=self.w_heater).put(flip=1) nd.strt(length=Ly_ht,width=self.w_heater,xs=self.xs_heater).put() VIA_L = vias.cell.put(0,L_arm-Ly_ht+self.w_metal/2,-90,flip=1) VIA_R = vias.cell.put(self.R_bend*2,L_arm-Ly_ht+self.w_metal/2,-90) # nd.Pin(name='ep1',pin=VIA_L.pin['b0'].move(0,0,-90)).put() # nd.Pin(name='en1',pin=VIA_R.pin['b0'].move(0,0,90)).put() nd.Pin(name='ep1',pin=VIA_L.pin['b0']).put() nd.Pin(name='en1',pin=VIA_R.pin['b0']).put() """ Placing Isolation trench with the parameter pack """ if (self.isl!=None): ## placing outer L_side = abs(L_arm+self.R_bend+self.w_heater/2+self.isl.width/2+self.isl.sp_isl_metal - VIA_L.pin['b0'].y - self.w_metal/2-self.isl.sp_isl_metal) ISL(xs=self.isl.xs,width=self.isl.width,length=L_side,spacing=self.isl.spacing,Lmax=self.isl.Lmax).cell.put( -self.isl.sp_isl_metal-self.w_heater/2-self.isl.width/2, VIA_L.pin['b0'].y+self.w_metal/2+self.isl.sp_isl_metal,90) ISL(xs=self.isl.xs,width=self.isl.width,length=L_side,spacing=self.isl.spacing,Lmax=self.isl.Lmax).cell.put( end.pin['b0'].x+self.isl.sp_isl_metal+self.w_heater/2+self.isl.width/2, VIA_L.pin['b0'].y+self.w_metal/2+self.isl.sp_isl_metal,90) L_top = abs(end.pin['b0'].x)+self.isl.width+(self.isl.sp_isl_metal+self.w_heater/2+self.isl.width/2)*2 ISL(xs=self.isl.xs,width=self.isl.width,length=L_top,spacing=self.isl.spacing,Lmax=self.isl.Lmax).cell.put( -self.isl.sp_isl_metal-self.w_heater/2-self.isl.width, VIA_L.pin['b0'].y+self.w_metal/2+self.isl.sp_isl_metal + L_side,0) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',pin=start.pin['a0']).put() nd.Pin(name='opt_a1',pin=start.pin['a0'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',pin=end.pin['b0']).put() nd.Pin(name='opt_b1',pin=end.pin['b0'],type="optical:").put() return C class PS_2st_Straight: """ PS 2st Straight primitive component. This component builds the PS 2st Straight layout cell. Parameters ---------- xs_wg : str, optional Layer or cross-section name used by the device. Default is 'strip'. w_wg : float, optional Width parameter in microns. Default is 0.5. w1 : float, optional Width parameter in microns. Default is 0.7. w2 : float, optional Width parameter in microns. Default is 0.9. L1 : int, optional Length parameter in microns. Default is 10. L2 : int, optional Length parameter in microns. Default is 55. L_wg : int, optional Length parameter in microns. Default is 0. L_tp : int, optional Length parameter in microns. Default is 1. L12 : Any, optional Length parameter in microns. Default is None. L_ht : Any, optional Length parameter in microns. Default is None. xs_heater : str, optional Layer or cross-section name used by the device. Default is 'heater'. xs_metal : str, optional Layer or cross-section name used by the device. Default is 'metal'. w_heater : float, optional Width parameter in microns. Default is 2.5. 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. UPPER_ISL : bool, optional Value for the UPPER_ISL parameter. Default is True. LOWER_ISL : bool, optional Length parameter in microns. Default is True. show_pins : bool, optional Whether to draw pin markers in the generated layout. Default is False. """ def __init__(self, xs_wg: str = 'strip', w_wg: float = 0.5, w1: float = 0.7, w2: float = 0.9, L1: int = 10, L2: int = 55, L_wg: int = 0, L_tp: int = 1, L12: Any = None, L_ht: Any = None, xs_heater: str='heater', xs_metal: str='metal', w_heater: float=2.5, w_metal: float = 8, via_h2m: Any = None, isl: Any = None, UPPER_ISL: bool = True, LOWER_ISL: bool = True, show_pins: bool=False) -> None: self.xs_wg = xs_wg self.w_wg = w_wg self.w1 = w1 self.w2 = w2 self.L1 = L1 self.L2 = L2 self.L_wg = L_wg self.L_tp = L_tp self.L_ht = L_ht self.xs_heater = xs_heater self.xs_metal = xs_metal self.w_heater = w_heater self.w_metal = w_metal self.via_h2m = via_h2m self.isl = isl self.show_pins = show_pins if (L12==None): L12 = L_tp self.L12 = L12 self.cell = self.generate_gds() def generate_gds(self): with nd.Cell(instantiate=False) as C: """ Generating the basic via_h2m """ # if (self.via_h2m==None): # vias = 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")): # vias = self.via_h2m # else : # vias = 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) ## placing vias start = nd.strt(length=self.L_wg,width=self.w_wg,xs=self.xs_wg).put(0,0,0) nd.taper(length=self.L_tp,width1=self.w_wg,width2=self.w1,xs=self.xs_wg).put() nd.strt(length=self.L1,width=self.w1,xs=self.xs_wg).put() nd.taper(length=self.L12,width1=self.w1,width2=self.w2,xs=self.xs_wg).put() nd.strt(length=self.L2,width=self.w2,xs=self.xs_wg).put() nd.taper(length=self.L_tp,width1=self.w2,width2=self.w_wg,xs=self.xs_wg).put() end = nd.strt(length=self.L_wg,width=self.w_wg,xs=self.xs_wg).put() L_arm = self.L_wg + self.L_tp + self.L1 + self.L12 + self.L2 + self.L_tp + self.L_wg self.L_arm = L_arm if (self.L_ht==None): self.L_ht = L_arm if (self.w_heater>0) : # L_wg_side = (L_wg-L_wg_mid)/2-R_bend """ Generating the basic via_h2m """ if (self.via_h2m==None): vias = Vias(xs=None,area=self.w_metal,sz=0,spacing=0,xs_l1=self.xs_heater,xs_l2=self.xs_metal) ## only putting metal blocks else: if (hasattr(self.via_h2m,"cell")): vias = self.via_h2m else : vias = 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) ## placing vias Ly_ht = (self.L_ht )/2 nd.strt(length=self.L_ht,width=self.w_heater,xs=self.xs_heater).put(self.L_arm/2 - self.L_ht/2,0,0) VIA_L = vias.cell.put(self.L_arm/2 - self.L_ht/2,0,180) VIA_R = vias.cell.put(self.L_arm/2 + self.L_ht/2,0,0) nd.Pin(name='ep1',pin=VIA_L.pin['b0']).put() nd.Pin(name='en1',pin=VIA_R.pin['b0']).put() """ Placing Isolation trench with the parameter pack """ ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',pin=start.pin['a0']).put() nd.Pin(name='opt_a1',pin=start.pin['a0'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',pin=end.pin['b0']).put() nd.Pin(name='opt_b1',pin=end.pin['b0'],type="optical:").put() return C class PSR_1x2: """ PSR 1x2 primitive component. This component builds the PSR 1x2 layout cell. Parameters ---------- PSR : Any Polarization splitter-rotator cell or component used by this composite. MDM : Any Mode multiplexer/demultiplexer cell or component used by this composite. xs : str, optional Layer or cross-section name used by the device. Default is 'strip'. w_wg : float, optional Width parameter in microns. Default is 0.45. L_tp : int, optional Length parameter in microns. Default is 15. show_pins : bool, optional Whether to draw pin markers in the generated layout. Default is False. """ def __init__(self,PSR: Any,MDM: Any,xs: str='strip',w_wg: float=0.45,L_tp: int=15,show_pins: bool=False) -> None: self.w_wg = w_wg PSR_cell = __cell_arg__(arg=PSR,arg_name="PSR",func_name="mxpicp::functional::PSR_1x2") MDM_cell = __cell_arg__(arg=MDM,arg_name="MDM",func_name="mxpicp::functional::PSR_1x2") with nd.Cell(instantiate=False) as C: ## revised in 2026.06.07 by Qin Yue # legacy: PSR_inst = PSR_cell.put('a1',0,0,0) PSR_inst = PSR_cell.put('opt_a1',0,0,0) ## revised in 2026.06.07 by Qin Yue # legacy: MDM_inst = MDM_cell.put('b1',PSR_inst.pin['b1'].x+L_tp,PSR_inst.pin['b1'].y,PSR_inst.pin['b1'].a) MDM_inst = MDM_cell.put('opt_b1',PSR_inst.pin['opt_b1'].x+L_tp,PSR_inst.pin['opt_b1'].y,PSR_inst.pin['opt_b1'].a) # taper_xs2xs(xs_1=MDM_inst.pin['b1'].xs,xs_2=PSR_inst.pin['b1'].xs,w_1=MDM_inst.pin['b1'].width,w_2=PSR_inst.pin['b1'].width,L_taper=L_tp).cell.put(MDM_inst.pin['b1']) ## revised in 2026.06.07 by Qin Yue # legacy: nd.taper(length=L_tp,width1=PSR_inst.pin['b1'].width,width2=MDM_inst.pin['b1'].width,xs=xs).put(PSR_inst.pin['b1']) nd.taper(length=L_tp,width1=PSR_inst.pin['opt_b1'].width,width2=MDM_inst.pin['opt_b1'].width,xs=xs).put(PSR_inst.pin['opt_b1']) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',pin=PSR_inst.pin['a1']).put() nd.Pin(name='opt_a1',pin=PSR_inst.pin['opt_a1'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',pin=MDM_inst.pin['a1']).put() nd.Pin(name='opt_b1',pin=MDM_inst.pin['opt_a1'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b2',pin=MDM_inst.pin['a2']).put() nd.Pin(name='opt_b2',pin=MDM_inst.pin['opt_a2'],type="optical:").put() if (show_pins): nd.put_stub(pinsize=2) self.cell = C ## revised in 2026.06.07 by Qin Yue # legacy: self.L = np.abs(self.cell.pin['a1'].x - np.max([self.cell.pin['b1'].x,self.cell.pin['b2'].x])) self.L = np.abs(self.cell.pin['opt_a1'].x - np.max([self.cell.pin['opt_b1'].x,self.cell.pin['opt_b2'].x])) def generate_test_gds(self,gc,gc_IN=None,gc2gc_dX=140,gc2gc_dY=40): with nd.Cell(name=self.cell.cell_name+"_test", instantiate=False) as C: gc_cell = __cell_arg__(arg=gc,arg_name="gc",func_name="mxpicp::functional::PSR_1x2::generate_test_gds") if (gc_IN==None): gc_IN = gc else : gc_IN = __cell_arg__(arg=gc,arg_name="gc_IN",func_name="mxpicp::functional::PSR_1x2::generate_test_gds") GC_I = gc_IN.put('g1',-gc2gc_dX/2,0,180) GC_OU = gc.put('g1', gc2gc_dX/2,-gc2gc_dY/2,0) GC_OD = gc.put('g1', gc2gc_dX/2,gc2gc_dY/2,0) PSR_test = self.cell.put(-self.L/2,0,0) stripe=Route(radius=10, width=self.w_wg, xs="strip") ## revised in 2026.06.07 by Qin Yue # legacy: stripe.taper_p2p(pin1=PSR_test.pin['a1'],pin2=GC_I.pin['g1'],arrow=False).put() stripe.taper_p2p(pin1=PSR_test.pin['opt_a1'],pin2=GC_I.pin['g1'],arrow=False).put() ## revised in 2026.06.07 by Qin Yue # legacy: stripe.sbend_p2p(pin1=PSR_test.pin['b1'],pin2=GC_OU.pin['g1'],arrow=False).put() stripe.sbend_p2p(pin1=PSR_test.pin['opt_b1'],pin2=GC_OU.pin['g1'],arrow=False).put() ## revised in 2026.06.07 by Qin Yue # legacy: stripe.sbend_p2p(pin1=PSR_test.pin['b2'],pin2=GC_OD.pin['g1'],arrow=False).put() stripe.sbend_p2p(pin1=PSR_test.pin['opt_b2'],pin2=GC_OD.pin['g1'],arrow=False).put() return C class Brag_WDM: """ Brag WDM primitive component. This component builds the Brag WDM layout cell. Parameters ---------- Brag : Any Bragg grating cell or component used by this composite. MDM : Any Mode multiplexer/demultiplexer cell or component used by this composite. w_wg : float, optional Width parameter in microns. Default is 0.45. L_tp : int, optional Length parameter in microns. Default is 30. show_pins : bool, optional Whether to draw pin markers in the generated layout. Default is False. """ def __init__(self,Brag: Any,MDM: Any,w_wg: float=0.45,L_tp: int=30,show_pins: bool=False) -> None: self.w_wg = w_wg Brag_cell = __cell_arg__(arg=Brag,arg_name="Brag",func_name="mxpicp::functional::Brag_WDM") MDM_cell = __cell_arg__(arg=MDM,arg_name="MDM",func_name="mxpicp::functional::Brag_WDM") with nd.Cell(instantiate=False) as C: ## revised in 2026.06.07 by Qin Yue # legacy: Brag_inst = Brag_cell.put('a1',0,0,0) Brag_inst = Brag_cell.put('opt_a1',0,0,0) ## revised in 2026.06.07 by Qin Yue # legacy: MDM_inst = MDM_cell.put('b1',Brag_inst.pin['a1'].x-L_tp,Brag_inst.pin['a1'].y,Brag_inst.pin['a1'].a) MDM_inst = MDM_cell.put('opt_b1',Brag_inst.pin['opt_a1'].x-L_tp,Brag_inst.pin['opt_a1'].y,Brag_inst.pin['opt_a1'].a) ## revised in 2026.06.07 by Qin Yue # legacy: nd.taper(length=L_tp,width1=Brag_inst.pin['b1'].width,width2=MDM_inst.pin['b1'].width,xs='strip').put(Brag_inst.pin['a1']) nd.taper(length=L_tp,width1=Brag_inst.pin['opt_b1'].width,width2=MDM_inst.pin['opt_b1'].width,xs='strip').put(Brag_inst.pin['opt_a1']) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',pin=Brag_inst.pin['b1']).put() nd.Pin(name='opt_b1',pin=Brag_inst.pin['opt_b1'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',pin=MDM_inst.pin['a1']).put() nd.Pin(name='opt_a1',pin=MDM_inst.pin['opt_a1'],type="optical:").put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b2',pin=MDM_inst.pin['a2']).put() nd.Pin(name='opt_b2',pin=MDM_inst.pin['opt_a2'],type="optical:").put() if (show_pins): nd.put_stub(pinsize=2) self.cell = C ## revised in 2026.06.07 by Qin Yue # legacy: self.L = np.abs(self.cell.pin['a1'].x - np.max([self.cell.pin['b1'].x,self.cell.pin['b2'].x])) self.L = np.abs(self.cell.pin['opt_a1'].x - np.max([self.cell.pin['opt_b1'].x,self.cell.pin['opt_b2'].x])) def generate_test_gds(self,gc,gc2gc_dX=140,gc2gc_dY=40,dX_offset=50): with nd.Cell(name=self.cell.cell_name+"_test", instantiate=False) as C: gc_cell = __cell_arg__(arg=gc,arg_name="gc",func_name="mxpicp::functional::Brag_WDM::generate_test_gds") # if (isinstance(gc,nd.Cell)): # gc_cell = gc # elif (hasattr(gc,"cell")): # gc_cell = gc.cell GC_I = gc_cell.put('g1',-gc2gc_dX/2,0,180) GC_O1 = gc_cell.put('g1', gc2gc_dX/2,0,0) GC_O2 = gc_cell.put('g1', gc2gc_dX/2+dX_offset,-gc2gc_dY,0) ## revised in 2026.06.07 by Qin Yue # legacy: INSTR = self.cell.put('a1',-self.L/2,0,0) INSTR = self.cell.put('opt_a1',-self.L/2,0,0) stripe=Route(radius=10, width=self.w_wg, xs="strip") ## revised in 2026.06.07 by Qin Yue # legacy: stripe.taper_p2p(pin1=INSTR.pin['a1'],pin2=GC_I.pin['g1'],arrow=False).put() stripe.taper_p2p(pin1=INSTR.pin['opt_a1'],pin2=GC_I.pin['g1'],arrow=False).put() ## revised in 2026.06.07 by Qin Yue # legacy: stripe.taper(pin=INSTR.pin['b1'],width1=INSTR.pin['b1'].width,width2=GC_O1.pin['g1'].width,length=10,arrow=False).put() stripe.taper(pin=INSTR.pin['opt_b1'],width1=INSTR.pin['opt_b1'].width,width2=GC_O1.pin['g1'].width,length=10,arrow=False).put() stripe.sbend_p2p(pin2=GC_O1.pin['g1'],arrow=False).put() ## revised in 2026.06.07 by Qin Yue # legacy: stripe.ubend_p2p(pin1=INSTR.pin['b2'],pin2=GC_O2.pin['g1'],arrow=False).put() stripe.ubend_p2p(pin1=INSTR.pin['opt_b2'],pin2=GC_O2.pin['g1'],arrow=False).put() return C