from typing import Optional import nazca as nd import numpy as np import math from ...routing import Route from ...geometry import * from ....technologies import * import pandas as pd from ...geometry import _my_polygon class Cross: """ Cross primitive component. This component builds the Cross layout cell. Parameters ---------- name : Optional[str], optional Unique identifier for the device cell. Default is None. L : list, optional Length parameter in microns. Default is [0, 1, 2, 3, 4]. w : list, optional Width parameter in microns. Default is [0.5, 0.45, 0.6, 0.4, 0.5]. xs : str, optional Layer or cross-section name used by the device. Default is 'strip'. show_pins : bool, optional Whether to draw pin markers in the generated layout. Default is False. """ def __init__(self, name: Optional[str] = None, L: list = [0 , 1, 2, 3, 4], w: list = [0.5,0.45,0.6,0.4,0.5], xs : str = 'strip', show_pins: bool=False ) -> None: self.name = name if (self.name==None): self.instantiate = False else : self.instantiate = True self.L = L self.w = w self.xs =xs self.cell = self.generate_gds(show_pins=show_pins) def generate_gds(self,show_pins): with nd.Cell(instantiate=self.instantiate,name=self.name) as C: for layers,growx,growy,acc in nd.layeriter(xs=self.xs): (a1,b1), (a2,b2),c1,c2 = growx L = np.array(self.L) L_arm = np.max(L) self.L_arm = L_arm w = np.array(self.w) + b1 - b2 vtx_x = np.r_[L,np.flip(L,0)] vtx_y = np.r_[w/2,-np.flip(w,0)/2] vtx = np.c_[vtx_x,vtx_y] _my_polygon(layer_wg=layers,vtx=vtx).put(-L_arm,0,0) _my_polygon(layer_wg=layers,vtx=vtx).put(0,-L_arm,90) _my_polygon(layer_wg=layers,vtx=vtx).put(0,L_arm,-90) _my_polygon(layer_wg=layers,vtx=vtx).put(L_arm,0,180) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a1',width=self.w[0]).put(-L_arm,0,180) nd.Pin(name='opt_a1',width=self.w[0],type="optical:").put(-L_arm,0,180) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='a2',width=self.w[0]).put( 0,-L_arm,-90) nd.Pin(name='opt_a2',width=self.w[0],type="optical:").put( 0,-L_arm,-90) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b2',width=self.w[0]).put( 0, L_arm, 90) nd.Pin(name='opt_b2',width=self.w[0],type="optical:").put( 0, L_arm, 90) ## revised in 2026.06.07 by Qin Yue # legacy: nd.Pin(name='b1',width=self.w[0]).put( L_arm,0,0) nd.Pin(name='opt_b1',width=self.w[0],type="optical:").put( L_arm,0,0) if (show_pins): nd.put_stub() return C def generate_test_gds(self,gc,num=5,dX_gc2gc=400,w_end=0.2,L_end=10): with nd.Cell(instantiate=False) as C: if (isinstance(gc,nd.Cell)): gc_cell = gc elif (hasattr(gc,'cell')): gc_cell = gc.cell else : raise Exception("ERROR: In , is not recongized") res = self.L_arm*2 dX = res*1.5 pic_strip = Route(radius=10,width=self.w[0],xs=self.xs) gc_In = gc_cell.put('g1',-dX_gc2gc/2,0,180) pin_pre = gc_In.pin['g1'] for _idx_ in range(0,num): inst = self.cell.put('a0',_idx_*dX - (num/2 - 1/2)*dX) ## revised in 2026.06.07 by Qin Yue # legacy: pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['a1'],arrow=False).put() pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['opt_a1'],arrow=False).put() ## revised in 2026.06.07 by Qin Yue # legacy: pin_pre = inst.pin['b1'] pin_pre = inst.pin['opt_b1'] ## revised in 2026.06.07 by Qin Yue # legacy: nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['b2']) nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['opt_b2']) nd.strt(length=L_end/2,width=w_end,xs=self.xs).put() ## revised in 2026.06.07 by Qin Yue # legacy: nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['a2']) nd.taper(length=L_end/2,width1=self.w[0],width2=w_end,xs=self.xs).put(inst.pin['opt_a2']) nd.strt(length=L_end/2,width=w_end,xs=self.xs).put() gc_Out = gc_cell.put('g1', dX_gc2gc/2,0,0) pic_strip.strt_p2p(pin1=pin_pre,pin2=gc_Out.pin['g1'],arrow=False).put() return C class Cross_Sine(Cross): """ Cross Sine primitive component. This component builds the Cross Sine layout cell. Parameters ---------- name : Optional[str], optional Unique identifier for the device cell. Default is None. res : list, optional Value for the res parameter. Default is [1, 1, 1, 1]. w : list, optional Width parameter in microns. Default is [0.5, 0.45, 0.6, 0.4, 0.5]. xs : str, optional Layer or cross-section name used by the device. Default is 'strip'. n_points : int, optional Value for the n_points parameter. Default is 4. show_pins : bool, optional Whether to draw pin markers in the generated layout. Default is False. """ def __init__(self, name: Optional[str] = None, res: list = [1,1,1,1], w: list = [0.5,0.45,0.6,0.4,0.5], xs : str = 'strip', n_points: int = 4, show_pins: bool=False ) -> None: L = 0 for _idx_ in range(0,len(w)-1): L_sect = np.linspace(L,L+res[_idx_],n_points) L = L+res[_idx_] w_sect = -np.cos((L_sect-L)/res[_idx_]*np.pi)*(w[_idx_]-w[_idx_+1])/2 + (w[_idx_]+w[_idx_+1])/2 if (_idx_==0): L_crs = L_sect w_crs = w_sect else : L_crs = np.r_[L_crs,L_sect] w_crs = np.r_[w_crs,w_sect] L_crs = np.r_[L_crs,L_crs[-1]+w_crs[-1]/2] w_crs = np.r_[w_crs,w_crs[-1]] super().__init__(name=name,L=L_crs,w=w_crs,xs=xs,show_pins=show_pins)