from typing import Optional from turtle import shape import nazca as nd import numpy as np import math from .taper import taper_xs2xs from ...routing import Route from ...structures import * from ....technologies import * from ...structures import _my_polygon,Conchoid """ Mono layer MMI """ class MMI_ML: def __init__(self, name: Optional[str]=None, L_arm: list=[10], w_arm: list=[0.45,1.35], xs: str = 'strip', arm_sine_width: bool=False, L_mmi: list = [10], w_mmi: list = [5,5], mmi_sine_width: bool=False, sharp_patch: bool=True, show_pins: bool = False, res: float = 0.01, N_out: int = 3, N_in: int = 1, Dp_out: float = 1.5, Dp_in: float = 1.5, ) -> None: self.name = name if (self.name==None): self.instantiate = False else : self.instantiate = True self.L_arm = L_arm self.xs = xs self.w_arm = w_arm self.arm_sine_width = arm_sine_width self.L_mmi = L_mmi self.w_mmi = w_mmi self.res = res self.N_out = N_out self.N_in = N_in self.Dp_out = Dp_out self.Dp_in = Dp_in self.mmi_sine_width = mmi_sine_width self.cell = self.generate_gds(sharp_patch=sharp_patch,show_pins=show_pins) self.L = np.sum(self.L_arm)*2+np.sum(self.L_mmi) def generate_gds(self,sharp_patch,show_pins): with nd.Cell(instantiate=self.instantiate,name=self.name) as C: L = 0 Lsg = [] Wsg = [] for idx in range(0,len(self.L_arm)): n_points = round(self.L_arm[idx]/self.res)+1 L_sect = np.linspace(L,L+self.L_arm[idx],n_points) Lsg = np.r_[Lsg,L_sect] if (self.arm_sine_width): dw = self.w_arm[idx+1]-self.w_arm[idx] w_sect = -np.cos(L_sect/self.L_arm[idx]*pi)*dw + (self.w_arm[idx+1]-self.w_arm[idx])/2 else: w_sect = np.linspace(self.w_arm[idx],self.w_arm[idx+1],n_points) Wsg = np.r_[Wsg,w_sect] L = L + self.L_arm[idx] with nd.Cell(instantiate=False) as Arm: for layers,growx,growy,acc in nd.layeriter(xs=self.xs): (a1,b1), (a2,b2),c1,c2 = growx vtx_y = np.r_[Wsg*a1+b1, np.flip(Wsg,0)*a2+b2] vtx_x = np.r_[Lsg, np.flip(Lsg,0)] vtx = np.c_[vtx_x,vtx_y] _my_polygon(layer_wg=layers,vtx=vtx).put(0,0,0) nd.Pin(name='a1',width=Wsg[0]).put(0,0,180) nd.Pin(name='b1',width=Wsg[-1]).put(L,0,0) """ For central MMI """ L_mmi = 0 Lsg_mmi = [] Wsg_mmi = [] for idx in range(0,len(self.L_mmi)): n_points = round(self.L_mmi[idx]/self.res)+1 L_sect = np.linspace(L_mmi,L_mmi+self.L_mmi[idx],n_points) Lsg_mmi = np.r_[Lsg_mmi,L_sect] if (self.arm_sine_width): dw = self.w_mmi[idx+1]-self.w_mmi[idx] w_sect = -np.cos(L_sect/self.L_mmi[idx]*pi)*dw + (self.w_mmi[idx+1]-self.w_mmi[idx])/2 else: w_sect = np.linspace(self.w_mmi[idx],self.w_mmi[idx+1],n_points) Wsg_mmi = np.r_[Wsg_mmi,w_sect] L_mmi = L_mmi + self.L_mmi[idx] with nd.Cell(instantiate=False) as MMI: for layers,growx,growy,acc in nd.layeriter(xs=self.xs): (a1,b1), (a2,b2),c1,c2 = growx vtx_y = np.r_[Wsg_mmi*a1+b1, np.flip(Wsg_mmi,0)*a2+b2] vtx_x = np.r_[Lsg_mmi, np.flip(Lsg_mmi,0)] vtx = np.c_[vtx_x,vtx_y] if (b1==0 and b2==0): _my_polygon(layer_wg=layers,vtx=vtx).put(0,0,0) else : w = max(Wsg_mmi)+b1*2 L = max(Lsg_mmi)+b1*2 nd.strt(length=L,layer=layers,width=w).put(-b1,0,0) nd.Pin(name='a1',width=Wsg_mmi[0]).put(0,0,180) nd.Pin(name='b1',width=Wsg_mmi[-1]).put(L_mmi,0,0) for idx_in in range(0,self.N_in): Arm_inst = Arm.put('b1',0,self.Dp_in*(-idx_in+(self.N_in-1)/2),180) nd.Pin(name='a'+str(round(idx_in+1)),pin=Arm_inst.pin['a1']).put() for idx_in in range(0,self.N_out): Arm_inst = Arm.put('b1',L_mmi,self.Dp_out*(-idx_in+(self.N_out-1)/2),0) nd.Pin(name='b'+str(round(idx_in+1)),pin=Arm_inst.pin['a1']).put() MMI.put('a1',0,0,0) if (show_pins): nd.put_stub() return C def generate_test_gds(self,gc,dX_gc2gc,dY_gc2gc,R_bend=10,Xout_offset=50): if (isinstance(gc,nd.Cell)): gc_cell =gc elif (hasattr(gc,'cell')): gc_cell = gc.cell else : raise Exception("ERROR: In , is not recongized as a cell") with nd.Cell(instantiate=False) as C: INST = self.cell.put(-self.L/2,0,0) pic_strip = Route(width=self.w_arm[0],radius=R_bend,xs=self.xs) for idx_in in range(0,self.N_in): GC = gc_cell.put('g1',-dX_gc2gc/2,dY_gc2gc*(-idx_in + (self.N_in-1)/2),180) pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['a'+str(idx_in+1)],Lstart=dX_gc2gc/10).put() for idx_in in range(0,self.N_out): toggle = np.mod(idx_in,2)-0.5 GC = gc_cell.put('g1', dX_gc2gc/2+Xout_offset*toggle,dY_gc2gc*(-idx_in + (self.N_out-1)/2),0) pic_strip.sbend_p2p(pin1=GC.pin['g1'],pin2=INST.pin['b'+str(idx_in+1)],Lstart=dX_gc2gc/10).put() return C class MMI_STD(MMI_ML): def __init__(self, name: Optional[str]=None, N_out: int=3, N_in: int=1, L_arm: int=10, w_wg: float=0.45, w_port: float = 1.2, xs: str='strip', L_mmi: int=10, w_mmi: float=5, sharp_patch: bool=True, show_pins: bool=False, Dp_out: float=1.5, Dp_in: float=1.5) -> None: """ Standard MMI with multiple input and output Args: L_arm (int, optional): _description_. Defaults to 10. w_wg (float, optional): _description_. Defaults to 0.45. w_port (float, optional): _description_. Defaults to 1.2. xs (str, optional): _description_. Defaults to 'strip'. arm_sine_width (bool, optional): _description_. Defaults to False. L_mmi (int, optional): _description_. Defaults to 10. w_mmi (int, optional): _description_. Defaults to 5. mmi_sine_width (bool, optional): _description_. Defaults to False. sharp_patch (bool, optional): _description_. Defaults to True. show_pins (bool, optional): _description_. Defaults to False. res (float, optional): _description_. Defaults to 0.01. N_out (int, optional): _description_. Defaults to 3. N_in (int, optional): _description_. Defaults to 1. Dp_out (float, optional): _description_. Defaults to 1.5. Dp_in (float, optional): _description_. Defaults to 1.5. """ super().__init__(name=name, L_arm=[L_arm], w_arm=[w_wg,w_port], xs=xs, arm_sine_width=False, L_mmi=[L_mmi], w_mmi=[w_mmi,w_mmi], mmi_sine_width=False, sharp_patch=sharp_patch, show_pins=show_pins, res=min([L_mmi,L_arm]), ## taper resolution N_out=N_out, N_in=N_in, Dp_out=Dp_out, Dp_in=Dp_in)