build_all, build_images, build_handbook revised so that the html is not ready to use.

This commit is contained in:
=
2026-06-07 20:30:23 +08:00
parent 54d20eb154
commit a4ac88f002
334 changed files with 1309 additions and 8710 deletions
-1
View File
@@ -13,5 +13,4 @@ from . import geometry
from . import primitives
from . import composites
from . import electronics
from . import pdks
from . import others
-44
View File
@@ -1,44 +0,0 @@
import nazca as nd
from ..gds_devices import gds_lib_load
class GC_TE_1550(gds_lib_load) :
'''
CUMEC TE Grating Coupler at 1550nm.
'''
def __init__(self,pdk_path: str="AMF_IPKISS_PDK") -> None:
lib_path = pdk_path
lib_name = "AMF_PDK_BB"
cell_name = "AMF_Si_GC1D_Cband_v3p0"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False)
self.w_wg = 0.5
self.add_pin(pin_name="a0", xya=(0,0,180))
self.add_pin(pin_name="g1", xya=(0,0,180), width=0.5)
class GC_TE_1310(gds_lib_load) :
'''
CUMEC TE Grating Coupler at 1310nm.
'''
def __init__(self,pdk_path: str="AMF_IPKISS_PDK") -> None:
lib_path = pdk_path
lib_name = "AMF_PDK_BB"
cell_name = "AMF_Si_GC1D_Oband_v3p0"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False)
self.w_wg = 0.41
self.add_pin(pin_name="a0", xya=(0,0,180))
self.add_pin(pin_name="g1", xya=(0,0,180), width=0.41)
class PD_Cband_Cell(gds_lib_load) :
'''
AMF Ge Power Monitor Cell at Cband.
'''
def __init__(self,pdk_path: str="AMF_IPKISS_PDK") -> None:
lib_path = pdk_path
lib_name = "AMF_PDK_BB"
cell_name = "AMF_Ge_PowMonitor_Cband_Cell_v3p0"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False)
self.w_wg = 0.5
self.add_pin(pin_name="a0", xya=(0,0,180))
self.add_pin(pin_name="a1", xya=(0,0,180), width=0.5)
self.add_pin(pin_name="ep1", xya=(129.8,0,0), width=5)
self.add_pin(pin_name="en1", xya=(129.8,(9+5.3)/2,0), width=3.7)
self.add_pin(pin_name="en2", xya=(129.8,-(9+5.3)/2,0), width=3.7)
-254
View File
@@ -1,254 +0,0 @@
from ..gds_devices import gds_lib_load
import nazca as nd
from ..routing import Route
from ..electronics import PADs
CUMEC_LAYER_MAP = {
(31,1): 'STRIP_COR',
(31,2): 'STRIP_CLD',
(31,3): 'STRIP_TRE',
(31,4): 'STRIP_HOL',
(32,1): 'SRIB_COR',
(32,2): 'SRIB_CLD',
(32,3): 'SRIB_TRE',
(32,4): 'SRIB_HOL',
(33,1): 'RIB_COR',
(33,2): 'RIB_CLD',
(33,3): 'RIB_TRE',
(33,4): 'RIB_HOL',
(11,1): 'METAL',
(12,1): 'METAL_2',
(51,1): 'VIA_H2M',
(60,0): 'PASS1',
(63,0): 'PASS2',
(20,0): 'PAD',
(61,0): 'GC_OPEN',
}
class PAD_60_80(gds_lib_load) :
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\bondpads"
lib_name = "BP_60_80"
cellname = "Fixed_BP_60_80"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False)
self.add_pin(pin_name='p1',xya=(0,0,-90))
class GPD_1550(gds_lib_load):
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\photodetector"
lib_name = "GPD_1550_unit"
cell_name = "Fixed_GPD_1550_unit"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["Fixed_GPD_1550_unit"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.45
self.length = 110.4
self.add_pin(pin_name='ep1', xya=(55.2, 3.325, 90), width=1) ## anode
self.add_pin(pin_name='en1', xya=(55.2,-3.325,-90), width=1) ## cathod
self.add_pin(pin_name='a1', xya=(0,0,180), width=0.45)
self.add_pin(pin_name='b1', xya=(110.4,0,0), width=self.w_wg)
class EC_1550(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\edge_couplers"
lib_name = "EC_1550"
cell_name = "Fixed_EC_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["Fixed_EC_1550"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.45
self.length = 689.9
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
self.add_pin(pin_name='b0', xya=(-673.9,0,180))
self.add_pin(pin_name='a0',xya=(-673.9,0,0))
class GC_TE_1550(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\grating_couplers"
lib_name = "GC_TE_1550"
cell_name = "Fixed_GC_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,cellsreused=["Fixed_GC_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
def generate_test_gds(self,gc2gc_dX=300):
with nd.Cell(name=self.cell.cell_name+"_test",instantiate=False) as C:
gc_input = self.cell.put('g1',-gc2gc_dX/2,0,180)
gc_output = self.cell.put('g1',gc2gc_dX/2,0,0)
stripe=Route(radius=5, width=self.w_wg, xs="strip")
stripe.strt_p2p(pin1=gc_input.pin['g1'],pin2=gc_output.pin['g1'],arrow=False).put()
return C
class GC_TM_1550(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\grating_couplers"
lib_name = "GC_TM_1550"
cell_name = "Fixed_GC_TM_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,cellsreused=["Fixed_GC_TM_1550"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.5
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
def generate_test_gds(self,gc2gc_dX=300):
with nd.Cell(name=self.cell.cell_name+"_test",instantiate=False) as C:
gc_input = self.cell.put('g1',-gc2gc_dX/2,0,180)
gc_output = self.cell.put('g1',gc2gc_dX/2,0,0)
stripe=Route(radius=5, width=self.w_wg, xs="strip")
stripe.strt_p2p(pin1=gc_input.pin['g1'],pin2=gc_output.pin['g1'],arrow=False).put()
return C
class GC_TE_1310(gds_lib_load):
'''
CUMEC TE Grating Coupler at 1310nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\grating_couplers"
lib_name = "GC_TE_1310"
cell_name = "Fixed_GC_TE_1310"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,cellsreused=["Fixed_GC_TE_1310"],layermap=CUMEC_LAYER_MAP)
self.w_wg = 0.38
self.add_pin(pin_name='g1', xya=(0,0,0), width=self.w_wg)
class MMI_1x2_TE_1550(gds_lib_load):
'''
CUMEC TE 1by 2 MMI at 1550nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK",sharp_patch: bool=True) -> None:
lib_path = pdk_path + "\\mmis"
lib_name = "M1X2_TE_1550"
cellname = "Fixed_M1X2_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_M1X2_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.length = 12
self.width = 1.55
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,0,180), width=self.w_wg)
self.add_pin(pin_name='b1', xya=(self.length,self.width/2,0), width=self.w_wg)
self.add_pin(pin_name='b2', xya=(self.length,-self.width/2,0), width=self.w_wg)
def generate_test_gds(self,gc,gc2gc_length=300):
with nd.Cell(name=self.cell.cell_name+"_test", instantiate=False) as C:
gc_input = gc.cell.put('g1',0,0,180)
gc_output_1 = gc.cell.put('g1',gc2gc_length, 20,0)
gc_output_2 = gc.cell.put('g1',gc2gc_length,-20,0)
# Put DC
dc = self.cell.put('a1',gc_input.pin['g1'].move((gc2gc_length-self.length)/2,0,0))
# Connect all the ports
stripe=Route(radius=5, width=self.w_wg, xs="strip")
stripe.sbend_route_p2p(pin1=gc_input.pin['g1'],pin2=dc.pin['a1'],arrow=False).put()
stripe.sbend_route_p2p(pin1=gc_output_1.pin['g1'],pin2=dc.pin['b1'],arrow=False).put()
stripe.sbend_route_p2p(pin1=gc_output_2.pin['g1'],pin2=dc.pin['b2'],arrow=False).put()
return C
class MMI_1x2_TE_1310(gds_lib_load):
'''
CUMEC TE 1by 2 MMI at 1310nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK",sharp_patch: bool=True) -> None:
lib_path = pdk_path + "\\mmis"
lib_name = "M1X2_TE_1310"
cellname = "Fixed_M1X2_TE_1310"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_M1X2_TE_1310"],layermap=CUMEC_LAYER_MAP)
self.length = 15
self.width = 1.45
self.w_wg = 0.38
self.add_pin(pin_name='a1', xya=(0,0,180), width=self.w_wg)
self.add_pin(pin_name='b1', xya=(self.length,self.width/2,0), width=self.w_wg)
self.add_pin(pin_name='b2', xya=(self.length,-self.width/2,0), width=self.w_wg)
class MMI_2x2_TE_1550(gds_lib_load):
'''
CUMEC TE 1by 2 MMI at 1310nm.
'''
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\mmis"
lib_name = "M2X2_TE_1550"
cellname = "Fixed_M2X2_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_M2X2_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.length = 125.4
self.width = 3
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,self.width/2,180), width=self.w_wg)
self.add_pin(pin_name='a2', xya=(0,-self.width/2,180), width=self.w_wg)
self.add_pin(pin_name='b1', xya=(self.length,self.width/2,0), width=self.w_wg)
self.add_pin(pin_name='b2', xya=(self.length,-self.width/2,0), width=self.w_wg)
class CRX_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\crossings"
lib_name = "X_TE_1550"
cellname = "Fixed_X_TE_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Fixed_X_TE_1550"],layermap=CUMEC_LAYER_MAP)
self.length = 5
self.width = 5
self.w_wg = 0.45
self.xs = 'strip'
self.L_arm = 5
self.add_pin(pin_name='a1',xya=(-5,0,180),width=self.w_wg)
self.add_pin(pin_name='b1',xya=( 5,0,0),width=self.w_wg)
self.add_pin(pin_name='a2',xya=( 0,5,90),width=self.w_wg)
self.add_pin(pin_name='b2',xya=( 0,-5,-90),width=self.w_wg)
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 <mxpiv::passive::cross::generate_test_gds>, <gc> is not recongized")
dL = self.L_arm*2
dX = dL*1.75
pic_strip = Route(radius=10,width=self.w_wg,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)
pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['a1'],arrow=False).put()
pin_pre = inst.pin['b1']
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['b2'])
nd.strt(length=L_end/2,width=w_end,xs=self.xs).put()
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['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 PBS_1550(gds_lib_load):
def __init__(self,pdk_path: str="CUMEC_SiP130Cu_PDK") -> None:
lib_path = pdk_path + "\\polarization_beam_splitter"
lib_name = "PBS_1550"
cellname = "Fixed_PBS_1550"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=cellname,layermap=CUMEC_LAYER_MAP)
self.length = 5
self.width = 5
self.w_wg = 0.45
self.xs = 'strip'
self.add_pin(pin_name='a1',xya=(-0,0,180),width=self.w_wg)
self.add_pin(pin_name='b1',xya=( 87.2,0,0),width=self.w_wg)
self.add_pin(pin_name='b2',xya=( 87.2,-20,0),width=self.w_wg)
-288
View File
@@ -1,288 +0,0 @@
from ..gds_devices import gds_lib_load
import nazca as nd
from ..routing import Route
from ..electronics import PADs
IMECAS_LAYER_MAP = {
(10,2): 'STRIP_COR',
(10,3): 'STRIP_CLD',
(10,4): 'STRIP_TRE',
(11,2): 'SRIB_COR',
(11,3): 'SRIB_CLD',
(11,4): 'SRIB_TRE',
(12,2): 'RIB_COR',
(12,3): 'RIB_CLD',
(12,4): 'RIB_TRE',
(31,0): 'METAL',
(34,0): 'METAL_2',
(36,0): 'PAD',
(80,0): 'DETCH',
}
class Template(gds_lib_load) :
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "IMECAS-templete"
cell_name = "IMECASTEST"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,cellsreused=["IMECASTEST"],layermap=IMECAS_LAYER_MAP)
class EC_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "EdegeCoupler_0_18_0_45"
cell_name = "EdegeCoupler_0_18_0_45"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["EdegeCoupler_0_18_0_45"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(220.00000,2.089,0), width=0.45)
self.add_pin(pin_name='a0', xya=(0,0,0))
class GC_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "FGC_C_TE_WG450"
cell_name = "FGC_C_TE_WG450"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["FGC_C_TE_WG450"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(43.91100,15,0), width=0.45)
self.add_pin(pin_name='a0', xya=(0,0,0))
class GC_TM_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "FGC_C_TM_WG450"
cell_name = "FGC_C_TM_WG450"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["FGC_C_TM_WG450"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(44.40100,15,0), width=0.45)
self.add_pin(pin_name='a0', xya=(0,0,0))
class GC_TE_1310(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "FGC_O_TE_WG380"
cell_name = "FGC_O_TE_WG380"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["FGC_O_TE_WG380"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(46.00000,15,0), width=0.38)
self.add_pin(pin_name='a0', xya=(0,0,0))
class GC_TM_1310(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "FGC_O_TM_WG380"
cell_name = "FGC_O_TM_WG380"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["FGC_O_TM_WG380"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(45.35500,15,0), width=0.38)
self.add_pin(pin_name='a0', xya=(0,0,0))
class DC_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "DC_C_TE_3dB"
cell_name = "DC_C_TE_3dB"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["DC_C_TE_3dB"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,62.225,180), width=0.45)
self.add_pin(pin_name='a2', xya=(0, 2.225,180), width=0.45)
self.add_pin(pin_name='b1', xya=(67.33700,62.225,0), width=0.45)
self.add_pin(pin_name='b2', xya=(67.33700, 2.225,0), width=0.45)
self.add_pin(pin_name='a0', xya=(0,32.225,180))
self.add_pin(pin_name='b0', xya=(67.33700,32.225,0))
class MMI_2x2_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "MMI2x2_C_SE_WG450"
cell_name = "MMI2x2_C_SE_WG450"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["MMI2x2_C_SE_WG450"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,11.325,180), width=0.45)
self.add_pin(pin_name='a2', xya=(0, 8.675,180), width=0.45)
self.add_pin(pin_name='b1', xya=(157.20000,11.325,0), width=0.45)
self.add_pin(pin_name='b2', xya=(157.20000, 8.675,0), width=0.45)
self.add_pin(pin_name='a0', xya=(157.20000/2,10, 0))
self.add_pin(pin_name='b0', xya=(157.20000/2,10,180))
class MMI_1x2_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "MMI1X2_C_WG450"
cell_name = "MMI1X2_C_WG450"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["MMI1X2_C_WG450"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.length = 12.41900
self.add_pin(pin_name='a1', xya=(0,3,180), width=0.45)
self.add_pin(pin_name='b1', xya=(12.41900,3.5,0), width=0.45)
self.add_pin(pin_name='b2', xya=(12.41900,2.5,0), width=0.45)
self.add_pin(pin_name='a0', xya=(12.41900/2,3, 0))
self.add_pin(pin_name='b0', xya=(12.41900/2,3,180))
class MMI_2x2_TE_1310(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "MMI2x2_O_WG380"
cell_name = "MMI2x2_O_WG380"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["MMI2x2_O_WG380"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,4,180), width=0.38)
self.add_pin(pin_name='a2', xya=(0, 3,180), width=0.38)
self.add_pin(pin_name='b1', xya=(25.30000,4,0), width=0.38)
self.add_pin(pin_name='b2', xya=(25.30000,3,0), width=0.38)
self.add_pin(pin_name='a0', xya=(25.30000/2,3.5, 0))
self.add_pin(pin_name='b0', xya=(25.30000/2,3.5,180))
class MMI_1x2_TE_1310(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "MMI1x2_O_WG380"
cell_name = "MMI1x2_O_WG380"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["MMI1x2_O_WG380"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,4,180), width=0.38)
self.add_pin(pin_name='b1', xya=(16.67800,4.5,0), width=0.38)
self.add_pin(pin_name='b2', xya=(16.67800,3.5,0), width=0.38)
self.add_pin(pin_name='a0', xya=(16.67800/2,3, 0))
self.add_pin(pin_name='b0', xya=(16.67800/2,3,180))
class Ybranch_TE(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "Ybranch_C_TE"
cell_name = "Ybranch_C_TE"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False,
cellsreused=["Ybranch_C_TE"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='a1', xya=(0,4,180), width=0.45)
self.add_pin(pin_name='b1', xya=(14.00000,4.875,0), width=0.45)
self.add_pin(pin_name='b2', xya=(14.00000,2.225,0), width=0.45)
self.add_pin(pin_name='a0', xya=(14.00000/2,3.05, 0))
self.add_pin(pin_name='b0', xya=(14.00000/2,3.05,180))
class CRX_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "Crossing_C_TE"
cellname = "Crossing_C_TE"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Crossing_C_TE"],layermap=IMECAS_LAYER_MAP)
self.length = 5
self.width = 5
self.w_wg = 0.45
self.xs = 'strip'
self.L_arm = 9.96400/2
self.add_pin(pin_name='a1',xya=( 0 ,4.982 ,180),width=self.w_wg)
self.add_pin(pin_name='b1',xya=( 9.96400,4.982 ,0),width=self.w_wg)
self.add_pin(pin_name='a2',xya=( 4.982 ,9.96400,90),width=self.w_wg)
self.add_pin(pin_name='b2',xya=( 4.982 ,0 ,-90),width=self.w_wg)
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 <mxpiv::passive::cross::generate_test_gds>, <gc> is not recongized")
dL = self.L_arm*2
dX = dL*1.75
pic_strip = Route(radius=10,width=self.w_wg,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)
pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['a1'],arrow=False).put()
pin_pre = inst.pin['b1']
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['b2'])
nd.strt(length=L_end/2,width=w_end,xs=self.xs).put()
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['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 CRX_TE_1310(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "Crossing_O_TE"
cellname = "Crossing_O_TE"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cellname, rename=cellname+"_WithPin", instantiate=False,cellsreused=["Crossing_O_TE"],layermap=IMECAS_LAYER_MAP)
self.length = 5
self.width = 5
self.w_wg = 0.38
self.xs = 'strip'
self.L_arm = 11.8280/2
self.add_pin(pin_name='a1',xya=( 0 ,5.914 ,180),width=self.w_wg)
self.add_pin(pin_name='b1',xya=( 11.8280,5.914 ,0),width=self.w_wg)
self.add_pin(pin_name='a2',xya=( 5.914 ,11.8280,90),width=self.w_wg)
self.add_pin(pin_name='b2',xya=( 5.914 ,0 ,-90),width=self.w_wg)
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 <mxpiv::passive::cross::generate_test_gds>, <gc> is not recongized")
dL = self.L_arm*2
dX = dL*1.75
pic_strip = Route(radius=10,width=self.w_wg,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)
pic_strip.strt_p2p(pin1=pin_pre,pin2=inst.pin['a1'],arrow=False).put()
pin_pre = inst.pin['b1']
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['b2'])
nd.strt(length=L_end/2,width=w_end,xs=self.xs).put()
nd.taper(length=L_end/2,width1=self.w_wg,width2=w_end,xs=self.xs).put(inst.pin['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 EC_TE_1550(gds_lib_load):
def __init__(self,pdk_path: str="IMECAS_PDK2.1") -> None:
lib_path = pdk_path
lib_name = "EdegeCoupler_0_18_0_45"
cell_name = "EdegeCoupler_0_18_0_45"
super().__init__(lib_path=lib_path, lib_name=lib_name, cell_name=cell_name, rename=cell_name+"_WithPin", instantiate=False, cellsreused=["EdegeCoupler_0_18_0_45"],layermap=IMECAS_LAYER_MAP)
self.w_wg = 0.45
self.add_pin(pin_name='g1', xya=(220.00000,2.089,0), width=0.45)
self.add_pin(pin_name='a0', xya=(0,0,0))
-5
View File
@@ -1,5 +0,0 @@
from . import AMF_pdk
from . import CUMEC_pdk
from . import IMECAS_pdk
from . import hgl_pdk_A
from . import qy_pdk_A
-52
View File
@@ -1,52 +0,0 @@
import numpy as np
from ..primitives.passive import DC_bend
class DC_bend_50_50_Cband(DC_bend):
def __init__(self, w_wg: float, show_pins: bool=False) -> None:
'''
This is a wideband 50/50 Direction Coupler based on bend directional coupler, from 1500nm to 1600nm.
'''
w_in = 0.45
w_out = 0.45
gap = 0.2
r_in = 60
coupling_length = 19.08
theta_arc = coupling_length / (r_in+gap/2+w_in/2) * 180 / np.pi
super().__init__(w_in=w_in, w_out=w_out, gap=gap, r_in=r_in, theta_arc=theta_arc, w_wg=w_wg, theta_ext=10, xs_wg="strip", show_pins=show_pins)
self.cell = self.generate_gds(cellname="_50_50_Cband")
class DC_bend_20_80_Cband(DC_bend):
'''
This is a wideband 20/80 Direction Coupler based on bend directional coupler, from 1500nm to 1600nm.
Through: 80%
Cross: 20%
'''
def __init__(self, w_wg: float, show_pins: bool=False) -> None:
w_in = 0.45
w_out = 0.45
gap = 0.2
r_in = 41
coupling_length = 19.6
theta_arc = coupling_length / (r_in+gap/2+w_in/2) * 180 / np.pi
super().__init__(w_in=w_in, w_out=w_out, gap=gap, r_in=r_in, theta_arc=theta_arc, w_wg=w_wg, theta_ext=10, xs_wg="strip", show_pins=show_pins)
self.generate_gds(cellname="_20_80_Cband")
class DC_bend_4_96_Cband(DC_bend):
'''
This is a wideband 20/80 Direction Coupler based on bend directional coupler, from 1500nm to 1600nm.
Through: 96%
Cross: 4%
'''
def __init__(self, w_wg: float, show_pins: bool=False) -> None:
w_in = 0.45
w_out = 0.45
gap = 0.2
r_in = 30
coupling_length = 18.9
theta_arc = coupling_length / (r_in+gap/2+w_in/2) * 180 / np.pi
super().__init__(w_in=w_in, w_out=w_out, gap=gap, r_in=r_in, theta_arc=theta_arc, w_wg=w_wg, theta_ext=10, xs_wg="strip", show_pins=show_pins)
self.generate_gds(cellname="_4_96_Cband")
-146
View File
@@ -1,146 +0,0 @@
from typing import Optional
import numpy as np
import nazca as nd
from ..primitives.passive import *
from ..gds_devices import generate_gds_lib
""" test passed, in ANT-20230228 submission """
class DC_pX3_50_50_Cband(DC_pX_3sg):
def __init__(self, w_wg: float=0.5,gds_lib_generate: bool=False,name: Optional[str]=None) -> None:
# DC_50_50_pX3 = mx.passive.DC_pX_3sg(name="DC_50_50_pX3",Lc1=33, Lp1=0.55, Lc2=15, Lt=1, w_cp=0.5, dw=0.1, gap=0.2, R0=17.5, A=20, w_wg=0.5, pX_type='symmetric', sharp_patch=True)
super().__init__(name=name,xs_wg='strip', Lc1=33, Lp1=0.55, Lc2=15, Lt=1, w_cp=0.5, dw=0.1, gap=0.2, R0=17.5, A=20, w_wg=w_wg, pX_type='symmetric', sharp_patch=True)
if (gds_lib_generate):
self.generate_gds_lib()
def generate_gds_lib(self):
generate_gds_lib("DC_pX3_50_50_Cband",self.cell,with_txt=True)
class MMG_1D_D14um_1550_2modes(GC_STD_1D):
def __init__(self, w_wg: float = 0.5, gds_lib_generate:bool=False) -> None:
pitch_1D_apodized = np.linspace(0.602,0.602,40)
eta_1D_apodized = np.linspace(0.389,0.613,40)
super().__init__(xs_wg='strip', w_wg=w_wg, etch_type='SETCH', xs_open='gc_open', L_taper=500, L_end=5, A_taper=2.5,
Pitch=pitch_1D_apodized, eta_etch=eta_1D_apodized, num=len(eta_1D_apodized), shape='rectangle')
if (gds_lib_generate):
self.generate_gds_lib()
def generate_gds_lib(self):
generate_gds_lib("MMG_1D_D14um_1550_2modes",self.cell,with_txt=True)
""" Aborted due to failure testing, 2022.12.30 """
class MDM_ADC_TE1_1550(MDM):
def __init__(self,w_wg: float=0.45,gds_lib_generate: bool=False) -> None:
"""
w_wg the single mode input for the device
"""
self.wb0 = 0.44
self.wb1 = 0.61
self.wb_in = 0.45
self.wb_out = 0.85
self.w0 = 0.33
self.w1 = 0.2
self.w_wg = w_wg
self.xs='strip'
self.Lt_bus = 22
self.Lt_cp = 22
self.R0 = 40
self.Rmin=8
self.angle=22.5
self.gap0=0.2
self.gap1=0.2
super().__init__(xs=self.xs,
wb0=self.wb0, wb1=self.wb1, wb_in=self.wb_in, wb_out=self.wb_out,
w_wg=self.w_wg, w0=self.w0, w1=self.w1,
gap0=self.gap0, Lt_bus=self.Lt_bus, R0=self.R0, angle=self.angle, Lt_cp=self.Lt_cp, gap1=self.gap1,
name=None, Lb0=None, symmetric_BUS=False, single_end=True)
if (gds_lib_generate):
self.generate_gds_lib()
def generate_gds_lib(self):
generate_gds_lib("MDM_ADC_TE1_1550",self.cell,with_txt=True)
class MDM_ADC_TE2_1550(MDM):
def __init__(self,w_wg: float=0.45,gds_lib_generate: bool=False) -> None:
"""
w_wg the single mode input for the device
"""
self.wb0 = 0.85
self.wb1 = 1.04
self.wb_in = 0.85
self.wb_out = 1.2
self.w0 = 0.33
self.w1 = 0.2
self.w_wg = w_wg
self.xs='strip'
self.Lt_bus = 32
self.Lt_cp = 32
self.R0 = 40
self.Rmin=8
self.angle=22.5
self.gap0=0.2
self.gap1=0.2
super().__init__(xs=self.xs,
wb0=self.wb0, wb1=self.wb1, wb_in=self.wb_in, wb_out=self.wb_out,
w_wg=self.w_wg, w0=self.w0, w1=self.w1,
gap0=self.gap0, Lt_bus=self.Lt_bus, R0=self.R0, angle=self.angle, Lt_cp=self.Lt_cp, gap1=self.gap1,
name=None, Lb0=None, symmetric_BUS=False, single_end=None)
if (gds_lib_generate):
self.generate_gds_lib()
def generate_gds_lib(self):
generate_gds_lib("MDM_ADC_TE2_1550",self.cell,with_txt=True)
class MDM_ADC_TE3_1550(MDM):
def __init__(self,w_wg: float=0.45,gds_lib_generate: bool=False) -> None:
"""
w_wg the single mode input for the device
"""
self.wb0 = 1.25
self.wb1 = 1.41
self.wb_in = 1.2
self.wb_out = 1.8
self.w0 = 0.33
self.w1 = 0.2
self.w_wg = w_wg
self.xs = 'strip'
self.Lt_bus = 70
self.Lt_cp = 70
self.R0 = 40
self.Rmin=8
self.angle=22.5
self.gap0=0.2
self.gap1=0.2
super().__init__(xs=self.xs,
wb0=self.wb0, wb1=self.wb1, wb_in=self.wb_in, wb_out=self.wb_out,
w_wg=self.w_wg, w0=self.w0, w1=self.w1,
gap0=self.gap0, Lt_bus=self.Lt_bus, R0=self.R0, angle=self.angle, Lt_cp=self.Lt_cp, gap1=self.gap1,
name=None, Lb0=None, symmetric_BUS=False, single_end=None)
if (gds_lib_generate):
self.generate_gds_lib()
def generate_gds_lib(self):
generate_gds_lib("MDM_ADC_TE3_1550",self.cell,with_txt=True)
@@ -1,250 +0,0 @@
import nazca as nd
import numpy as np
from scipy.interpolate import CubicSpline
from ...routing import Route
from ..geometry import *
from ...foundries import *
import pandas as pd
from ..geometry import _my_polygon
from ...basic import __cell_arg__
class YBranch:
"""
Broadband spline-shaped Y-branch with two bent output ports.
Parameters
----------
name : str or None, optional
Nazca cell name. ``None`` keeps the cell uninstantiated (default is None).
xs : str, optional
Cross-section key used for both the taper body and attachments (default is "strip").
w : Sequence[float], optional
Width control points (µm) used by the cubic spline along the taper axis.
Length must be >= 2. Default is ``[1.2, 1.0, 1.8, 1.2, 1.0, 1.2, 1.2]``.
L : float, optional
Total spline length in microns (default is 6).
R_att : float, optional
Bend radius of each attachment waveguide in microns (default is 10).
A_att : float, optional
Bend angle (degrees) per attachment arc (default is 10).
w_port : float, optional
Output port width in microns (default is 0.45).
show_pins : bool, optional
Draw Nazca stub markers when True (default is False).
sharp_patch : bool, optional
Add chamfer helpers inside polygons when True (default is True).
res : float, optional
Longitudinal sampling pitch (µm) for polygon discretization (default is 0.1).
"""
def __init__(self,
name : str = None,
xs : str = 'strip',
w : 'list|np.ndarray' = [1.2,1.0,1.8,1.2,1.0,1.2,1.2],
L : float = 6,
R_att : float = 10,
A_att : float = 10,
w_port : float = 0.45,
show_pins : bool = False,
sharp_patch : bool = True,
res : float = 0.1,
) -> None:
self.name = name
if (name!=None):
self.instantiate = True
else :
self.instantiate = False
self.w = w
self.L = L
self.res = res
self.R_att = R_att
self.A_att = A_att
self.w_port = w_port
self.xs = xs
self.cell = self.generate_gds(show_pins=show_pins,sharp_patch=sharp_patch)
def generate_gds(self,show_pins=False,sharp_patch=True):
with nd.Cell(name=self.name,instantiate=self.instantiate) as C:
w = np.r_[self.w]
n_sects = len(self.w)-1
res = self.L/n_sects
n_points = int(self.L/self.res)+1
L = np.linspace(0,self.L,n_sects+1)
L_act = np.linspace(0,self.L,n_points)
f = CubicSpline(L,w) ## cubic spline interpolant
w_act = f(L_act)
for layers,growx,growy,acc in nd.layeriter(xs=self.xs):
(a1,b1), (a2,b2),c1,c2 = growx
w_cur = w_act*(a1-a2) + (b1-b2)
if (b1!=0 and b2!=0):
w_cur = max(w_cur)*np.ones(np.shape(w_cur))
vtx_x = np.r_[L_act,np.flip(L_act,0)]
vtx_y = np.r_[w_cur/2,-np.flip(w_cur/2,0)]
vtx = np.c_[vtx_x,vtx_y]
_my_polygon(layer_wg=layers,vtx=vtx).put(0,0,0)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('a1',self.L,self.w[-1]/2 - self.w_port/2,0)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('a1',temp.pin['b1'],flip=1)
nd.Pin(name='b1',width=self.w_port).put(temp.pin['b1'])
temp = circle(xs=self.xs,radius=self.R_att,theta_start=0,theta_stop=self.A_att,width=self.w_port).cell.put('a1',self.L,-self.w[-1]/2 + self.w_port/2,0,flip=1)
temp = circle(xs=self.xs,radius=self.R_att,theta_start=-self.A_att,theta_stop=0,width=self.w_port).cell.put('a1',temp.pin['b1'],flip=0)
nd.Pin(name='b2',width=self.w_port).put(temp.pin['b1'])
nd.Pin(name='a1',width=self.w[0]).put(0,0,180)
if (show_pins):
nd.put_stub()
return C
class Ybranch_3wg:
"""
Initialization of a symmetric tapered coupler for 3dB coupling
Parameters
----------
name : str or None, optional
Nazca cell name (default is None).
1. taper part
w0 : float, optional
Width (µm) of the center arm at the coupling region entrance (default is 0.4).
w1 : float, optional
Width (µm) of the outer arms at the coupling region exit (default is 0.2).
gap : float, optional
Vertical spacing (µm) between adjacent arms inside the coupler (default is 0.18).
Lcp : float, optional
Length (µm) of each taper section forming the coupler (default is 20).
xs : str, optional
Cross-section key for all segments (default is "strip").
2. attachment part
w_wg : float, optional
External IO waveguide width in microns (default is 0.45).
R0 : float, optional
Bend radius (µm) used for both output waveguides (default is 10).
angle : float, optional
Bend deflection angle in degrees (default is 20).
L_attach : float, optional
Length (µm) of straight sections appended after the output tapers (default is 3).
L_in_tp : float, optional
Taper length (µm) that links the IO waveguide to width ``w0`` (default is 3).
sharp_patch : bool, optional
Insert chamfer helpers when True (default is True).
"""
def __init__(self,
name = None,
w0:float=0.4,
w1:float=0.2,
gap:float=0.18,
Lcp:float=20,
xs:str='strip',
w_wg:float=0.45,
R0:float=10,
angle:float=20,
L_attach:float=3,
L_in_tp:float=3,
sharp_patch:bool=True):
self.name = name
if (self.name==None):
self.instantiate = False
else :
self.instantiate = True
self.w0 = w0
self.w1 = w1
self.gap = gap
self.Lcp = Lcp
self.xs = xs
self.w_wg = w_wg
self.R0 = R0
self.angle = angle
self.L_attach = L_attach
self.L_in_tp = L_in_tp
self.cell = self.generate_gds(sharp_patch=sharp_patch)
self.L = np.abs(self.cell.pin['a1'].x - self.cell.pin['b1'].x)
def generate_gds(self,sharp_patch,err_asy=0):
with nd.Cell(instantiate=self.instantiate,name=self.name) as C:
w0 = self.w0
w1 = self.w1
Lcp = self.Lcp
gap = self.gap
xs = self.xs
w_wg = self.w_wg
L_attach = self.L_attach
L_in_tp = self.L_in_tp
angle = self.angle
R0 = self.R0
t_mid = nd.taper(width1=w0,width2=w1,length=Lcp,xs=xs).put(0,0,0)
t_u = nd.taper(width2=w0,width1=w1,length=Lcp,xs=xs).put(0,w1/2+w0/2+gap,0)
t_d = nd.taper(width2=w0,width1=w1,length=Lcp,xs=xs).put(0,-(w1/2+w0/2+gap),0)
t_in = nd.taper(width1=w_wg,width2=w0,length=L_in_tp,xs=xs).put(-L_in_tp,0,0)
t_in = nd.strt(width=w_wg,length=L_attach,xs=xs).put(t_in.pin['a0'],flip=0)
nd.Pin(name='a1',pin=t_in.pin['b0']).put()
au = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(t_u.pin['b0'],flip=0)
au = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(au.pin['b0'],flip=1)
au = nd.taper(width1=w0,width2=w_wg,length=L_in_tp,xs=xs).put(au.pin['b0'],flip=0)
au = nd.strt(width=w_wg,length=L_attach,xs=xs).put(au.pin['b0'],flip=0)
nd.Pin(name='b1',pin=au.pin['b0']).put()
ad = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(t_d.pin['b0'],flip=1)
ad = nd.bend(radius=R0,angle=angle,xs=xs,width=w0).put(ad.pin['b0'],flip=0)
ad = nd.taper(width1=w0,width2=w_wg,length=L_in_tp,xs=xs).put(ad.pin['b0'],flip=0)
ad = nd.strt(width=w_wg,length=L_attach,xs=xs).put(ad.pin['b0'],flip=0)
nd.Pin(name='b2',pin=ad.pin['b0']).put()
if (sharp_patch==True):
dY = np.abs(ad.pin['b0'].y-au.pin['b0'].y)+w_wg
for layers,growx,growy,acc in nd.layeriter(xs=xs):
(a1,b1), (a2,b2),c1,c2 = growx
if (b1!=0 and b2!=0):
L_patch = dY*(a1-a2)+(b1-b2)
W_patch = dY*(a1-a2)+(b1-b2)
nd.strt(length=W_patch,width=L_patch,layer=layers).put(ad.pin['b0'].x,0,0)
return C
def generate_test_gds(self,gc,dX_gc2gc=400,dY_gc2gc=80,sharp_patch = True,Rbend=15):
with nd.Cell(instantiate=False) as C:
gc_cell = __cell_arg__(arg=gc,arg_name="gc",func_name="mxpic::Ybranch_3wg::generate_test_gds")
inst = self.cell.put('a1',-self.L/2,0,0)
gc_In = gc_cell.put('g1',-dX_gc2gc/2,0,180)
gc_O1 = gc_cell.put('g1',dX_gc2gc/2, dY_gc2gc/2,0)
gc_O2 = gc_cell.put('g1',dX_gc2gc/2,-dY_gc2gc/2,0)
pic_strip = Route(radius=Rbend,width=self.w_wg,xs=self.xs)
pic_strip.taper(pin=gc_O1.pin['g1'],width1=gc_O1.pin['g1'].width,width2=self.w_wg,length=5,arrow=False)
pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['b1'],arrow=False).put()
pic_strip.taper(pin=gc_O2.pin['g1'],width1=gc_O2.pin['g1'].width,width2=self.w_wg,length=5,arrow=False)
pic_strip.sbend_p2p(original_function=not sharp_patch, pin2=inst.pin['b2'],arrow=False).put()
pic_strip.taper_p2p(pin1=gc_In.pin['g1'],pin2=inst.pin['a1'],arrow=False).put()
return C
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,260 +0,0 @@
from turtle import shape
import nazca as nd
import numpy as np
import math
from ...routing import Route
from ..geometry import *
from ..geometry import _my_polygon,Conchoid
""" Mono layer MMI """
class MMI_ML:
"""
Multi-layer (mono-layer) multimode interference (MMI) device generator.
Parameters
----------
name : str or None, optional
Nazca cell name. ``None`` keeps the cell uninstantiated (default is None).
L_arm : Sequence[float], optional
Segment lengths (µm) of each arm taper section (default is ``[10]``).
w_arm : Sequence[float], optional
Corresponding arm widths (µm). Length must be ``len(L_arm) + 1`` (default is ``[0.45, 1.35]``).
xs : str, optional
Nazca cross-section key used for both arm and MMI regions (default is "strip").
arm_sine_width : bool, optional
If True, arm width follows a cosine taper instead of linear interpolation (default is False).
L_mmi : Sequence[float], optional
Segment lengths (µm) within the central MMI body (default is ``[10]``).
w_mmi : Sequence[float], optional
MMI widths (µm). Length must be ``len(L_mmi) + 1`` (default is ``[5, 5]``).
mmi_sine_width : bool, optional
If True, MMI width transition uses cosine instead of linear interpolation (default is False).
sharp_patch : bool, optional
Insert chamfer polygons at acute corners when ``True`` (default is True).
show_pins : bool, optional
Draw Nazca stub markers for debugging when ``True`` (default is False).
res : float, optional
Longitudinal sampling resolution (µm) for polygon generation (default is 0.01).
N_out : int, optional
Number of output ports (default is 3).
N_in : int, optional
Number of input ports (default is 1).
Dp_out : float, optional
Vertical pitch (µm) between adjacent output ports (default is 1.5).
Dp_in : float, optional
Vertical pitch (µm) between adjacent input ports (default is 1.5).
"""
def __init__(self,
name=None,
L_arm=[10],
w_arm=[0.45,1.35],
xs = 'strip',
arm_sine_width=False,
L_mmi = [10],
w_mmi = [5,5],
mmi_sine_width=False,
sharp_patch=True,
show_pins = False,
res = 0.01,
N_out = 3,
N_in = 1,
Dp_out = 1.5,
Dp_in = 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 <mxpic::passive::ADC_STD_2x2::generate_test_gds>, <gc> 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):
"""
Convenience wrapper for standard MMIs with equal-length arms and uniform MMI body.
Parameters
----------
name : str or None, optional
Nazca cell name (default is None).
N_out : int, optional
Number of output ports (default is 3).
N_in : int, optional
Number of input ports (default is 1).
L_arm : float, optional
Single arm length in microns (default is 10).
w_wg : float, optional
Input/output waveguide width in microns (default is 0.45).
w_port : float, optional
Width at the transition between the taper and MMI (default is 1.2).
xs : str, optional
Cross-section key for all regions (default is "strip").
L_mmi : float, optional
Central MMI length in microns (default is 10).
w_mmi : float, optional
Central MMI width in microns (default is 5).
sharp_patch : bool, optional
Add chamfer helpers when True (default is True).
show_pins : bool, optional
Draw Nazca stub markers when True (default is False).
Dp_out : float, optional
Output port pitch in microns (default is 1.5).
Dp_in : float, optional
Input port pitch in microns (default is 1.5).
"""
def __init__(self,
name=None,
N_out=3,
N_in=1,
L_arm=10,
w_wg=0.45,
w_port = 1.2,
xs='strip',
L_mmi=10,
w_mmi=5,
sharp_patch=True,
show_pins=False,
Dp_out=1.5,
Dp_in=1.5) -> None:
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)
@@ -2,8 +2,8 @@ from .unit import PSR_1x2 , Brag_WDM
from .unit import waveguide,PS_2st, PS_2st_Straight
from .rings import STD_ring_AMZI_adddrop, MRR_MM_Adddrop, MRR_MM_Allpass, MRR_STD_Adddrop,MRR_STD_Allpass,MRR_DW_Adddrop,MRR_DW_Allpass
from .rings import SOCR_Adiabatic, SOCR_Adiabatic_Cband
from .rings import SOCR, SOCR_Cband
# from .rings import SOCR_Adiabatic, SOCR_Adiabatic_Cband
# from .rings import SOCR, SOCR_Cband
from .crows import CROW_Eul_Ring,CROW_Eul_RCK,CROW_AED,CROW_STD_Adddrop,CROW_STD_Allpass
+2 -2
View File
@@ -246,8 +246,8 @@ class STD_CROW_V:
# instr = self.ring_cell[_idx_+1].put(0,dy,0)
instr = __cell_arg__(arg=self.ring_cell[_idx_+1],arg_name="ring_cell[_idx_+1]",func_name="STD_CROW_V::generate_pic_gds").put(0,dy,0)
if (_idx_==0):
instr.raise_pins(['r1','r2','r3','r4'],['rb1','rb2','rb3','rb4'])
# if (_idx_==0):
# instr.raise_pins(['r1','r2','r3','r4'],['rb1','rb2','rb3','rb4'])
if (len(self.gap_cp)==2):
+4 -4
View File
@@ -1,8 +1,8 @@
from .gratings import GC_STD_1D,GC_STD_2D
from .gratings import Grating_2D_Hole, Grating_2D_Hole_3Rec, Grating_2D_Hole_4Rec
from .gratings import Nano_ant
from .gratings import FA
# from .gratings import GC_STD_1D,GC_STD_2D
# from .gratings import Grating_2D_Hole, Grating_2D_Hole_3Rec, Grating_2D_Hole_4Rec
# from .gratings import Nano_ant
# from .gratings import FA
from .rings import STD_PIC_Rings,AED_ring
+1 -1
View File
@@ -1211,7 +1211,7 @@ class GC_STD_1D:
## retangular grating
elif (self.shape=='rectangle'):
elif (self.sector_gc==False):
L_grat = sum(self.Period)
W_grat = self.w_wg + self.L_taper*np.tan(self.A_taper/2*np.pi/180)*2
File diff suppressed because it is too large Load Diff